<commit_before>/*
   Copyright 2015 Vinhthuy Phan
	Compressed FM index.
*/
package fmic

import (
	"bufio"
	"bytes"
	"fmt"
	"math"
	"math/rand"
	"os"
	"sort"
)

//-----------------------------------------------------------------------------
// Global variables: sequence (SEQ), suffix array (SA), BWT, FM index (C, OCC)
//-----------------------------------------------------------------------------

type IndexC struct {
	SEQ []byte
	BWT []byte
	SA  []indexType          // suffix array
	SSA []sequenceType       // SSA[i] stores the sequence containing position SA[i]
	C   map[byte]indexType   // count table
	OCC map[byte][]indexType // occurence table

	END_POS indexType          // position of "$" in the text
	SYMBOLS []int              // sorted symbols
	EP      map[byte]indexType // ending row/position of each symbol

	LEN        indexType
	OCC_SIZE   indexType
	Freq       map[byte]indexType // Frequency of each symbol
	M          int                // Compression ratio
	Multiple   bool               // True if the input contains multiple sequences
	input_file string
}

//-----------------------------------------------------------------------------
// Build FM index given the file storing the text.
// multiple is true if the input file contains multiple sequences
// compression ratio >=1
//-----------------------------------------------------------------------------
func CompressedIndex(file string, multiple bool, compression_ratio int) *IndexC {
	I := new(IndexC)
	I.input_file = file
	I.M = compression_ratio
	I.Multiple = multiple

	// GET THE SEQUENCE
	I.ReadFasta(file)

	// BUILD SUFFIX ARRAY
	I.LEN = indexType(len(I.SEQ))
	I.OCC_SIZE = indexType(math.Ceil(float64(I.LEN/indexType(I.M)))) + 1
	I.SA = make([]indexType, I.LEN)
	var SID []sequenceType
	if I.Multiple {
		I.SSA = make([]sequenceType, I.LEN)
		SID = make([]sequenceType, I.LEN)
	}
	SA := make([]int, I.LEN)
	ws := &WorkSpace{}
	ws.ComputeSuffixArray(I.SEQ, SA)
	sid := sequenceType(0)
	for i := range SA {
		I.SA[i] = indexType(SA[i])
		if I.Multiple {
			SID[i] = sid
			if I.SEQ[i] == '|' {
				sid++
			}
		}
	}

	// BUILD BWT
	I.Freq = make(map[byte]indexType)
	I.BWT = make([]byte, I.LEN)
	var i indexType
	for i = 0; i < I.LEN; i++ {
		I.Freq[I.SEQ[i]]++
		if I.SA[i] == 0 {
			I.BWT[i] = I.SEQ[I.LEN-1]
		} else {
			I.BWT[i] = I.SEQ[I.SA[i]-1]
		}
		if I.BWT[i] == '$' {
			I.END_POS = i
		}
		if I.Multiple {
			I.SSA[i] = SID[I.SA[i]]
		}
	}

	// BUILD COUNT AND OCCURENCE TABLE
	I.C = make(map[byte]indexType)
	I.OCC = make(map[byte][]indexType)
	for c := range I.Freq {
		I.SYMBOLS = append(I.SYMBOLS, int(c))
		I.OCC[c] = make([]indexType, I.OCC_SIZE)
		I.C[c] = 0
	}
	sort.Ints(I.SYMBOLS)
	I.EP = make(map[byte]indexType)
	count := make(map[byte]indexType)

	for j := 1; j < len(I.SYMBOLS); j++ {
		curr_c, prev_c := byte(I.SYMBOLS[j]), byte(I.SYMBOLS[j-1])
		I.C[curr_c] = I.C[prev_c] + I.Freq[prev_c]
		I.EP[curr_c] = I.C[curr_c] + I.Freq[curr_c] - 1
		count[curr_c] = 0
	}

	for j := 0; j < len(I.BWT); j++ {
		count[I.BWT[j]] += 1
		if j%I.M == 0 {
			for symbol := range I.OCC {
				I.OCC[symbol][int(j/I.M)] = count[symbol]
			}
		}
	}

	return I
}

//-----------------------------------------------------------------------------
func (I *IndexC) Occurence(c byte, pos indexType) indexType {
	i := indexType(pos / indexType(I.M))
	count := I.OCC[c][i]
	for j := i*indexType(I.M) + 1; j <= pos; j++ {
		if I.BWT[j] == c {
			count += 1
		}
	}
	return count
}

// -----------------------------------------------------------------------------
// Returns starting, ending positions (sp, ep) and last-matched position (i)

func (I *IndexC) Search(query []byte) (int, int) {
	var offset indexType
	var i int
	start_pos := len(query) - 1
	c := query[start_pos]
	sp, ok := I.C[c]
	if !ok {
		panic("Unknown character: " + string(c))
	}
	ep := I.EP[c]
	// fmt.Println(ep-sp+1, "\t", i, string(c), len(query))
	for i = int(start_pos - 1); sp <= ep && i >= 0; i-- {
		c = query[i]
		offset, ok = I.C[c]
		if !ok {
			panic("Unknown character: " + string(c))
		}
		sp = offset + I.Occurence(c, sp-1)
		ep = offset + I.Occurence(c, ep) - 1
		// fmt.Println(ep-sp+1, "\t", i, string(c), len(query))
	}
	return int(sp), int(ep)
}

//-----------------------------------------------------------------------------
// Guess which sequence contains the query.
// If randomized_round is 0, there is no randomization. The search begins at the.
//-----------------------------------------------------------------------------

func (I *IndexC) Guess(query []byte, randomized_round int) (int, int) {
	var seq, count int
	// var start_pos, end_pos int
	if randomized_round == 0 {
		seq, count, _ = I._guess(query, len(query)-1)
		return seq, count
	} else {
		for i := 0; i < randomized_round; i++ {
			// start_pos = rand.Intn(len(query))
			// seq, count, end_pos = I._guess(query, start_pos)
			// fmt.Println(end_pos, start_pos, "<")
			seq, count, _ = I._guess(query, rand.Intn(len(query)))
			if seq >= 0 {
				return seq, count
			}
		}
		return -1, 0
	}
}

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

func (I *IndexC) GuessPair(query1 []byte, query2 []byte, randomized_round int) int {
	var seq1, seq2 int
	if randomized_round == 0 {
		seq1, _, _ = I._guess(query1, len(query1)-1)
		seq2, _, _ = I._guess(query2, len(query2)-1)
		if seq1 == seq2 {
			return seq1
		} else {
			return -1
		}
	} else {
		for i := 0; i < randomized_round; i++ {
			seq1, _, _ = I._guess(query1, rand.Intn(len(query1)))
			seq2, _, _ = I._guess(query2, rand.Intn(len(query2)))
			if seq1 >= 0 && seq1 == seq2 {
				return seq1
			}
		}
		if seq1 == -1 {
			return seq2
		} else if seq2 == -1 {
			return seq1
		}
		return -1
	}
}

//-----------------------------------------------------------------------------
func (I *IndexC) _guess(query []byte, start_pos int) (int, int, int) {
	if !I.Multiple {
		return 0, -1, -1
	}
	var offset indexType
	var i int
	c := query[start_pos]
	sp, ok := I.C[c]
	if !ok {
		return -2, 0, 0
	}
	ep := I.EP[c]
	// fmt.Println(ep-sp+1, "\t", i, string(c), len(query))
	for i = int(start_pos - 1); sp < ep && i >= 0; i-- {
		c = query[i]
		offset, ok = I.C[c]
		if !ok {
			return -2, 0, 0
		}
		sp = offset + I.Occurence(c, sp-1)
		ep = offset + I.Occurence(c, ep) - 1
		// fmt.Println(ep-sp+1, "\t", i, string(c), len(query))
	}
	if sp <= ep {
		for j := sp + 1; j <= ep; j++ {
			if I.SSA[j] != I.SSA[sp] {
				return -1, int(ep - sp + 1), i
			}
		}
		return int(I.SSA[sp]), int(ep - sp + 1), i
	} else {
		return -1, int(ep - sp + 1), i
	}
}

//-----------------------------------------------------------------------------
func (I *IndexC) ReadFasta(file string) {
	f, err := os.Open(file)
	check_for_error(err)
	defer f.Close()

	if file[len(file)-6:] != ".fasta" {
		panic("ReadFasta:" + file + "is not a fasta file.")
	}

	scanner := bufio.NewScanner(f)
	byte_array := make([]byte, 0)
	i := 0
	for scanner.Scan() {
		line := scanner.Bytes()
		if len(line) > 0 {
			if line[0] != '>' {
				byte_array = append(byte_array, bytes.Trim(line, "\n\r ")...)
			} else if len(byte_array) > 0 {
				byte_array = append(byte_array, byte('|'))
			}
			i++
		}
	}
	I.SEQ = append(byte_array, byte('$'))
}

//-----------------------------------------------------------------------------
func (I *IndexC) Show() {
	fmt.Printf(" %6s %6s  OCC\n", "Freq", "C")
	for i := 0; i < len(I.SYMBOLS); i++ {
		c := byte(I.SYMBOLS[i])
		fmt.Printf("%c%6d %6d  %d\n", c, I.Freq[c], I.C[c], I.OCC[c])
	}
	fmt.Printf("SA ")
	for i := 0; i < len(I.SA); i++ {
		fmt.Print(I.SA[i], " ")
	}
	fmt.Printf("\nBWT ")
	for i := 0; i < len(I.BWT); i++ {
		fmt.Print(string(I.BWT[i]))
	}
	fmt.Println()
	fmt.Printf("\nSSA ")
	for i := 0; i < len(I.SSA); i++ {
		fmt.Printf("%d ", I.SSA[i])
	}
	fmt.Println()
	fmt.Println("SEQ", string(I.SEQ))
}

//-----------------------------------------------------------------------------
func (I *IndexC) Check() {
	fmt.Println("Checking...")
	for i := 0; i < len(I.SYMBOLS); i++ {
		c := byte(I.SYMBOLS[i])
		fmt.Printf("%c%6d %6d  [", c, I.Freq[c], I.C[c])
		for j := 0; j < int(I.LEN); j++ {
			fmt.Printf("%d ", I.Occurence(c, indexType(j)))
		}
		fmt.Printf("]\n")
	}
	if len(I.SEQ) > 0 {
		seq, count := I.Search(I.SEQ[0 : len(I.SEQ)-1])
		fmt.Println("Search for SEQ returns", seq, count)
	}
}

//-----------------------------------------------------------------------------
<commit_msg>ensure that two ends are close (<=1000 bases) of each other<commit_after>/*
   Copyright 2015 Vinhthuy Phan
	Compressed FM index.
*/
package fmic

import (
	"bufio"
	"bytes"
	"fmt"
	"math"
	"math/rand"
	"os"
	"sort"
)

//-----------------------------------------------------------------------------
// Global variables: sequence (SEQ), suffix array (SA), BWT, FM index (C, OCC)
//-----------------------------------------------------------------------------

type IndexC struct {
	SEQ []byte
	BWT []byte
	SA  []indexType          // suffix array
	SSA []sequenceType       // SSA[i] stores the sequence containing position SA[i]
	C   map[byte]indexType   // count table
	OCC map[byte][]indexType // occurence table

	END_POS indexType          // position of "$" in the text
	SYMBOLS []int              // sorted symbols
	EP      map[byte]indexType // ending row/position of each symbol

	LEN        indexType
	OCC_SIZE   indexType
	Freq       map[byte]indexType // Frequency of each symbol
	M          int                // Compression ratio
	Multiple   bool               // True if the input contains multiple sequences
	input_file string
}

//-----------------------------------------------------------------------------
// Build FM index given the file storing the text.
// multiple is true if the input file contains multiple sequences
// compression ratio >=1
//-----------------------------------------------------------------------------
func CompressedIndex(file string, multiple bool, compression_ratio int) *IndexC {
	I := new(IndexC)
	I.input_file = file
	I.M = compression_ratio
	I.Multiple = multiple

	// GET THE SEQUENCE
	I.ReadFasta(file)

	// BUILD SUFFIX ARRAY
	I.LEN = indexType(len(I.SEQ))
	I.OCC_SIZE = indexType(math.Ceil(float64(I.LEN/indexType(I.M)))) + 1
	I.SA = make([]indexType, I.LEN)
	var SID []sequenceType
	if I.Multiple {
		I.SSA = make([]sequenceType, I.LEN)
		SID = make([]sequenceType, I.LEN)
	}
	SA := make([]int, I.LEN)
	ws := &WorkSpace{}
	ws.ComputeSuffixArray(I.SEQ, SA)
	sid := sequenceType(0)
	for i := range SA {
		I.SA[i] = indexType(SA[i])
		if I.Multiple {
			SID[i] = sid
			if I.SEQ[i] == '|' {
				sid++
			}
		}
	}

	// BUILD BWT
	I.Freq = make(map[byte]indexType)
	I.BWT = make([]byte, I.LEN)
	var i indexType
	for i = 0; i < I.LEN; i++ {
		I.Freq[I.SEQ[i]]++
		if I.SA[i] == 0 {
			I.BWT[i] = I.SEQ[I.LEN-1]
		} else {
			I.BWT[i] = I.SEQ[I.SA[i]-1]
		}
		if I.BWT[i] == '$' {
			I.END_POS = i
		}
		if I.Multiple {
			I.SSA[i] = SID[I.SA[i]]
		}
	}

	// BUILD COUNT AND OCCURENCE TABLE
	I.C = make(map[byte]indexType)
	I.OCC = make(map[byte][]indexType)
	for c := range I.Freq {
		I.SYMBOLS = append(I.SYMBOLS, int(c))
		I.OCC[c] = make([]indexType, I.OCC_SIZE)
		I.C[c] = 0
	}
	sort.Ints(I.SYMBOLS)
	I.EP = make(map[byte]indexType)
	count := make(map[byte]indexType)

	for j := 1; j < len(I.SYMBOLS); j++ {
		curr_c, prev_c := byte(I.SYMBOLS[j]), byte(I.SYMBOLS[j-1])
		I.C[curr_c] = I.C[prev_c] + I.Freq[prev_c]
		I.EP[curr_c] = I.C[curr_c] + I.Freq[curr_c] - 1
		count[curr_c] = 0
	}

	for j := 0; j < len(I.BWT); j++ {
		count[I.BWT[j]] += 1
		if j%I.M == 0 {
			for symbol := range I.OCC {
				I.OCC[symbol][int(j/I.M)] = count[symbol]
			}
		}
	}

	return I
}

//-----------------------------------------------------------------------------
func (I *IndexC) Occurence(c byte, pos indexType) indexType {
	i := indexType(pos / indexType(I.M))
	count := I.OCC[c][i]
	for j := i*indexType(I.M) + 1; j <= pos; j++ {
		if I.BWT[j] == c {
			count += 1
		}
	}
	return count
}

// -----------------------------------------------------------------------------
// Returns starting, ending positions (sp, ep) and last-matched position (i)

func (I *IndexC) Search(query []byte) (int, int) {
	var offset indexType
	var i int
	start_pos := len(query) - 1
	c := query[start_pos]
	sp, ok := I.C[c]
	if !ok {
		panic("Unknown character: " + string(c))
	}
	ep := I.EP[c]
	// fmt.Println(ep-sp+1, "\t", i, string(c), len(query))
	for i = int(start_pos - 1); sp <= ep && i >= 0; i-- {
		c = query[i]
		offset, ok = I.C[c]
		if !ok {
			panic("Unknown character: " + string(c))
		}
		sp = offset + I.Occurence(c, sp-1)
		ep = offset + I.Occurence(c, ep) - 1
		// fmt.Println(ep-sp+1, "\t", i, string(c), len(query))
	}
	return int(sp), int(ep)
}

//-----------------------------------------------------------------------------
// Guess which sequence contains the query.
// If randomized_round is 0, there is no randomization. The search begins at the.
//-----------------------------------------------------------------------------

func (I *IndexC) Guess(query []byte, randomized_round int) (int, int) {
	var seq, count int
	// var start_pos, end_pos int
	if randomized_round == 0 {
		seq, count, _ = I._guess(query, len(query)-1)
		return seq, count
	} else {
		for i := 0; i < randomized_round; i++ {
			// start_pos = rand.Intn(len(query))
			// seq, count, end_pos = I._guess(query, start_pos)
			// fmt.Println(end_pos, start_pos, "<")
			seq, count, _ = I._guess(query, rand.Intn(len(query)))
			if seq >= 0 {
				return seq, count
			}
		}
		return -1, 0
	}
}

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

func (I *IndexC) GuessPair(query1 []byte, query2 []byte, randomized_round int) int {
	var seq1, seq2, p1, p2, pos int
	// var count1, count2 int
	if randomized_round == 0 {
		seq1, _, _ = I._guess(query1, len(query1)-1)
		seq2, _, _ = I._guess(query2, len(query2)-1)
		if seq1 == seq2 {
			return seq1
		} else {
			return -1
		}
	} else {
		for i := 0; i < randomized_round; i++ {
			pos = 10 + rand.Intn(len(query1)-10)
			if pos <= 0 {
				pos = len(query1)-1
			}
			seq1, _, p1 = I._guess(query1, pos)

			pos = 10 + rand.Intn(len(query2)-10)
			if pos <= 0 {
				pos = len(query2)-1
			}
			seq2, _, p2 = I._guess(query2, pos)

			// if seq1 >= 0 && seq1 == seq2 {
			if seq1 >= 0 && seq1 == seq2 && ((p1>=p2 && p1-p2<=1000) || (p2>p1 && p2-p1<=1000)){
				// fmt.Println(seq1, p2-p1, count1, count2, p1, p2)
				return seq1
			}
		}
		if seq1 == -1 {
			// fmt.Println(seq2, -1, -1, count2, -1, p1)
			return seq2
		} else if seq2 == -1 {
			// fmt.Println(seq1, -1, -1, count1, p1, -1)
			return seq1
		}
		// fmt.Println(-1, -1, -1, -1, -1, -1)
		return -1
	}
}

//-----------------------------------------------------------------------------
func (I *IndexC) _guess(query []byte, start_pos int) (int, int, int) {
	if !I.Multiple {
		return 0, -1, -1
	}
	var offset indexType
	var i int
	c := query[start_pos]
	sp, ok := I.C[c]
	if !ok {
		return -2, 0, 0
	}
	ep := I.EP[c]
	// fmt.Println(ep-sp+1, "\t", i, string(c), len(query))
	for i = int(start_pos - 1); sp < ep && i >= 0; i-- {
		c = query[i]
		offset, ok = I.C[c]
		if !ok {
			return -2, 0, 0
		}
		sp = offset + I.Occurence(c, sp-1)
		ep = offset + I.Occurence(c, ep) - 1
		// fmt.Println(ep-sp+1, "\t", i, string(c), len(query))
	}
	if sp <= ep {
		for j := sp + 1; j <= ep; j++ {
			if I.SSA[j] != I.SSA[sp] {
				return -1, int(ep - sp + 1), -1
			}
		}
		return int(I.SSA[sp]), int(ep - sp + 1), int(I.SA[sp])
	} else {
		return -1, int(ep - sp + 1), -1
	}
}

//-----------------------------------------------------------------------------
func (I *IndexC) ReadFasta(file string) {
	f, err := os.Open(file)
	check_for_error(err)
	defer f.Close()

	if file[len(file)-6:] != ".fasta" {
		panic("ReadFasta:" + file + "is not a fasta file.")
	}

	scanner := bufio.NewScanner(f)
	byte_array := make([]byte, 0)
	i := 0
	for scanner.Scan() {
		line := scanner.Bytes()
		if len(line) > 0 {
			if line[0] != '>' {
				byte_array = append(byte_array, bytes.Trim(line, "\n\r ")...)
			} else if len(byte_array) > 0 {
				byte_array = append(byte_array, byte('|'))
			}
			i++
		}
	}
	I.SEQ = append(byte_array, byte('$'))
}

//-----------------------------------------------------------------------------
func (I *IndexC) Show() {
	fmt.Printf(" %6s %6s  OCC\n", "Freq", "C")
	for i := 0; i < len(I.SYMBOLS); i++ {
		c := byte(I.SYMBOLS[i])
		fmt.Printf("%c%6d %6d  %d\n", c, I.Freq[c], I.C[c], I.OCC[c])
	}
	fmt.Printf("SA ")
	for i := 0; i < len(I.SA); i++ {
		fmt.Print(I.SA[i], " ")
	}
	fmt.Printf("\nBWT ")
	for i := 0; i < len(I.BWT); i++ {
		fmt.Print(string(I.BWT[i]))
	}
	fmt.Println()
	fmt.Printf("\nSSA ")
	for i := 0; i < len(I.SSA); i++ {
		fmt.Printf("%d ", I.SSA[i])
	}
	fmt.Println()
	fmt.Println("SEQ", string(I.SEQ))
}

//-----------------------------------------------------------------------------
func (I *IndexC) Check() {
	fmt.Println("Checking...")
	for i := 0; i < len(I.SYMBOLS); i++ {
		c := byte(I.SYMBOLS[i])
		fmt.Printf("%c%6d %6d  [", c, I.Freq[c], I.C[c])
		for j := 0; j < int(I.LEN); j++ {
			fmt.Printf("%d ", I.Occurence(c, indexType(j)))
		}
		fmt.Printf("]\n")
	}
	if len(I.SEQ) > 0 {
		seq, count := I.Search(I.SEQ[0 : len(I.SEQ)-1])
		fmt.Println("Search for SEQ returns", seq, count)
	}
}

//-----------------------------------------------------------------------------
<|endoftext|>


<commit_before>/*
Copyright (c) 2012 krepa098 (krepa098 at gmail dot com)
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose, including commercial applications,
and to alter it and redistribute it freely, subject to the following restrictions:
	1.	The origin of this software must not be misrepresented; you must not claim that you wrote the original software.
		If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
	2. 	Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
	3. 	This notice may not be removed or altered from any source distribution.
*/

package gosfml2

// #include <SFML/Graphics/Font.h>
// #include <stdlib.h>
import "C"

import (
	"errors"
	"runtime"
	"unsafe"
)

/////////////////////////////////////
///		STRUCTS
/////////////////////////////////////

type Font struct {
	cptr *C.sfFont
}

/////////////////////////////////////
///		FUNCS
/////////////////////////////////////

func NewFontFromFile(filename string) (font *Font, err error) {
	cFilename := C.CString(filename)
	defer C.free(unsafe.Pointer(cFilename))

	font = &Font{C.sfFont_createFromFile(cFilename)}
	runtime.SetFinalizer(font, (*Font).Destroy)

	if font.cptr == nil {
		err = errors.New("NewFontFromFile: Cannot load font " + filename)
	}

	return
}

func NewFontFromMemory(data []byte) (*Font, error) {
	if len(data) > 0 {
		font := &Font{C.sfFont_createFromMemory(unsafe.Pointer(&data[0]), C.size_t(len(data)))}
		runtime.SetFinalizer(font, (*Font).Destroy)
		return font, nil
	}
	return nil, errors.New("NewFontFromMemory: no data")
}

func (this *Font) Copy() *Font {
	font := &Font{C.sfFont_copy(this.cptr)}
	runtime.SetFinalizer(font, (*Font).Destroy)
	return font
}

func (this *Font) Destroy() {
	C.sfFont_destroy(this.cptr)
	this.cptr = nil
}

func (this *Font) GetGlyph(codePoint uint, characterSize uint32, bold bool) (glyph Glyph) {
	glyph.fromC(C.sfFont_getGlyph(this.cptr, C.sfUint32(codePoint), C.uint(characterSize), goBool2C(bold)))
	return
}

func (this *Font) GetKerning(first uint32, second uint32, characterSize uint) int {
	return int(C.sfFont_getKerning(this.cptr, C.sfUint32(first), C.sfUint32(second), C.uint(characterSize)))
}

func (this *Font) GetLineSpacing(characterSize uint) int {
	return int(C.sfFont_getLineSpacing(this.cptr, C.uint(characterSize)))
}

func (this *Font) GetTexture(characterSize uint) Texture {
	return Texture{C.sfFont_getTexture(this.cptr, C.uint(characterSize))}
}

/////////////////////////////////////
///		GO <-> C
/////////////////////////////////////

func (this *Font) toCPtr() *C.sfFont {
	if this != nil {
		return this.cptr
	}
	return nil
}
<commit_msg>documented font.go<commit_after>/*
Copyright (c) 2012 krepa098 (krepa098 at gmail dot com)
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose, including commercial applications,
and to alter it and redistribute it freely, subject to the following restrictions:
	1.	The origin of this software must not be misrepresented; you must not claim that you wrote the original software.
		If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
	2. 	Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
	3. 	This notice may not be removed or altered from any source distribution.
*/

package gosfml2

// #include <SFML/Graphics/Font.h>
// #include <stdlib.h>
import "C"

import (
	"errors"
	"runtime"
	"unsafe"
)

/////////////////////////////////////
///		STRUCTS
/////////////////////////////////////

type Font struct {
	cptr *C.sfFont
}

/////////////////////////////////////
///		FUNCS
/////////////////////////////////////

// Font constructor
// Creates a new font from file
//
// The supported font formats are: TrueType, Type 1, CFF,
// OpenType, SFNT, X11 PCF, Windows FNT, BDF, PFR and Type 42.
// Note that this function know nothing about the standard
// fonts installed on the user's system, thus you can't
// load them directly.
func NewFontFromFile(filename string) (font *Font, err error) {
	cFilename := C.CString(filename)
	defer C.free(unsafe.Pointer(cFilename))

	font = &Font{C.sfFont_createFromFile(cFilename)}
	runtime.SetFinalizer(font, (*Font).Destroy)

	if font.cptr == nil {
		err = errors.New("NewFontFromFile: Cannot load font " + filename)
	}

	return
}

// Font constructor
// Creates a new font from memory
//
// The supported font formats are: TrueType, Type 1, CFF,
// OpenType, SFNT, X11 PCF, Windows FNT, BDF, PFR and Type 42.
func NewFontFromMemory(data []byte) (*Font, error) {
	if len(data) > 0 {
		font := &Font{C.sfFont_createFromMemory(unsafe.Pointer(&data[0]), C.size_t(len(data)))}
		runtime.SetFinalizer(font, (*Font).Destroy)
		return font, nil
	}
	return nil, errors.New("NewFontFromMemory: no data")
}

func (this *Font) Copy() *Font {
	font := &Font{C.sfFont_copy(this.cptr)}
	runtime.SetFinalizer(font, (*Font).Destroy)
	return font
}

func (this *Font) Destroy() {
	C.sfFont_destroy(this.cptr)
	this.cptr = nil
}

// Retrieve a glyph of the font
//
// codePoint     Unicode code point of the character to get
// characterSize Reference character size
// bold          Retrieve the bold version or the regular one?
//
// return The glyph corresponding to codePoint and characterSize
func (this *Font) GetGlyph(codePoint uint, characterSize uint32, bold bool) (glyph Glyph) {
	glyph.fromC(C.sfFont_getGlyph(this.cptr, C.sfUint32(codePoint), C.uint(characterSize), goBool2C(bold)))
	return
}

//Get the kerning offset of two glyphs
//
// The kerning is an extra offset (negative) to apply between two
// glyphs when rendering them, to make the pair look more "natural".
// For example, the pair "AV" have a special kerning to make them
// closer than other characters. Most of the glyphs pairs have a
// kerning offset of zero, though.
//
// first         Unicode code point of the first character
// second        Unicode code point of the second character
// characterSize Reference character size
//
// return Kerning value for first and second, in pixels
func (this *Font) GetKerning(first uint32, second uint32, characterSize uint) int {
	return int(C.sfFont_getKerning(this.cptr, C.sfUint32(first), C.sfUint32(second), C.uint(characterSize)))
}

// Get the line spacing
//
// Line spacing is the vertical offset to apply between two
// consecutive lines of text.
//
// characterSize Reference character size
//
// return Line spacing, in pixels
func (this *Font) GetLineSpacing(characterSize uint) int {
	return int(C.sfFont_getLineSpacing(this.cptr, C.uint(characterSize)))
}

// Retrieve the texture containing the loaded glyphs of a certain size
//
// The contents of the returned texture changes as more glyphs
// are requested, thus it is not very relevant.
//
// characterSize Reference character size
//
// Texture containing the glyphs of the requested size
func (this *Font) GetTexture(characterSize uint) Texture {
	return Texture{C.sfFont_getTexture(this.cptr, C.uint(characterSize))}
}

/////////////////////////////////////
///		GO <-> C
/////////////////////////////////////

func (this *Font) toCPtr() *C.sfFont {
	if this != nil {
		return this.cptr
	}
	return nil
}
<|endoftext|>


<commit_before>// Copyright (c) 2013-2014 by Michael Dvorkin. All Rights Reserved.
// Use of this source code is governed by a MIT-style license that can
// be found in the LICENSE file.

package donna

import (
        `bytes`
        `fmt`
        `regexp`
        `time`
)

type Game struct {
	pieces	     [64]Piece
        nodes        int
        qnodes       int
        bestLine     [MaxPly][MaxPly]Move
        bestLength   [MaxPly]int
        goodMoves    [14][64]int
        killers      [MaxPly][2]Move
}

func NewGame() *Game {
        return new(Game)
}

func (game *Game) Setup(white, black string) *Game {
	re := regexp.MustCompile(`\W+`)
	whiteSide, blackSide := re.Split(white, -1), re.Split(black, -1)
	return game.SetupSide(whiteSide, 0).SetupSide(blackSide, 1)
}

func (game *Game) SetupSide(moves []string, color int) *Game {
	re := regexp.MustCompile(`([KQRBN]?)([a-h])([1-8])`)

	for _, move := range moves {
		arr := re.FindStringSubmatch(move)
		if len(arr) == 0 {
			fmt.Printf("Invalid move '%s' for %s\n", move, C(color))
			return game
		}
		name, col, row := arr[1], int(arr[2][0]-'a'), int(arr[3][0]-'1')

		var piece Piece
		switch name {
		case `K`:
			piece = king(color)
		case `Q`:
			piece = queen(color)
		case `R`:
			piece = rook(color)
		case `B`:
			piece = bishop(color)
		case `N`:
			piece = knight(color)
		default:
			piece = pawn(color)
		}
                game.pieces[Square(row, col)] = piece
	}
	return game
}

func (game *Game) InitialPosition() *Game {
        return game.Setup(`Ra1,Nb1,Bc1,Qd1,Ke1,Bf1,Ng1,Rh1,a2,b2,c2,d2,e2,f2,g2,h2`,
                          `Ra8,Nb8,Bc8,Qd8,Ke8,Bf8,Ng8,Rh8,a7,b7,c7,d7,e7,f7,g7,h7`)
}

func (game *Game) Start(color int) *Position {
        tree = [1024]Position{}
        rootNode, node = 0, 0
        game.bestLine = [MaxPly][MaxPly]Move{}
        game.bestLength = [MaxPly]int{}
        game.goodMoves = [14][64]int{}
        game.killers = [MaxPly][2]Move{}

        return NewPosition(game, game.pieces, color, Flags{})
}

func (game *Game) Think(requestedDepth int, position *Position) Move {
        if position == nil {
                position = game.Start(White)
        }

        book := NewBook("./books/gm2001.bin") // From http://www.chess2u.com/t5834-gm-polyglot-book
        if move := book.pickMove(position); move != 0 {
                fmt.Printf("Book move: %s\n", move)
                return move
        }

        rootNode = node
        game.goodMoves = [14][64]int{}
        move, score := Move(0), 0

        fmt.Println(`Depth/Time     Nodes      QNodes     Nodes/s   Score   Best`)
        for depth := 1; depth <= Min(MaxDepth, requestedDepth); depth++ {
                game.nodes, game.qnodes = 0, 0
                start := time.Now()
                move, score = position.searchRoot(depth)
                finish := time.Since(start).Seconds()
                if position.color == Black {
                        score = -score
                }
                if game.isOver(depth, score, finish) {
                        return 0
                }
        }
        fmt.Printf("\nDonna's move: %s\n\n", move)
        return move
}

func (game *Game) isOver(depth, score int, finish float64) bool {
        gameOver := 0
        absScore := Abs(score)
        movesLeft := (Checkmate - absScore) / 2

        if absScore > 32500 && movesLeft > 0 {
                gameOver = 1 // Checkmate in X moves.
        } else if absScore == Checkmate {
                gameOver = 2 // Checkmate.
        } else if score == 0 {
                if game.bestLength[0] == 0 {
                        gameOver = 4 // Stalemate.
                } else if game.bestLength[0] == -1 {
                        gameOver = 8 // Repetition.
                }
        }

        switch gameOver {
        case 1:
                fmt.Printf(" %d %02d:%02d    %8d    %8d   %9.1f   X%-4d   %v\n",
                        depth, int(finish) / 60, int(finish) % 60, game.nodes, game.qnodes,
                        float64(game.nodes + game.qnodes) / finish, movesLeft,
                        game.bestLine[0][0 : Min(depth, game.bestLength[0])])
        case 2:
                fmt.Printf(" %d %02d:%02d    %8d    %8d   %9.1f   Checkmate\n",
                        depth, int(finish) / 60, int(finish) % 60, game.nodes, game.qnodes,
                        float64(game.nodes + game.qnodes) / finish)
        case 4:
                fmt.Printf(" %d %02d:%02d    %8d    %8d   %9.1f   1/2 Stalemate\n",
                        depth, int(finish) / 60, int(finish) % 60, game.nodes, game.qnodes,
                        float64(game.nodes + game.qnodes) / finish)
        case 8:
                fmt.Printf(" %d %02d:%02d    %8d    %8d   %9.1f   1/2 Repetition\n",
                        depth, int(finish) / 60, int(finish) % 60, game.nodes, game.qnodes,
                        float64(game.nodes + game.qnodes) / finish)
        default:
                fmt.Printf(" %d %02d:%02d    %8d    %8d   %9.1f   %5.2f   %v\n",
                        depth, int(finish) / 60, int(finish) % 60, game.nodes, game.qnodes,
                        float64(game.nodes + game.qnodes) / finish, float64(score) / 100.0,
                        game.bestLine[0][0 : Min(depth, game.bestLength[0])])
        }

        return gameOver > 1
}

func (game *Game) saveBest(ply int, move Move) *Game {
        game.bestLine[ply][ply] = move
        game.bestLength[ply] = ply + 1

        if length := game.bestLength[ply+1]; length > 0 {
                copy(game.bestLine[ply]  [ply+1 : length],
                     game.bestLine[ply+1][ply+1 : length])
                game.bestLength[ply] = length
        }
        return game
}

func (game *Game) saveGood(depth int, move Move) *Game {
        if ply := Ply(); move & (isCapture|isPromo) == 0 && move != game.killers[ply][0] {
                game.killers[ply][1] = game.killers[ply][0]
                game.killers[ply][0] = move
                game.goodMoves[move.piece()][move.to()] += depth * depth
        }
        return game
}

func (game *Game)String() string {
	buffer := bytes.NewBufferString("  a b c d e f g h\n")
	for row := 7;  row >= 0;  row-- {
		buffer.WriteByte('1' + byte(row))
		for col := 0;  col <= 7; col++ {
			square := Square(row, col)
			buffer.WriteByte(' ')
			if piece := game.pieces[square]; piece != 0 {
				buffer.WriteString(piece.String())
			} else {
				buffer.WriteString("\u22C5")
			}
		}
		buffer.WriteByte('\n')
	}
	return buffer.String()
}
<commit_msg>Initialization tweaks<commit_after>// Copyright (c) 2013-2014 by Michael Dvorkin. All Rights Reserved.
// Use of this source code is governed by a MIT-style license that can
// be found in the LICENSE file.

package donna

import (
        `bytes`
        `fmt`
        `regexp`
        `time`
)

type Game struct {
	pieces	     [64]Piece
        nodes        int
        qnodes       int
        bestLine     [MaxPly][MaxPly]Move
        bestLength   [MaxPly]int
        goodMoves    [14][64]int
        killers      [MaxPly][2]Move
}

func NewGame() *Game {
        return new(Game)
}

func (game *Game) Setup(white, black string) *Game {
	re := regexp.MustCompile(`\W+`)
	whiteSide, blackSide := re.Split(white, -1), re.Split(black, -1)
	return game.SetupSide(whiteSide, 0).SetupSide(blackSide, 1)
}

func (game *Game) SetupSide(moves []string, color int) *Game {
	re := regexp.MustCompile(`([KQRBN]?)([a-h])([1-8])`)

	for _, move := range moves {
		arr := re.FindStringSubmatch(move)
		if len(arr) == 0 {
			fmt.Printf("Invalid move '%s' for %s\n", move, C(color))
			return game
		}
		name, col, row := arr[1], int(arr[2][0]-'a'), int(arr[3][0]-'1')

		var piece Piece
		switch name {
		case `K`:
			piece = king(color)
		case `Q`:
			piece = queen(color)
		case `R`:
			piece = rook(color)
		case `B`:
			piece = bishop(color)
		case `N`:
			piece = knight(color)
		default:
			piece = pawn(color)
		}
                game.pieces[Square(row, col)] = piece
	}
	return game
}

func (game *Game) InitialPosition() *Game {
        return game.Setup(`Ra1,Nb1,Bc1,Qd1,Ke1,Bf1,Ng1,Rh1,a2,b2,c2,d2,e2,f2,g2,h2`,
                          `Ra8,Nb8,Bc8,Qd8,Ke8,Bf8,Ng8,Rh8,a7,b7,c7,d7,e7,f7,g7,h7`)
}

func (game *Game) getReady() *Game {
        rootNode = node
        game.bestLine = [MaxPly][MaxPly]Move{}
        game.bestLength = [MaxPly]int{}
        game.goodMoves = [14][64]int{}
        game.killers = [MaxPly][2]Move{}

        return game;
}

func (game *Game) Start(color int) *Position {
        tree, node = [1024]Position{}, 0
        game.getReady()

        return NewPosition(game, game.pieces, color, Flags{})
}

func (game *Game) Think(requestedDepth int, position *Position) Move {
        if position == nil {
                position = game.Start(White)
        }

        book := NewBook("./books/gm2001.bin") // From http://www.chess2u.com/t5834-gm-polyglot-book
        if move := book.pickMove(position); move != 0 {
                fmt.Printf("Book move: %s\n", move)
                return move
        }

        game.getReady()
        move, score := Move(0), 0

        fmt.Println(`Depth/Time     Nodes      QNodes     Nodes/s   Score   Best`)
        for depth := 1; depth <= Min(MaxDepth, requestedDepth); depth++ {
                game.nodes, game.qnodes = 0, 0
                start := time.Now()
                move, score = position.searchRoot(depth)
                finish := time.Since(start).Seconds()
                if position.color == Black {
                        score = -score
                }
                if game.isOver(depth, score, finish) {
                        return 0
                }
        }
        fmt.Printf("\nDonna's move: %s\n\n", move)
        return move
}

func (game *Game) isOver(depth, score int, finish float64) bool {
        gameOver := 0
        absScore := Abs(score)
        movesLeft := (Checkmate - absScore) / 2

        if absScore > 32500 && movesLeft > 0 {
                gameOver = 1 // Checkmate in X moves.
        } else if absScore == Checkmate {
                gameOver = 2 // Checkmate.
        } else if score == 0 {
                if game.bestLength[0] == 0 {
                        gameOver = 4 // Stalemate.
                } else if game.bestLength[0] == -1 {
                        gameOver = 8 // Repetition.
                }
        }

        switch gameOver {
        case 1:
                fmt.Printf(" %d %02d:%02d    %8d    %8d   %9.1f   X%-4d   %v\n",
                        depth, int(finish) / 60, int(finish) % 60, game.nodes, game.qnodes,
                        float64(game.nodes + game.qnodes) / finish, movesLeft,
                        game.bestLine[0][0 : Min(depth, game.bestLength[0])])
        case 2:
                fmt.Printf(" %d %02d:%02d    %8d    %8d   %9.1f   Checkmate\n",
                        depth, int(finish) / 60, int(finish) % 60, game.nodes, game.qnodes,
                        float64(game.nodes + game.qnodes) / finish)
        case 4:
                fmt.Printf(" %d %02d:%02d    %8d    %8d   %9.1f   1/2 Stalemate\n",
                        depth, int(finish) / 60, int(finish) % 60, game.nodes, game.qnodes,
                        float64(game.nodes + game.qnodes) / finish)
        case 8:
                fmt.Printf(" %d %02d:%02d    %8d    %8d   %9.1f   1/2 Repetition\n",
                        depth, int(finish) / 60, int(finish) % 60, game.nodes, game.qnodes,
                        float64(game.nodes + game.qnodes) / finish)
        default:
                fmt.Printf(" %d %02d:%02d    %8d    %8d   %9.1f   %5.2f   %v\n",
                        depth, int(finish) / 60, int(finish) % 60, game.nodes, game.qnodes,
                        float64(game.nodes + game.qnodes) / finish, float64(score) / 100.0,
                        game.bestLine[0][0 : Min(depth, game.bestLength[0])])
        }

        return gameOver > 1
}

func (game *Game) saveBest(ply int, move Move) *Game {
        game.bestLine[ply][ply] = move
        game.bestLength[ply] = ply + 1

        if length := game.bestLength[ply+1]; length > 0 {
                copy(game.bestLine[ply]  [ply+1 : length],
                     game.bestLine[ply+1][ply+1 : length])
                game.bestLength[ply] = length
        }
        return game
}

func (game *Game) saveGood(depth int, move Move) *Game {
        if ply := Ply(); move & (isCapture|isPromo) == 0 && move != game.killers[ply][0] {
                game.killers[ply][1] = game.killers[ply][0]
                game.killers[ply][0] = move
                game.goodMoves[move.piece()][move.to()] += depth * depth
        }
        return game
}

func (game *Game)String() string {
	buffer := bytes.NewBufferString("  a b c d e f g h\n")
	for row := 7;  row >= 0;  row-- {
		buffer.WriteByte('1' + byte(row))
		for col := 0;  col <= 7; col++ {
			square := Square(row, col)
			buffer.WriteByte(' ')
			if piece := game.pieces[square]; piece != 0 {
				buffer.WriteString(piece.String())
			} else {
				buffer.WriteString("\u22C5")
			}
		}
		buffer.WriteByte('\n')
	}
	return buffer.String()
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"encoding/json"
	"errors"
	"io"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"sync"
	"time"
)

var TIMEOUTDURATION = time.Duration(10 * time.Second)
var Queues map[string]*Queue

type JobEntry struct {
	QueueName string `json:"queue"`
	ID        int64
	EntryDate time.Time
}

type Jobs []*JobEntry
type JobFile struct {
	Jobs Jobs `json:"jobs"`
}

type Queue struct {
	entries    chan *JobEntry
	j          Jobs
	m          sync.Mutex   // Whole queue mutex
	t          sync.Mutex   // just the timer mutex
	rw         sync.RWMutex // For reading and setting fields
	ondisk     bool
	ondiskfile string
	timer      *time.Timer
}

// Initialize a new queue using the filepath as it's disk storage.
func NewQueue(filepath string) *Queue {
	q := &Queue{
		ondiskfile: filepath,
		entries:    make(chan *JobEntry),
		timer:      time.NewTimer(TIMEOUTDURATION),
	}
	go MonitorQueue(q)
	return q
}

// SaveToDisk will write any unused entries to disk
//
// This is not thread safe and external locking should be used.
func (q *Queue) SaveToDisk() {
	var jobfile JobFile
	if q.HasOnDisk() {
		q.PopOnDiskJobs(&jobfile)
	}
	for {
		select {
		case job := <-q.entries:
			jobfile.Jobs = append(jobfile.Jobs, job)
		default:
			if len(jobfile.Jobs) < 1 {
				return
			}
			w, err := os.OpenFile(q.ondiskfile, os.O_CREATE|os.O_RDWR, 0666)
			if err != nil {
				panic(err)
			}
			w.Write(jobfile.Jobs.Serialize())
			q.rw.Lock()
			defer q.rw.Unlock()
			q.ondisk = true
			return
		}
	}
}

// HasOnDisk returns the ondisk state
func (q Queue) HasOnDisk() bool {
	q.rw.RLock()
	defer q.rw.RUnlock()
	return q.ondisk
}

// Reset the underlying timer. Used when we interact with the queue so
// we can organize the writes to disk into low-activity periods.
func (q *Queue) Reset() bool {
	q.t.Lock()
	defer q.t.Unlock()
	return q.timer.Reset(TIMEOUTDURATION)
}

// Pop off all the on-disk jobs into the supplied JobFile.
func (q *Queue) PopOnDiskJobs(j *JobFile) {
	if q.ondiskfile == "" {
		panic("Queue's job file is inaccessible.")
	}
	q.m.Lock()
	defer q.m.Unlock()
	b, err := ioutil.ReadFile(q.ondiskfile)
	if err != nil {
		log.Println(err)
		return
	}
	err = json.Unmarshal(b, j)
	if err != nil {
		log.Println(err)
		return
	}
	q.ondisk = false
	if err := os.Remove(q.ondiskfile); err != nil {
		log.Println(err)
	}
}

// Monitors a queue for inactivity, if there is inactivity for the
// specified timeout duration, we write to disk.
func MonitorQueue(q *Queue) {
	log.Printf("Monitoring %s\n", q.ondiskfile)
	for {
		select {
		case <-q.timer.C:
			q.m.Lock()
			q.SaveToDisk()
			q.Reset()
			q.m.Unlock()
		}
	}
}

func (j Jobs) Serialize() []byte {
	var b bytes.Buffer
	b.WriteString(`{"jobs":[`)
	for idx, job := range j {
		b.Write(job.Serialize())
		if idx+1 != len(j) {
			b.WriteString(",")
		}
	}
	b.WriteString("]}")
	return b.Bytes()
}

func (j JobEntry) Serialize() []byte {
	b, _ := json.Marshal(j)
	return b
}

func Pop(w http.ResponseWriter, req *http.Request) {
	job, err := readbody(req.Body)
	if err != nil {
		writefail(w)
		return
	}
	queue, ok := Queues[job.QueueName]
	if !ok {
		writefail(w)
		return
	}

	// We're interacting with the queue so we'll reset the timer to
	// show that
	queue.Reset()
	var jobfile JobFile

	// Get all the pending jobs from disk
	if queue.HasOnDisk() {
		queue.PopOnDiskJobs(&jobfile)
	}

	// Doing it this way allows other readers to take jobs out the
	// queue without duplicating our jobs.
	for {
		select {
		case job := <-queue.entries:
			jobfile.Jobs = append(jobfile.Jobs, job)
		default:
			if len(jobfile.Jobs) < 1 {
				w.WriteHeader(http.StatusNoContent)
				return
			}
			w.Write(jobfile.Jobs.Serialize())
			return
		}
	}
}

// Pushes a new job into the queue.
func Push(w http.ResponseWriter, req *http.Request) {
	job, err := readbody(req.Body)
	if err != nil {
		writefail(w)
		return
	}
	go func() {
		if queue, ok := Queues[job.QueueName]; ok {
			queue.Reset()
			queue.entries <- job
		}
	}()
	writesuccess(w)
}

func readbody(b io.ReadCloser) (*JobEntry, error) {
	if b == nil {
		return nil, errors.New("Nil body supplied!")
	}
	defer b.Close()
	body, err := ioutil.ReadAll(b)
	if err != nil {
		return nil, err
	}
	e := &JobEntry{}
	err = json.Unmarshal(body, e)
	return e, err
}

func writesuccess(w http.ResponseWriter) {
	w.Write([]byte(`{"success": true}`))
}

func writefail(w http.ResponseWriter) {
	w.WriteHeader(http.StatusBadRequest)
	w.Write([]byte(`{"success": false}`))
}

func main() {

	// Save to disk in the case of horrible failure.
	defer func() {
		if err := recover(); err != nil {
			log.Println(err)
			for _, queue := range Queues {
				queue.SaveToDisk()
			}
		}
	}()
	Queues = make(map[string]*Queue)
	Queues["tt"] = NewQueue("tt.q")
	http.HandleFunc("/push/", Push)
	http.HandleFunc("/pop/", Pop)
	log.Fatal(http.ListenAndServe(":8080", nil))
}
<commit_msg>Removed unecessary select{} in the Monitor function.<commit_after>package main

import (
	"bytes"
	"encoding/json"
	"errors"
	"io"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"sync"
	"time"
)

var TIMEOUTDURATION = time.Duration(10 * time.Second)
var Queues map[string]*Queue

type JobEntry struct {
	QueueName string `json:"queue"`
	ID        int64
	EntryDate time.Time
}

type Jobs []*JobEntry
type JobFile struct {
	Jobs Jobs `json:"jobs"`
}

type Queue struct {
	entries    chan *JobEntry
	j          Jobs
	m          sync.Mutex   // Whole queue mutex
	t          sync.Mutex   // just the timer mutex
	rw         sync.RWMutex // For reading and setting fields
	ondisk     bool
	ondiskfile string
	timer      *time.Timer
}

// Initialize a new queue using the filepath as it's disk storage.
func NewQueue(filepath string) *Queue {
	q := &Queue{
		ondiskfile: filepath,
		entries:    make(chan *JobEntry),
		timer:      time.NewTimer(TIMEOUTDURATION),
	}
	go MonitorQueue(q)
	return q
}

// SaveToDisk will write any unused entries to disk
//
// This is not thread safe and external locking should be used.
func (q *Queue) SaveToDisk() {
	var jobfile JobFile
	if q.HasOnDisk() {
		q.PopOnDiskJobs(&jobfile)
	}
	for {
		select {
		case job := <-q.entries:
			jobfile.Jobs = append(jobfile.Jobs, job)
		default:
			if len(jobfile.Jobs) < 1 {
				return
			}
			w, err := os.OpenFile(q.ondiskfile, os.O_CREATE|os.O_RDWR, 0666)
			if err != nil {
				panic(err)
			}
			w.Write(jobfile.Jobs.Serialize())
			q.rw.Lock()
			defer q.rw.Unlock()
			q.ondisk = true
			return
		}
	}
}

// HasOnDisk returns the ondisk state
func (q Queue) HasOnDisk() bool {
	q.rw.RLock()
	defer q.rw.RUnlock()
	return q.ondisk
}

// Reset the underlying timer. Used when we interact with the queue so
// we can organize the writes to disk into low-activity periods.
func (q *Queue) Reset() bool {
	q.t.Lock()
	defer q.t.Unlock()
	return q.timer.Reset(TIMEOUTDURATION)
}

// Pop off all the on-disk jobs into the supplied JobFile.
func (q *Queue) PopOnDiskJobs(j *JobFile) {
	if q.ondiskfile == "" {
		panic("Queue's job file is inaccessible.")
	}
	q.m.Lock()
	defer q.m.Unlock()
	b, err := ioutil.ReadFile(q.ondiskfile)
	if err != nil {
		log.Println(err)
		return
	}
	err = json.Unmarshal(b, j)
	if err != nil {
		log.Println(err)
		return
	}
	q.ondisk = false
	if err := os.Remove(q.ondiskfile); err != nil {
		log.Println(err)
	}
}

// Monitors a queue for inactivity, if there is inactivity for the
// specified timeout duration, we write to disk.
func MonitorQueue(q *Queue) {
	log.Printf("Monitoring %s\n", q.ondiskfile)
	for {
		<-q.timer.C
		q.m.Lock()
		q.SaveToDisk()
		q.Reset()
		q.m.Unlock()
	}
}

func (j Jobs) Serialize() []byte {
	var b bytes.Buffer
	b.WriteString(`{"jobs":[`)
	for idx, job := range j {
		b.Write(job.Serialize())
		if idx+1 != len(j) {
			b.WriteString(",")
		}
	}
	b.WriteString("]}")
	return b.Bytes()
}

func (j JobEntry) Serialize() []byte {
	b, _ := json.Marshal(j)
	return b
}

func Pop(w http.ResponseWriter, req *http.Request) {
	job, err := readbody(req.Body)
	if err != nil {
		writefail(w)
		return
	}
	queue, ok := Queues[job.QueueName]
	if !ok {
		writefail(w)
		return
	}

	// We're interacting with the queue so we'll reset the timer to
	// show that
	queue.Reset()
	var jobfile JobFile

	// Get all the pending jobs from disk
	if queue.HasOnDisk() {
		queue.PopOnDiskJobs(&jobfile)
	}

	// Doing it this way allows other readers to take jobs out the
	// queue without duplicating our jobs.
	for {
		select {
		case job := <-queue.entries:
			jobfile.Jobs = append(jobfile.Jobs, job)
		default:
			if len(jobfile.Jobs) < 1 {
				w.WriteHeader(http.StatusNoContent)
				return
			}
			w.Write(jobfile.Jobs.Serialize())
			return
		}
	}
}

// Pushes a new job into the queue.
func Push(w http.ResponseWriter, req *http.Request) {
	job, err := readbody(req.Body)
	if err != nil {
		writefail(w)
		return
	}
	go func() {
		if queue, ok := Queues[job.QueueName]; ok {
			queue.Reset()
			queue.entries <- job
		}
	}()
	writesuccess(w)
}

func readbody(b io.ReadCloser) (*JobEntry, error) {
	if b == nil {
		return nil, errors.New("Nil body supplied!")
	}
	defer b.Close()
	body, err := ioutil.ReadAll(b)
	if err != nil {
		return nil, err
	}
	e := &JobEntry{}
	err = json.Unmarshal(body, e)
	return e, err
}

func writesuccess(w http.ResponseWriter) {
	w.Write([]byte(`{"success": true}`))
}

func writefail(w http.ResponseWriter) {
	w.WriteHeader(http.StatusBadRequest)
	w.Write([]byte(`{"success": false}`))
}

func main() {

	// Save to disk in the case of horrible failure.
	defer func() {
		if err := recover(); err != nil {
			log.Println(err)
			for _, queue := range Queues {
				queue.SaveToDisk()
			}
		}
	}()
	Queues = make(map[string]*Queue)
	Queues["tt"] = NewQueue("tt.q")
	http.HandleFunc("/push/", Push)
	http.HandleFunc("/pop/", Pop)
	log.Fatal(http.ListenAndServe(":8080", nil))
}
<|endoftext|>


<commit_before>package ghch

import (
	"bytes"
	"fmt"
	"os"
	"os/exec"
	"regexp"
	"sort"
	"strings"

	"github.com/Masterminds/semver"
)

type Ghch struct {
	RepoPath string
}

func (gh *Ghch) Cmd(argv ...string) (string, error) {
	arg := []string{"-C", gh.RepoPath}
	arg = append(arg, argv...)
	cmd := exec.Command("git", arg...)
	cmd.Env = append(os.Environ(), "LANG=C")

	var b bytes.Buffer
	cmd.Stdout = &b
	err := cmd.Run()
	return b.String(), err
}

var verReg = regexp.MustCompile(`^v?[0-9]+(?:\.[0-9]+){0,2}$`)

func (gh *Ghch) Versions() []string {
	out, _ := gh.Cmd("tag")
	rawTags := strings.Split(out, "\n")
	var versions []*semver.Version
	for _, tag := range rawTags {
		t := strings.TrimSpace(tag)
		if verReg.MatchString(t) {
			v, _ := semver.NewVersion(t)
			versions = append(versions, v)
		}
	}
	sort.Sort(sort.Reverse(semver.Collection(versions)))
	var vers = make([]string, len(versions))
	for i, v := range versions {
		vers[i] = v.Original()
	}
	return vers
}

var prMergeReg = regexp.MustCompile(`^[a-f0-9]{7} Merge pull request #([0-9]+) from`)

func (gh *Ghch) MergedPRNums(argv ...string) (nums []string) {
	var from, to string
	if len(argv) > 0 {
		from = argv[0]
	}
	if len(argv) > 1 {
		from = argv[1]
	}
	if from == "" {
		vers := gh.Versions()
		if len(vers) < 1 {
			return
		}
		from = vers[0]
	}
	revisionRange := fmt.Sprintf("%s...%s", from, to)
	out, err := gh.Cmd("log", revisionRange, "--merges", "--oneline")
	if err != nil {
		return
	}
	lines := strings.Split(out, "\n")
	for _, line := range lines {
		if matches := prMergeReg.FindStringSubmatch(line); len(matches) > 1 {
			nums = append(nums, matches[1])
		}
	}
	return
}
<commit_msg>Remote<commit_after>package ghch

import (
	"bytes"
	"fmt"
	"os"
	"os/exec"
	"regexp"
	"sort"
	"strings"

	"github.com/google/go-github/github"
	"github.com/Masterminds/semver"
)

type Ghch struct {
	RepoPath string
	client *github.Client
}

func New(repo string) *Ghch {
	return &Ghch{
		RepoPath: "/Users/Songmu/dev/src/github.com/mackerelio/mackerel-agent",
		client: github.NewClient(nil),
	}
}

func (gh *Ghch) Cmd(argv ...string) (string, error) {
	arg := []string{"-C", gh.RepoPath}
	arg = append(arg, argv...)
	cmd := exec.Command("git", arg...)
	cmd.Env = append(os.Environ(), "LANG=C")

	var b bytes.Buffer
	cmd.Stdout = &b
	err := cmd.Run()
	return b.String(), err
}

var verReg = regexp.MustCompile(`^v?[0-9]+(?:\.[0-9]+){0,2}$`)

func (gh *Ghch) Versions() []string {
	out, _ := gh.Cmd("tag")
	rawTags := strings.Split(out, "\n")
	var versions []*semver.Version
	for _, tag := range rawTags {
		t := strings.TrimSpace(tag)
		if verReg.MatchString(t) {
			v, _ := semver.NewVersion(t)
			versions = append(versions, v)
		}
	}
	sort.Sort(sort.Reverse(semver.Collection(versions)))
	var vers = make([]string, len(versions))
	for i, v := range versions {
		vers[i] = v.Original()
	}
	return vers
}

var repoURLReg = regexp.MustCompile(`([^/:]+)/([^/]+?)(?:\.git)?$`)

func (gh *Ghch) Remote() (org, repo string) {
	out, _ := gh.Cmd("remote", "-v")
	remotes := strings.Split(out, "\n")
	for _, r := range remotes {
		fields := strings.Fields(r)
		if len(fields) > 1 && fields[0] == "origin" {
			if matches := repoURLReg.FindStringSubmatch(fields[1]); len(matches) > 2 {
				return matches[1], matches[2]
			}
		}
	}
	return
}

var prMergeReg = regexp.MustCompile(`^[a-f0-9]{7} Merge pull request #([0-9]+) from`)

func (gh *Ghch) MergedPRNums(argv ...string) (nums []string) {
	var from, to string
	if len(argv) > 0 {
		from = argv[0]
	}
	if len(argv) > 1 {
		from = argv[1]
	}
	if from == "" {
		vers := gh.Versions()
		if len(vers) < 1 {
			return
		}
		from = vers[0]
	}
	revisionRange := fmt.Sprintf("%s...%s", from, to)
	out, err := gh.Cmd("log", revisionRange, "--merges", "--oneline")
	if err != nil {
		return
	}
	lines := strings.Split(out, "\n")
	for _, line := range lines {
		if matches := prMergeReg.FindStringSubmatch(line); len(matches) > 1 {
			nums = append(nums, matches[1])
		}
	}
	return
}
<|endoftext|>


<commit_before>package web

import "gopkg.in/webnice/debug.v1"
import "gopkg.in/webnice/log.v2"
import (
	"crypto/tls"
	"net"
	"os"
)

// Wait while web server is running
func (wsv *web) Wait() Interface { wsv.doCloseDone.Wait(); return wsv }

// ListenAndServe listens on the TCP network address addr and then calls Serve with handler to handle requests on incoming connections
func (wsv *web) ListenAndServe(addr string) Interface {
	var conf *Configuration

	if conf, wsv.err = parseAddress(addr); wsv.err != nil {
		return wsv
	}

	return wsv.ListenAndServeWithConfig(conf)
}

// ListenAndServeTLS listens on the TCP network address address with TLS and then calls Serve with handler
// to handle requests on incoming connections
func (wsv *web) ListenAndServeTLS(addr string, certFile string, keyFile string, tlsConfig *tls.Config) Interface {
	var conf *Configuration

	if conf, wsv.err = parseAddress(addr); wsv.err != nil {
		return wsv
	}
	conf.TLSPublicKeyPEM, conf.TLSPrivateKeyPEM = certFile, keyFile

	return wsv.ListenAndServeTLSWithConfig(conf, tlsConfig)
}

// ListenAndServeWithConfig Fully configurable web server listens and then calls Serve on incoming connections
func (wsv *web) ListenAndServeWithConfig(conf *Configuration) Interface {
	if conf == nil {
		wsv.err = ErrNoConfiguration()
		return wsv
	}
	wsv.conf = conf

	return wsv.Listen(nil)
}

// ListenAndServeTLSWithConfig Fully configurable web server listens and then calls Serve on incoming connections
func (wsv *web) ListenAndServeTLSWithConfig(conf *Configuration, tlsConfig *tls.Config) Interface {
	if conf == nil {
		wsv.err = ErrNoConfiguration()
		return wsv
	}
	wsv.conf = conf
	if tlsConfig == nil {
		if tlsConfig, wsv.err = wsv.tlsConfigDefault(conf.TLSPublicKeyPEM, conf.TLSPrivateKeyPEM); wsv.err != nil {
			return wsv
		}
	}

	return wsv.Listen(tlsConfig)
}

// NewListener Make new listener from web server configuration
func (wsv *web) NewListener(conf *Configuration) (ret net.Listener, err error) {
	var (
		lstWithNames map[string][]net.Listener
		listeners    []net.Listener
		ok           bool
	)

	defaultConfiguration(conf)
	switch conf.Mode {
	case netSystemd:
		if conf.Socket != "" {
			// Имена сокетов указаны
			if lstWithNames, err = wsv.ListenersSystemdWithNames(false); err != nil {
				return
			}
			// Выбор сокета по имени
			if listeners, ok = lstWithNames[conf.Socket]; !ok {
				err = ErrListenSystemdNotFound()
				return
			}
		} else {
			// Имена сокетов не указаны
			if listeners, err = wsv.ListenersSystemdWithoutNames(false); err != nil {
				return
			}
		}
		log.Debug(debug.DumperString(lstWithNames, listeners, os.Environ(), conf.Socket, ok))
		if len(listeners) == 0 {
			err = ErrListenSystemdUnexpectedNumber()
			return
		}
		ret = listeners[0]
	case netUnix, netUnixPacket:
		_ = os.Remove(conf.Socket)
		ret, err = net.Listen(conf.Mode, conf.Socket)
		_ = os.Chmod(conf.Socket, os.FileMode(0666))
	default:
		ret, err = net.Listen(conf.Mode, conf.HostPort)
	}

	return
}

// NewListenerTLS Make new listener with TLS from web server configuration
func (wsv *web) NewListenerTLS(conf *Configuration, tlsConfig *tls.Config) (ret net.Listener, err error) {
	var l net.Listener

	if l, err = wsv.NewListener(conf); err != nil {
		return
	}
	if tlsConfig == nil {
		if tlsConfig, err = wsv.tlsConfigDefault(conf.TLSPublicKeyPEM, conf.TLSPrivateKeyPEM); err != nil {
			return
		}
	}
	ret = tls.NewListener(l, tlsConfig)

	return
}

// Конфигурация TLS по умолчанию
func (wsv *web) tlsConfigDefault(tlsPublicFile string, tlsPrivateFile string) (ret *tls.Config, err error) {
	ret = &tls.Config{
		MinVersion:               tls.VersionTLS12,
		CurvePreferences:         []tls.CurveID{tls.CurveP521, tls.CurveP384, tls.CurveP256},
		PreferServerCipherSuites: true,
		CipherSuites: []uint16{
			tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
			tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
			tls.TLS_RSA_WITH_AES_256_GCM_SHA384,
			tls.TLS_RSA_WITH_AES_256_CBC_SHA,
		},
		Certificates: make([]tls.Certificate, 1),
	}
	if ret.Certificates[0], err = tls.LoadX509KeyPair(tlsPublicFile, tlsPrivateFile); err != nil {
		return
	}

	return
}

// Listen Begin listen port and web server serve
func (wsv *web) Listen(tlsConfig *tls.Config) Interface {
	var ltn net.Listener

	if wsv.isRun.Load().(bool) {
		wsv.err = ErrAlreadyRunning()
		return wsv
	}
	switch tlsConfig == nil {
	case true:
		ltn, wsv.err = wsv.NewListener(wsv.conf)
	case false:
		ltn, wsv.err = wsv.NewListenerTLS(wsv.conf, tlsConfig)
	}
	if wsv.err != nil {
		return wsv
	}

	return wsv.ServeTLS(ltn, tlsConfig)
}

// Serve accepts incoming connections on the listener, creating a new web server goroutine
func (wsv *web) Serve(ltn net.Listener) Interface { return wsv.ServeTLS(ltn, nil) }

// ServeTLS accepts incoming connections on the listener with TLS configuration, creating a new web server goroutine
func (wsv *web) ServeTLS(ltn net.Listener, tlsConfig *tls.Config) Interface {
	var conf *Configuration

	// TODO: Реализовать поддержку PROXY Protocol через "gopkg.in/webnice/web.v1/proxyp", conf.ProxyProtocol

	if wsv.conf == nil {
		conf, _ = parseAddress(ltn.Addr().String())
		defaultConfiguration(conf)
		wsv.conf = conf
	}
	wsv.listener = ltn
	wsv.isRun.Store(true)
	wsv.doCloseDone.Add(1)
	go wsv.run(tlsConfig)

	return wsv
}

// Goroutine of the web server
func (wsv *web) run(tlsConfig *tls.Config) {
	defer wsv.doCloseDone.Done()
	defer wsv.isRun.Store(false)
	defer func() {
		if wsv.conf.Socket == "" {
			return
		}
		switch wsv.conf.Mode {
		case netSystemd:
			return
		case netUnix, netUnixPacket:
			_ = os.Remove(wsv.conf.Socket)
		}
	}()

	// Configure net/http web server
	if wsv.server = wsv.loadConfiguration(tlsConfig); wsv.err != nil {
		return
	}
	// Configure keepalive of web server
	if wsv.conf.KeepAliveDisable {
		wsv.server.SetKeepAlivesEnabled(false)
	}
	// Begin serve
	if wsv.conf.TLSPrivateKeyPEM == "" || wsv.conf.TLSPublicKeyPEM == "" {
		wsv.err = wsv.server.Serve(wsv.listener)
		return
	}
	wsv.err = wsv.server.ServeTLS(wsv.listener, wsv.conf.TLSPublicKeyPEM, wsv.conf.TLSPrivateKeyPEM)
}
<commit_msg>Debug added temporarily<commit_after>package web

import "gopkg.in/webnice/debug.v1"
import "gopkg.in/webnice/log.v2"
import (
	"crypto/tls"
	"net"
	"os"
)

// Wait while web server is running
func (wsv *web) Wait() Interface { wsv.doCloseDone.Wait(); return wsv }

// ListenAndServe listens on the TCP network address addr and then calls Serve with handler to handle requests on incoming connections
func (wsv *web) ListenAndServe(addr string) Interface {
	var conf *Configuration

	if conf, wsv.err = parseAddress(addr); wsv.err != nil {
		return wsv
	}

	return wsv.ListenAndServeWithConfig(conf)
}

// ListenAndServeTLS listens on the TCP network address address with TLS and then calls Serve with handler
// to handle requests on incoming connections
func (wsv *web) ListenAndServeTLS(addr string, certFile string, keyFile string, tlsConfig *tls.Config) Interface {
	var conf *Configuration

	if conf, wsv.err = parseAddress(addr); wsv.err != nil {
		return wsv
	}
	conf.TLSPublicKeyPEM, conf.TLSPrivateKeyPEM = certFile, keyFile

	return wsv.ListenAndServeTLSWithConfig(conf, tlsConfig)
}

// ListenAndServeWithConfig Fully configurable web server listens and then calls Serve on incoming connections
func (wsv *web) ListenAndServeWithConfig(conf *Configuration) Interface {
	if conf == nil {
		wsv.err = ErrNoConfiguration()
		return wsv
	}
	wsv.conf = conf

	return wsv.Listen(nil)
}

// ListenAndServeTLSWithConfig Fully configurable web server listens and then calls Serve on incoming connections
func (wsv *web) ListenAndServeTLSWithConfig(conf *Configuration, tlsConfig *tls.Config) Interface {
	if conf == nil {
		wsv.err = ErrNoConfiguration()
		return wsv
	}
	wsv.conf = conf
	if tlsConfig == nil {
		if tlsConfig, wsv.err = wsv.tlsConfigDefault(conf.TLSPublicKeyPEM, conf.TLSPrivateKeyPEM); wsv.err != nil {
			return wsv
		}
	}

	return wsv.Listen(tlsConfig)
}

// NewListener Make new listener from web server configuration
func (wsv *web) NewListener(conf *Configuration) (ret net.Listener, err error) {
	var (
		lstWithNames map[string][]net.Listener
		listeners    []net.Listener
		ok           bool
	)

	defaultConfiguration(conf)
	switch conf.Mode {
	case netSystemd:
		if conf.Socket != "" {
			// Имена сокетов указаны
			if lstWithNames, err = wsv.ListenersSystemdWithNames(false); err != nil {
				return
			}

			log.Debug(debug.DumperString(lstWithNames, listeners, os.Environ(), conf.Socket, conf))

			// Выбор сокета по имени
			if listeners, ok = lstWithNames[conf.Socket]; !ok {
				err = ErrListenSystemdNotFound()
				return
			}
		} else {
			// Имена сокетов не указаны
			if listeners, err = wsv.ListenersSystemdWithoutNames(false); err != nil {
				return
			}
		}
		if len(listeners) == 0 {
			err = ErrListenSystemdUnexpectedNumber()
			return
		}
		ret = listeners[0]
	case netUnix, netUnixPacket:
		_ = os.Remove(conf.Socket)
		ret, err = net.Listen(conf.Mode, conf.Socket)
		_ = os.Chmod(conf.Socket, os.FileMode(0666))
	default:
		ret, err = net.Listen(conf.Mode, conf.HostPort)
	}

	return
}

// NewListenerTLS Make new listener with TLS from web server configuration
func (wsv *web) NewListenerTLS(conf *Configuration, tlsConfig *tls.Config) (ret net.Listener, err error) {
	var l net.Listener

	if l, err = wsv.NewListener(conf); err != nil {
		return
	}
	if tlsConfig == nil {
		if tlsConfig, err = wsv.tlsConfigDefault(conf.TLSPublicKeyPEM, conf.TLSPrivateKeyPEM); err != nil {
			return
		}
	}
	ret = tls.NewListener(l, tlsConfig)

	return
}

// Конфигурация TLS по умолчанию
func (wsv *web) tlsConfigDefault(tlsPublicFile string, tlsPrivateFile string) (ret *tls.Config, err error) {
	ret = &tls.Config{
		MinVersion:               tls.VersionTLS12,
		CurvePreferences:         []tls.CurveID{tls.CurveP521, tls.CurveP384, tls.CurveP256},
		PreferServerCipherSuites: true,
		CipherSuites: []uint16{
			tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
			tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
			tls.TLS_RSA_WITH_AES_256_GCM_SHA384,
			tls.TLS_RSA_WITH_AES_256_CBC_SHA,
		},
		Certificates: make([]tls.Certificate, 1),
	}
	if ret.Certificates[0], err = tls.LoadX509KeyPair(tlsPublicFile, tlsPrivateFile); err != nil {
		return
	}

	return
}

// Listen Begin listen port and web server serve
func (wsv *web) Listen(tlsConfig *tls.Config) Interface {
	var ltn net.Listener

	if wsv.isRun.Load().(bool) {
		wsv.err = ErrAlreadyRunning()
		return wsv
	}
	switch tlsConfig == nil {
	case true:
		ltn, wsv.err = wsv.NewListener(wsv.conf)
	case false:
		ltn, wsv.err = wsv.NewListenerTLS(wsv.conf, tlsConfig)
	}
	if wsv.err != nil {
		return wsv
	}

	return wsv.ServeTLS(ltn, tlsConfig)
}

// Serve accepts incoming connections on the listener, creating a new web server goroutine
func (wsv *web) Serve(ltn net.Listener) Interface { return wsv.ServeTLS(ltn, nil) }

// ServeTLS accepts incoming connections on the listener with TLS configuration, creating a new web server goroutine
func (wsv *web) ServeTLS(ltn net.Listener, tlsConfig *tls.Config) Interface {
	var conf *Configuration

	// TODO: Реализовать поддержку PROXY Protocol через "gopkg.in/webnice/web.v1/proxyp", conf.ProxyProtocol

	if wsv.conf == nil {
		conf, _ = parseAddress(ltn.Addr().String())
		defaultConfiguration(conf)
		wsv.conf = conf
	}
	wsv.listener = ltn
	wsv.isRun.Store(true)
	wsv.doCloseDone.Add(1)
	go wsv.run(tlsConfig)

	return wsv
}

// Goroutine of the web server
func (wsv *web) run(tlsConfig *tls.Config) {
	defer wsv.doCloseDone.Done()
	defer wsv.isRun.Store(false)
	defer func() {
		if wsv.conf.Socket == "" {
			return
		}
		switch wsv.conf.Mode {
		case netSystemd:
			return
		case netUnix, netUnixPacket:
			_ = os.Remove(wsv.conf.Socket)
		}
	}()

	// Configure net/http web server
	if wsv.server = wsv.loadConfiguration(tlsConfig); wsv.err != nil {
		return
	}
	// Configure keepalive of web server
	if wsv.conf.KeepAliveDisable {
		wsv.server.SetKeepAlivesEnabled(false)
	}
	// Begin serve
	if wsv.conf.TLSPrivateKeyPEM == "" || wsv.conf.TLSPublicKeyPEM == "" {
		wsv.err = wsv.server.Serve(wsv.listener)
		return
	}
	wsv.err = wsv.server.ServeTLS(wsv.listener, wsv.conf.TLSPublicKeyPEM, wsv.conf.TLSPrivateKeyPEM)
}
<|endoftext|>


<commit_before>// Module level logging for Go
//
// This package provides an alternative to the standard library log package.
//
// The actual logging functions never return errors.  If you are logging
// something, you really don't want to be worried about the logging
// having trouble.
//
// Modules have names that are defined by dotted strings.
//   e.g.  "first.second.third"
//
// There is a root module that has the name "".  Each module
// (except the root module) has a parent, identified by the part of
// the name without the last dotted value.
//   e.g. the parent of "first.second.third" is "first.second"
//        the parent of "first.second" is "first"
//        the parent of "first" is "" (the root module)
//
// Each module can specify its own severity level.  Logging calls that are of
// a lower severity than the module's effective severity level are not written
// out.
//
// Loggers are created using the GetLogger function.
//   e.g. logger := loggo.GetLogger("foo.bar")
//
// By default there is one writer registered, which will write to Stderr,
// and the root module, which will only emit warnings and above.
// If you want to continue using the default
// logger, but have it emit all logging levels you need to do the following.
//
//   writer, _, err := loggo.RemoveWriter("default")
//   // err is non-nil if and only if the name isn't found.
//   loggo.RegisterWriter("default", writer, loggo.TRACE)
package loggo

import (
	"fmt"
	"runtime"
	"sort"
	"strings"
	"sync"
	"sync/atomic"
	"time"
)

// Level holds a severity level.
type Level uint32

// The severity levels. Higher values are more considered more
// important.
const (
	UNSPECIFIED Level = iota
	TRACE
	DEBUG
	INFO
	WARNING
	ERROR
	CRITICAL
)

// A Logger represents a logging module. It has an associated logging
// level which can be changed; messages of lesser severity will
// be dropped. Loggers have a hierarchical relationship - see
// the package documentation.
//
// The zero Logger value is usable - any messages logged
// to it will be sent to the root Logger.
type Logger struct {
	impl *module
}

type module struct {
	name   string
	level  Level
	parent *module
}

// Initially the modules map only contains the root module.
var (
	root         = &module{level: WARNING}
	modulesMutex sync.Mutex
	modules      = map[string]*module{
		"": root,
	}
)

func (level Level) String() string {
	switch level {
	case UNSPECIFIED:
		return "UNSPECIFIED"
	case TRACE:
		return "TRACE"
	case DEBUG:
		return "DEBUG"
	case INFO:
		return "INFO"
	case WARNING:
		return "WARNING"
	case ERROR:
		return "ERROR"
	case CRITICAL:
		return "CRITICAL"
	}
	return "<unknown>"
}

// get atomically gets the value of the given level.
func (level *Level) get() Level {
	return Level(atomic.LoadUint32((*uint32)(level)))
}

// set atomically sets the value of the receiver
// to the given level.
func (level *Level) set(newLevel Level) {
	atomic.StoreUint32((*uint32)(level), uint32(newLevel))
}

// getLoggerInternal assumes that the modulesMutex is locked.
func getLoggerInternal(name string) Logger {
	impl, found := modules[name]
	if found {
		return Logger{impl}
	}
	parentName := ""
	if i := strings.LastIndex(name, "."); i >= 0 {
		parentName = name[0:i]
	}
	parent := getLoggerInternal(parentName).impl
	impl = &module{name, UNSPECIFIED, parent}
	modules[name] = impl
	return Logger{impl}
}

// GetLogger returns a Logger for the given module name,
// creating it and its parents if necessary.
func GetLogger(name string) Logger {
	// Lowercase the module name, and look for it in the modules map.
	name = strings.ToLower(name)
	modulesMutex.Lock()
	defer modulesMutex.Unlock()
	return getLoggerInternal(name)
}

// LoggerInfo returns information about the configured loggers and their logging
// levels.  The information is returned in the format expected by
// ConfigureModules. Loggers with UNSPECIFIED level will not
// be included.
func LoggerInfo() string {
	output := []string{}
	// output in alphabetical order.
	keys := []string{}
	modulesMutex.Lock()
	defer modulesMutex.Unlock()
	for key := range modules {
		keys = append(keys, key)
	}
	sort.Strings(keys)
	for _, name := range keys {
		mod := modules[name]
		severity := mod.level
		if severity == UNSPECIFIED {
			continue
		}
		output = append(output, fmt.Sprintf("%s=%s", mod.Name(), severity))
	}
	return strings.Join(output, ";")
}

// ParseConfigurationString parses a logger configuration string into a map of
// logger names and their associated log level. This method is provided to
// allow other programs to pre-validate a configuration string rather than
// just calling ConfigureLoggers.
//
// Loggers are colon- or semicolon-separated; each module is specified as
// <modulename>=<level>.  White space outside of module names and levels is
// ignored.  The root module is specified with the name "<root>".
//
// As a special case, a log level may be specified on its own.
// This is equivalent to specifying the level of the root module,
// so "DEBUG" is equivalent to `<root>=DEBUG`
//
// An example specification:
//	`<root>=ERROR; foo.bar=WARNING`
func ParseConfigurationString(specification string) (map[string]Level, error) {
	levels := make(map[string]Level)
	if level, ok := ParseLevel(specification); ok {
		levels[""] = level
		return levels, nil
	}
	values := strings.FieldsFunc(specification, func(r rune) bool { return r == ';' || r == ':' })
	for _, value := range values {
		s := strings.SplitN(value, "=", 2)
		if len(s) < 2 {
			return nil, fmt.Errorf("logger specification expected '=', found %q", value)
		}
		name := strings.TrimSpace(s[0])
		levelStr := strings.TrimSpace(s[1])
		if name == "" || levelStr == "" {
			return nil, fmt.Errorf("logger specification %q has blank name or level", value)
		}
		if name == "<root>" {
			name = ""
		}
		level, ok := ParseLevel(levelStr)
		if !ok {
			return nil, fmt.Errorf("unknown severity level %q", levelStr)
		}
		levels[name] = level
	}
	return levels, nil
}

// ConfigureLoggers configures loggers according to the given string
// specification, which specifies a set of modules and their associated
// logging levels.  Loggers are colon- or semicolon-separated; each
// module is specified as <modulename>=<level>.  White space outside of
// module names and levels is ignored.  The root module is specified
// with the name "<root>".
//
// An example specification:
//	`<root>=ERROR; foo.bar=WARNING`
func ConfigureLoggers(specification string) error {
	if specification == "" {
		return nil
	}
	levels, err := ParseConfigurationString(specification)
	if err != nil {
		return err
	}
	for name, level := range levels {
		GetLogger(name).SetLogLevel(level)
	}
	return nil
}

// ResetLogging iterates through the known modules and sets the levels of all
// to UNSPECIFIED, except for <root> which is set to WARNING.
func ResetLoggers() {
	modulesMutex.Lock()
	defer modulesMutex.Unlock()
	for name, module := range modules {
		if name == "" {
			module.level.set(WARNING)
		} else {
			module.level.set(UNSPECIFIED)
		}
	}
}

// ParseLevel converts a string representation of a logging level to a
// Level. It returns the level and whether it was valid or not.
func ParseLevel(level string) (Level, bool) {
	level = strings.ToUpper(level)
	switch level {
	case "UNSPECIFIED":
		return UNSPECIFIED, true
	case "TRACE":
		return TRACE, true
	case "DEBUG":
		return DEBUG, true
	case "INFO":
		return INFO, true
	case "WARN", "WARNING":
		return WARNING, true
	case "ERROR":
		return ERROR, true
	case "CRITICAL":
		return CRITICAL, true
	}
	return UNSPECIFIED, false
}

func (logger Logger) getModule() *module {
	if logger.impl == nil {
		return root
	}
	return logger.impl
}

// Name returns the logger's module name.
func (logger Logger) Name() string {
	return logger.getModule().Name()
}

// LogLevel returns the configured log level of the logger.
func (logger Logger) LogLevel() Level {
	return logger.getModule().level.get()
}

func (module *module) getEffectiveLogLevel() Level {
	// Note: the root module is guaranteed to have a
	// specified logging level, so acts as a suitable sentinel
	// for this loop.
	for {
		if level := module.level.get(); level != UNSPECIFIED {
			return level
		}
		module = module.parent
	}
	panic("unreachable")
}

func (module *module) Name() string {
	if module.name == "" {
		return "<root>"
	}
	return module.name
}

// EffectiveLogLevel returns the effective log level of
// the receiver - that is, messages with a lesser severity
// level will be discarded.
//
// If the log level of the receiver is unspecified,
// it will be taken from the effective log level of its
// parent.
func (logger Logger) EffectiveLogLevel() Level {
	return logger.getModule().getEffectiveLogLevel()
}

// SetLogLevel sets the severity level of the given logger.
// The root logger cannot be set to UNSPECIFIED level.
// See EffectiveLogLevel for how this affects the
// actual messages logged.
func (logger Logger) SetLogLevel(level Level) {
	module := logger.getModule()
	// The root module can't be unspecified.
	if module.name == "" && level == UNSPECIFIED {
		level = WARNING
	}
	module.level.set(level)
}

// Logf logs a printf-formatted message at the given level.
// A message will be discarded if level is less than the
// the effective log level of the logger.
// Note that the writers may also filter out messages that
// are less than their registered minimum severity level.
func (logger Logger) Logf(level Level, message string, args ...interface{}) {
	if logger.getModule().getEffectiveLogLevel() > level ||
		!WillWrite(level) ||
		level < TRACE ||
		level > CRITICAL {
		return
	}
	// Gather time, and filename, line number.
	now := time.Now() // get this early.
	// Param to Caller is the call depth.  Since this method is called from
	// the Logger methods, we want the place that those were called from.
	_, file, line, ok := runtime.Caller(2)
	if !ok {
		file = "???"
		line = 0
	}
	// Trim newline off format string, following usual
	// Go logging conventions.
	if len(message) > 0 && message[len(message)-1] == '\n' {
		message = message[0 : len(message)-1]
	}

	formattedMessage := fmt.Sprintf(message, args...)
	writeToWriters(level, logger.impl.name, file, line, now, formattedMessage)
}

// Criticalf logs the printf-formatted message at critical level.
func (logger Logger) Criticalf(message string, args ...interface{}) {
	logger.Logf(CRITICAL, message, args...)
}

// Errorf logs the printf-formatted message at error level.
func (logger Logger) Errorf(message string, args ...interface{}) {
	logger.Logf(ERROR, message, args...)
}

// Warningf logs the printf-formatted message at warning level.
func (logger Logger) Warningf(message string, args ...interface{}) {
	logger.Logf(WARNING, message, args...)
}

// Infof logs the printf-formatted message at info level.
func (logger Logger) Infof(message string, args ...interface{}) {
	logger.Logf(INFO, message, args...)
}

// Debugf logs the printf-formatted message at debug level.
func (logger Logger) Debugf(message string, args ...interface{}) {
	logger.Logf(DEBUG, message, args...)
}

// Tracef logs the printf-formatted message at trace level.
func (logger Logger) Tracef(message string, args ...interface{}) {
	logger.Logf(TRACE, message, args...)
}

// IsLevelEnabled returns whether debugging is enabled
// for the given log level.
func (logger Logger) IsLevelEnabled(level Level) bool {
	return logger.getModule().getEffectiveLogLevel() <= level
}

// IsErrorEnabled returns whether debugging is enabled
// at error level.
func (logger Logger) IsErrorEnabled() bool {
	return logger.IsLevelEnabled(ERROR)
}

// IsWarningEnabled returns whether debugging is enabled
// at warning level.
func (logger Logger) IsWarningEnabled() bool {
	return logger.IsLevelEnabled(WARNING)
}

// IsInfoEnabled returns whether debugging is enabled
// at info level.
func (logger Logger) IsInfoEnabled() bool {
	return logger.IsLevelEnabled(INFO)
}

// IsDebugEnabled returns whether debugging is enabled
// at debug level.
func (logger Logger) IsDebugEnabled() bool {
	return logger.IsLevelEnabled(DEBUG)
}

// IsTraceEnabled returns whether debugging is enabled
// at trace level.
func (logger Logger) IsTraceEnabled() bool {
	return logger.IsLevelEnabled(TRACE)
}
<commit_msg>Add a function that exposes the calldepth so it can be built on.<commit_after>// Module level logging for Go
//
// This package provides an alternative to the standard library log package.
//
// The actual logging functions never return errors.  If you are logging
// something, you really don't want to be worried about the logging
// having trouble.
//
// Modules have names that are defined by dotted strings.
//   e.g.  "first.second.third"
//
// There is a root module that has the name "".  Each module
// (except the root module) has a parent, identified by the part of
// the name without the last dotted value.
//   e.g. the parent of "first.second.third" is "first.second"
//        the parent of "first.second" is "first"
//        the parent of "first" is "" (the root module)
//
// Each module can specify its own severity level.  Logging calls that are of
// a lower severity than the module's effective severity level are not written
// out.
//
// Loggers are created using the GetLogger function.
//   e.g. logger := loggo.GetLogger("foo.bar")
//
// By default there is one writer registered, which will write to Stderr,
// and the root module, which will only emit warnings and above.
// If you want to continue using the default
// logger, but have it emit all logging levels you need to do the following.
//
//   writer, _, err := loggo.RemoveWriter("default")
//   // err is non-nil if and only if the name isn't found.
//   loggo.RegisterWriter("default", writer, loggo.TRACE)
package loggo

import (
	"fmt"
	"runtime"
	"sort"
	"strings"
	"sync"
	"sync/atomic"
	"time"
)

// Level holds a severity level.
type Level uint32

// The severity levels. Higher values are more considered more
// important.
const (
	UNSPECIFIED Level = iota
	TRACE
	DEBUG
	INFO
	WARNING
	ERROR
	CRITICAL
)

// A Logger represents a logging module. It has an associated logging
// level which can be changed; messages of lesser severity will
// be dropped. Loggers have a hierarchical relationship - see
// the package documentation.
//
// The zero Logger value is usable - any messages logged
// to it will be sent to the root Logger.
type Logger struct {
	impl *module
}

type module struct {
	name   string
	level  Level
	parent *module
}

// Initially the modules map only contains the root module.
var (
	root         = &module{level: WARNING}
	modulesMutex sync.Mutex
	modules      = map[string]*module{
		"": root,
	}
)

func (level Level) String() string {
	switch level {
	case UNSPECIFIED:
		return "UNSPECIFIED"
	case TRACE:
		return "TRACE"
	case DEBUG:
		return "DEBUG"
	case INFO:
		return "INFO"
	case WARNING:
		return "WARNING"
	case ERROR:
		return "ERROR"
	case CRITICAL:
		return "CRITICAL"
	}
	return "<unknown>"
}

// get atomically gets the value of the given level.
func (level *Level) get() Level {
	return Level(atomic.LoadUint32((*uint32)(level)))
}

// set atomically sets the value of the receiver
// to the given level.
func (level *Level) set(newLevel Level) {
	atomic.StoreUint32((*uint32)(level), uint32(newLevel))
}

// getLoggerInternal assumes that the modulesMutex is locked.
func getLoggerInternal(name string) Logger {
	impl, found := modules[name]
	if found {
		return Logger{impl}
	}
	parentName := ""
	if i := strings.LastIndex(name, "."); i >= 0 {
		parentName = name[0:i]
	}
	parent := getLoggerInternal(parentName).impl
	impl = &module{name, UNSPECIFIED, parent}
	modules[name] = impl
	return Logger{impl}
}

// GetLogger returns a Logger for the given module name,
// creating it and its parents if necessary.
func GetLogger(name string) Logger {
	// Lowercase the module name, and look for it in the modules map.
	name = strings.ToLower(name)
	modulesMutex.Lock()
	defer modulesMutex.Unlock()
	return getLoggerInternal(name)
}

// LoggerInfo returns information about the configured loggers and their logging
// levels.  The information is returned in the format expected by
// ConfigureModules. Loggers with UNSPECIFIED level will not
// be included.
func LoggerInfo() string {
	output := []string{}
	// output in alphabetical order.
	keys := []string{}
	modulesMutex.Lock()
	defer modulesMutex.Unlock()
	for key := range modules {
		keys = append(keys, key)
	}
	sort.Strings(keys)
	for _, name := range keys {
		mod := modules[name]
		severity := mod.level
		if severity == UNSPECIFIED {
			continue
		}
		output = append(output, fmt.Sprintf("%s=%s", mod.Name(), severity))
	}
	return strings.Join(output, ";")
}

// ParseConfigurationString parses a logger configuration string into a map of
// logger names and their associated log level. This method is provided to
// allow other programs to pre-validate a configuration string rather than
// just calling ConfigureLoggers.
//
// Loggers are colon- or semicolon-separated; each module is specified as
// <modulename>=<level>.  White space outside of module names and levels is
// ignored.  The root module is specified with the name "<root>".
//
// As a special case, a log level may be specified on its own.
// This is equivalent to specifying the level of the root module,
// so "DEBUG" is equivalent to `<root>=DEBUG`
//
// An example specification:
//	`<root>=ERROR; foo.bar=WARNING`
func ParseConfigurationString(specification string) (map[string]Level, error) {
	levels := make(map[string]Level)
	if level, ok := ParseLevel(specification); ok {
		levels[""] = level
		return levels, nil
	}
	values := strings.FieldsFunc(specification, func(r rune) bool { return r == ';' || r == ':' })
	for _, value := range values {
		s := strings.SplitN(value, "=", 2)
		if len(s) < 2 {
			return nil, fmt.Errorf("logger specification expected '=', found %q", value)
		}
		name := strings.TrimSpace(s[0])
		levelStr := strings.TrimSpace(s[1])
		if name == "" || levelStr == "" {
			return nil, fmt.Errorf("logger specification %q has blank name or level", value)
		}
		if name == "<root>" {
			name = ""
		}
		level, ok := ParseLevel(levelStr)
		if !ok {
			return nil, fmt.Errorf("unknown severity level %q", levelStr)
		}
		levels[name] = level
	}
	return levels, nil
}

// ConfigureLoggers configures loggers according to the given string
// specification, which specifies a set of modules and their associated
// logging levels.  Loggers are colon- or semicolon-separated; each
// module is specified as <modulename>=<level>.  White space outside of
// module names and levels is ignored.  The root module is specified
// with the name "<root>".
//
// An example specification:
//	`<root>=ERROR; foo.bar=WARNING`
func ConfigureLoggers(specification string) error {
	if specification == "" {
		return nil
	}
	levels, err := ParseConfigurationString(specification)
	if err != nil {
		return err
	}
	for name, level := range levels {
		GetLogger(name).SetLogLevel(level)
	}
	return nil
}

// ResetLogging iterates through the known modules and sets the levels of all
// to UNSPECIFIED, except for <root> which is set to WARNING.
func ResetLoggers() {
	modulesMutex.Lock()
	defer modulesMutex.Unlock()
	for name, module := range modules {
		if name == "" {
			module.level.set(WARNING)
		} else {
			module.level.set(UNSPECIFIED)
		}
	}
}

// ParseLevel converts a string representation of a logging level to a
// Level. It returns the level and whether it was valid or not.
func ParseLevel(level string) (Level, bool) {
	level = strings.ToUpper(level)
	switch level {
	case "UNSPECIFIED":
		return UNSPECIFIED, true
	case "TRACE":
		return TRACE, true
	case "DEBUG":
		return DEBUG, true
	case "INFO":
		return INFO, true
	case "WARN", "WARNING":
		return WARNING, true
	case "ERROR":
		return ERROR, true
	case "CRITICAL":
		return CRITICAL, true
	}
	return UNSPECIFIED, false
}

func (logger Logger) getModule() *module {
	if logger.impl == nil {
		return root
	}
	return logger.impl
}

// Name returns the logger's module name.
func (logger Logger) Name() string {
	return logger.getModule().Name()
}

// LogLevel returns the configured log level of the logger.
func (logger Logger) LogLevel() Level {
	return logger.getModule().level.get()
}

func (module *module) getEffectiveLogLevel() Level {
	// Note: the root module is guaranteed to have a
	// specified logging level, so acts as a suitable sentinel
	// for this loop.
	for {
		if level := module.level.get(); level != UNSPECIFIED {
			return level
		}
		module = module.parent
	}
	panic("unreachable")
}

func (module *module) Name() string {
	if module.name == "" {
		return "<root>"
	}
	return module.name
}

// EffectiveLogLevel returns the effective log level of
// the receiver - that is, messages with a lesser severity
// level will be discarded.
//
// If the log level of the receiver is unspecified,
// it will be taken from the effective log level of its
// parent.
func (logger Logger) EffectiveLogLevel() Level {
	return logger.getModule().getEffectiveLogLevel()
}

// SetLogLevel sets the severity level of the given logger.
// The root logger cannot be set to UNSPECIFIED level.
// See EffectiveLogLevel for how this affects the
// actual messages logged.
func (logger Logger) SetLogLevel(level Level) {
	module := logger.getModule()
	// The root module can't be unspecified.
	if module.name == "" && level == UNSPECIFIED {
		level = WARNING
	}
	module.level.set(level)
}

// Logf logs a printf-formatted message at the given level.
// A message will be discarded if level is less than the
// the effective log level of the logger.
// Note that the writers may also filter out messages that
// are less than their registered minimum severity level.
func (logger Logger) Logf(level Level, message string, args ...interface{}) {
	logger.LogCallf(2, level, message, args...)
}

// LogCallf logs a printf-formatted message at the given level.
// The location of the call is indicated by the calldepth argument.
// A calldepth of 1 means the function that called this function.
// A message will be discarded if level is less than the
// the effective log level of the logger.
// Note that the writers may also filter out messages that
// are less than their registered minimum severity level.
func (logger Logger) LogCallf(calldepth int, level Level, message string, args ...interface{}) {
	if logger.getModule().getEffectiveLogLevel() > level ||
		!WillWrite(level) ||
		level < TRACE ||
		level > CRITICAL {
		return
	}
	// Gather time, and filename, line number.
	now := time.Now() // get this early.
	// Param to Caller is the call depth.  Since this method is called from
	// the Logger methods, we want the place that those were called from.
	_, file, line, ok := runtime.Caller(calldepth + 1)
	if !ok {
		file = "???"
		line = 0
	}
	// Trim newline off format string, following usual
	// Go logging conventions.
	if len(message) > 0 && message[len(message)-1] == '\n' {
		message = message[0 : len(message)-1]
	}

	formattedMessage := fmt.Sprintf(message, args...)
	writeToWriters(level, logger.impl.name, file, line, now, formattedMessage)
}

// Criticalf logs the printf-formatted message at critical level.
func (logger Logger) Criticalf(message string, args ...interface{}) {
	logger.Logf(CRITICAL, message, args...)
}

// Errorf logs the printf-formatted message at error level.
func (logger Logger) Errorf(message string, args ...interface{}) {
	logger.Logf(ERROR, message, args...)
}

// Warningf logs the printf-formatted message at warning level.
func (logger Logger) Warningf(message string, args ...interface{}) {
	logger.Logf(WARNING, message, args...)
}

// Infof logs the printf-formatted message at info level.
func (logger Logger) Infof(message string, args ...interface{}) {
	logger.Logf(INFO, message, args...)
}

// Debugf logs the printf-formatted message at debug level.
func (logger Logger) Debugf(message string, args ...interface{}) {
	logger.Logf(DEBUG, message, args...)
}

// Tracef logs the printf-formatted message at trace level.
func (logger Logger) Tracef(message string, args ...interface{}) {
	logger.Logf(TRACE, message, args...)
}

// IsLevelEnabled returns whether debugging is enabled
// for the given log level.
func (logger Logger) IsLevelEnabled(level Level) bool {
	return logger.getModule().getEffectiveLogLevel() <= level
}

// IsErrorEnabled returns whether debugging is enabled
// at error level.
func (logger Logger) IsErrorEnabled() bool {
	return logger.IsLevelEnabled(ERROR)
}

// IsWarningEnabled returns whether debugging is enabled
// at warning level.
func (logger Logger) IsWarningEnabled() bool {
	return logger.IsLevelEnabled(WARNING)
}

// IsInfoEnabled returns whether debugging is enabled
// at info level.
func (logger Logger) IsInfoEnabled() bool {
	return logger.IsLevelEnabled(INFO)
}

// IsDebugEnabled returns whether debugging is enabled
// at debug level.
func (logger Logger) IsDebugEnabled() bool {
	return logger.IsLevelEnabled(DEBUG)
}

// IsTraceEnabled returns whether debugging is enabled
// at trace level.
func (logger Logger) IsTraceEnabled() bool {
	return logger.IsLevelEnabled(TRACE)
}
<|endoftext|>