<commit_before>package main

import (
	_ "time"
	"crypto/rand"
	// "encoding/binary"
	"encoding/json"
	"fmt"
	"github.com/gorilla/sessions"
	"io"
	"net/http"
	"database/sql"
	_ "github.com/go-sql-driver/mysql"
	"runtime"
	"errors"
	"html/template"
)

var templates = template.Must(template.ParseFiles("index.html"))

const MESSAGE_QUEUE_SIZE = 10

const STATUS_FAILURE = "{\"status\":\"failure\"}"

var authKey = []byte("somesecretauth")
var store sessions.Store

var pool *Pool
var clients map[int64]*Client

var db *sql.DB

type Pool struct {
	in  chan *Client
	out chan *Room
}

type Client struct {
	id      int64
	in      chan string
	out     chan string
	retChan chan *Room
}

type Room struct {
	id      []byte
	client1 *Client
	client2 *Client
}

func (p *Pool) Pair() {
	for {
		c1, c2 := <-p.in, <-p.in

		fmt.Println("match found for ", c1.id, " and ", c2.id)

		b := make([]byte, 32)
		n, err := io.ReadFull(rand.Reader, b)
		if err != nil || n != 32 {
			return
		}
		// crId, _ := binary.Varint(b)

		room := &Room{b, c1, c2}

		fmt.Println("ChatroomID: ", b)

		c1.in, c2.in = c2.out, c1.out

		c1.retChan <- room
		c2.retChan <- room
	}
}

func newPool() *Pool {
	pool := &Pool{
		in:  make(chan *Client),
		out: make(chan *Room),
	}

	go pool.Pair()

	return pool
}

func UIDFromSession(w http.ResponseWriter, r *http.Request) (int64, error) {
	session, _ := store.Get(r, "session")
	userid := session.Values["userid"]

	if userid == nil {
		return 0, errors.New("no cookie set")
	}
	return userid.(int64), nil
}

func main() {
	runtime.GOMAXPROCS(runtime.NumCPU())

	db, _ = sql.Open("mysql", "root:pass@/suitup")
	defer db.Close()

	store = sessions.NewCookieStore(authKey)

	pool = newPool()
	clients = make(map[int64]*Client)

	http.HandleFunc("/", mainHandle)

	http.HandleFunc("/login", login)

	http.HandleFunc("/message/check", checkMessage)
	http.HandleFunc("/message/send", sendMessage)

	http.HandleFunc("/question/new", newQuestion)

	http.HandleFunc("/chatroom/join", joinChatRoom)
	http.HandleFunc("/chatroom/leave", leaveChatRoom)

	http.Handle("/assets/", http.StripPrefix("/assets/", http.FileServer(http.Dir("/home/suitup/hackmit/assets/"))))
	http.ListenAndServe(":8080", nil)
}

type IdQuery struct {
    Id            int64      `json:"id"`

}

func mainHandle(w http.ResponseWriter, r *http.Request) {
	templates.ExecuteTemplate(w, "index.html", nil)
}

func joinChatRoom(w http.ResponseWriter, r *http.Request) {
	uid, err := UIDFromSession(w, r)
	handleError(err)

	retChan := make(chan *Room)
	client := &Client{
		id:      uid,
		in:      nil,
		out:     make(chan string, MESSAGE_QUEUE_SIZE),
		retChan: retChan,
	}
	clients[uid] = client
	pool.in <- client

	chatroom := <- retChan

	fmt.Println("joinChatRoom-chatroom.id: ", chatroom.id)

	fmt.Fprint(w, "{\"status\":\"success\",\"crid\":\"", asciify(chatroom.id), "\"}")
}

func asciify(ba []byte) string {
	for i, b := range ba {
		ba[i] = (b % 26) + 97
	}
	return string(ba)
}

func leaveChatRoom(w http.ResponseWriter, r *http.Request) {
	uid, _ := UIDFromSession(w, r)
	delete(clients, uid)
	fmt.Fprint(w, "{\"status\":\"success\"}")
}

func sendMessage(w http.ResponseWriter, r *http.Request) {
	uid, err := UIDFromSession(w, r)
	handleError(err)

	message := r.FormValue("s")

	// message := r.PostFormValue("message")

	client := clients[uid]

	if client != nil {
		client.out <- message
		fmt.Fprint(w, "{\"status\":\"success\"}")
	} else {
		fmt.Fprint(w, STATUS_FAILURE)
	}
}

func checkMessage(w http.ResponseWriter, r *http.Request) {
	uid, err := UIDFromSession(w, r)
	handleError(err)

	client := clients[uid]

	if client != nil {
		select {
		case message, ok := <- clients[uid].in:
			// fmt.Println("message pulled from channel")
			if ok {
				fmt.Fprint(w, message)
			} else {
				fmt.Fprint(w, "")
			}
		default:
			fmt.Fprint(w, "")
		}

	} else {
		fmt.Fprint(w, "")
	}
}

type Question struct {
	id 	int64
	title string
	body string
	difficulty int
}

func newQuestion (w http.ResponseWriter, r *http.Request) {
	row := db.QueryRow("SELECT * FROM questions ORDER BY RAND()")
	q := new(Question)
	err := row.Scan(&q.id, &q.title, &q.body, &q.difficulty)

	if err != nil {
		fmt.Println(err)
		fmt.Fprint(w, STATUS_FAILURE)
	}

	b, err := json.Marshal(q)
	if err != nil {
		fmt.Println(err)
		fmt.Fprint(w, STATUS_FAILURE)
	}

	fmt.Fprint(w, string(b))
}

func login(w http.ResponseWriter, r *http.Request) {
	inputToken := r.FormValue("access_token")
	if len(inputToken) != 0 {
		uid := GetMe(inputToken)

		// row := db.QueryRow("SELECT id FROM users")
		row := db.QueryRow("SELECT id FROM users WHERE facebook_id=?", string(uid))
		iq := new(IdQuery)
		err := row.Scan(&iq.Id)

		if err != nil {
			_, err = db.Exec("INSERT INTO users (facebook_id, username, email, level, points) VALUES (?, ?, ?, 0, 0)", uid, "", "")
			if err != nil {
				fmt.Fprint(w, STATUS_FAILURE)
				return
			} else {
				row = db.QueryRow("SELECT id FROM users WHERE facebook_id=?", string(uid))
				err = row.Scan(&iq.Id)
				if err != nil {
					fmt.Fprint(w, STATUS_FAILURE)
					return
				}
			}

		}

		session, _ := store.Get(r, "session")
		session.Values["userid"] = iq.Id
		session.Save(r, w)

		fmt.Fprint(w, "{\"status\":\"success\"}")
	}
}

func readHttpBody(response *http.Response) string {
	bodyBuffer := make([]byte, 1000)
	var str string

	count, err := response.Body.Read(bodyBuffer)

	for ; count > 0; count, err = response.Body.Read(bodyBuffer) {

		if err != nil {

		}

		str += string(bodyBuffer[:count])
	}

	return str

}

func getUncachedResponse(uri string) (*http.Response, error) {
	request, err := http.NewRequest("GET", uri, nil)

	if err == nil {
		request.Header.Add("Cache-Control", "no-cache")

		client := new(http.Client)

		return client.Do(request)
	}

	if (err != nil) {
	}
	return nil, err

}

func GetMe(token string) string {
	response, err := getUncachedResponse("https://graph.facebook.com/me?access_token="+token)

	if err == nil {

		var jsonBlob interface{}

		responseBody := readHttpBody(response)

		if responseBody != "" {
			err = json.Unmarshal([]byte(responseBody), &jsonBlob)

			if err == nil {
				jsonObj := jsonBlob.(map[string]interface{})
				return jsonObj["id"].(string)
			}
		}
		return err.Error()
	}

	return err.Error()
}

func handleError(err error) {
	if err != nil {
		fmt.Println(err)
	}
}
<commit_msg>Marshal question<commit_after>package main

import (
	_ "time"
	"crypto/rand"
	// "encoding/binary"
	"encoding/json"
	"fmt"
	"github.com/gorilla/sessions"
	"io"
	"net/http"
	"database/sql"
	_ "github.com/go-sql-driver/mysql"
	"runtime"
	"errors"
	"html/template"
)

var templates = template.Must(template.ParseFiles("index.html"))

const MESSAGE_QUEUE_SIZE = 10

const STATUS_FAILURE = "{\"status\":\"failure\"}"

var authKey = []byte("somesecretauth")
var store sessions.Store

var pool *Pool
var clients map[int64]*Client

var db *sql.DB

type Pool struct {
	in  chan *Client
	out chan *Room
}

type Client struct {
	id      int64
	in      chan string
	out     chan string
	retChan chan *Room
}

type Room struct {
	id      []byte
	client1 *Client
	client2 *Client
}

func (p *Pool) Pair() {
	for {
		c1, c2 := <-p.in, <-p.in

		fmt.Println("match found for ", c1.id, " and ", c2.id)

		b := make([]byte, 32)
		n, err := io.ReadFull(rand.Reader, b)
		if err != nil || n != 32 {
			return
		}
		// crId, _ := binary.Varint(b)

		room := &Room{b, c1, c2}

		fmt.Println("ChatroomID: ", b)

		c1.in, c2.in = c2.out, c1.out

		c1.retChan <- room
		c2.retChan <- room
	}
}

func newPool() *Pool {
	pool := &Pool{
		in:  make(chan *Client),
		out: make(chan *Room),
	}

	go pool.Pair()

	return pool
}

func UIDFromSession(w http.ResponseWriter, r *http.Request) (int64, error) {
	session, _ := store.Get(r, "session")
	userid := session.Values["userid"]

	if userid == nil {
		return 0, errors.New("no cookie set")
	}
	return userid.(int64), nil
}

func main() {
	runtime.GOMAXPROCS(runtime.NumCPU())

	db, _ = sql.Open("mysql", "root:pass@/suitup")
	defer db.Close()

	store = sessions.NewCookieStore(authKey)

	pool = newPool()
	clients = make(map[int64]*Client)

	http.HandleFunc("/", mainHandle)

	http.HandleFunc("/login", login)

	http.HandleFunc("/message/check", checkMessage)
	http.HandleFunc("/message/send", sendMessage)

	http.HandleFunc("/question/new", newQuestion)

	http.HandleFunc("/chatroom/join", joinChatRoom)
	http.HandleFunc("/chatroom/leave", leaveChatRoom)

	http.Handle("/assets/", http.StripPrefix("/assets/", http.FileServer(http.Dir("/home/suitup/hackmit/assets/"))))
	http.ListenAndServe(":8080", nil)
}

type IdQuery struct {
    Id            int64      `json:"id"`

}

func mainHandle(w http.ResponseWriter, r *http.Request) {
	templates.ExecuteTemplate(w, "index.html", nil)
}

func joinChatRoom(w http.ResponseWriter, r *http.Request) {
	uid, err := UIDFromSession(w, r)
	handleError(err)

	retChan := make(chan *Room)
	client := &Client{
		id:      uid,
		in:      nil,
		out:     make(chan string, MESSAGE_QUEUE_SIZE),
		retChan: retChan,
	}
	clients[uid] = client
	pool.in <- client

	chatroom := <- retChan

	fmt.Println("joinChatRoom-chatroom.id: ", chatroom.id)

	fmt.Fprint(w, "{\"status\":\"success\",\"crid\":\"", asciify(chatroom.id), "\"}")
}

func asciify(ba []byte) string {
	for i, b := range ba {
		ba[i] = (b % 26) + 97
	}
	return string(ba)
}

func leaveChatRoom(w http.ResponseWriter, r *http.Request) {
	uid, _ := UIDFromSession(w, r)
	delete(clients, uid)
	fmt.Fprint(w, "{\"status\":\"success\"}")
}

func sendMessage(w http.ResponseWriter, r *http.Request) {
	uid, err := UIDFromSession(w, r)
	handleError(err)

	message := r.FormValue("s")

	// message := r.PostFormValue("message")

	client := clients[uid]

	if client != nil {
		client.out <- message
		fmt.Fprint(w, "{\"status\":\"success\"}")
	} else {
		fmt.Fprint(w, STATUS_FAILURE)
	}
}

func checkMessage(w http.ResponseWriter, r *http.Request) {
	uid, err := UIDFromSession(w, r)
	handleError(err)

	client := clients[uid]

	if client != nil {
		select {
		case message, ok := <- clients[uid].in:
			// fmt.Println("message pulled from channel")
			if ok {
				fmt.Fprint(w, message)
			} else {
				fmt.Fprint(w, "")
			}
		default:
			fmt.Fprint(w, "")
		}

	} else {
		fmt.Fprint(w, "")
	}
}

type Question struct {
	Id 	int64
	Title string
	Body string
	Difficulty int
}

func newQuestion(w http.ResponseWriter, r *http.Request) {
	row := db.QueryRow("SELECT * FROM questions ORDER BY RAND()")
	q := new(Question)
	err := row.Scan(&q.Id, &q.Title, &q.Body, &q.Difficulty)

	if err != nil {
		fmt.Println(err)
		fmt.Fprint(w, STATUS_FAILURE)
	}

	b, err := json.Marshal(q)
	if err != nil {
		fmt.Println(err)
		fmt.Fprint(w, STATUS_FAILURE)
	}

	fmt.Fprint(w, string(b))
}

func login(w http.ResponseWriter, r *http.Request) {
	inputToken := r.FormValue("access_token")
	if len(inputToken) != 0 {
		uid := GetMe(inputToken)

		// row := db.QueryRow("SELECT id FROM users")
		row := db.QueryRow("SELECT id FROM users WHERE facebook_id=?", string(uid))
		iq := new(IdQuery)
		err := row.Scan(&iq.Id)

		if err != nil {
			_, err = db.Exec("INSERT INTO users (facebook_id, username, email, level, points) VALUES (?, ?, ?, 0, 0)", uid, "", "")
			if err != nil {
				fmt.Fprint(w, STATUS_FAILURE)
				return
			} else {
				row = db.QueryRow("SELECT id FROM users WHERE facebook_id=?", string(uid))
				err = row.Scan(&iq.Id)
				if err != nil {
					fmt.Fprint(w, STATUS_FAILURE)
					return
				}
			}

		}

		session, _ := store.Get(r, "session")
		session.Values["userid"] = iq.Id
		session.Save(r, w)

		fmt.Fprint(w, "{\"status\":\"success\"}")
	}
}

func readHttpBody(response *http.Response) string {
	bodyBuffer := make([]byte, 1000)
	var str string

	count, err := response.Body.Read(bodyBuffer)

	for ; count > 0; count, err = response.Body.Read(bodyBuffer) {

		if err != nil {

		}

		str += string(bodyBuffer[:count])
	}

	return str

}

func getUncachedResponse(uri string) (*http.Response, error) {
	request, err := http.NewRequest("GET", uri, nil)

	if err == nil {
		request.Header.Add("Cache-Control", "no-cache")

		client := new(http.Client)

		return client.Do(request)
	}

	if (err != nil) {
	}
	return nil, err

}

func GetMe(token string) string {
	response, err := getUncachedResponse("https://graph.facebook.com/me?access_token="+token)

	if err == nil {

		var jsonBlob interface{}

		responseBody := readHttpBody(response)

		if responseBody != "" {
			err = json.Unmarshal([]byte(responseBody), &jsonBlob)

			if err == nil {
				jsonObj := jsonBlob.(map[string]interface{})
				return jsonObj["id"].(string)
			}
		}
		return err.Error()
	}

	return err.Error()
}

func handleError(err error) {
	if err != nil {
		fmt.Println(err)
	}
}
<|endoftext|>


<commit_before>// Package stun implements Session Traversal Utilities for NAT (STUN) RFC 5389.
//
// The stun package is intended to use by package that implements extension
// to STUN (e.g. TURN) or client/server applications.
//
// Most methods are designed to be zero allocations. If it is not enough,
// low-level methods are available. On other hand, there are helpers that
// reduce code repeat.
//
// See examples for Message for basic usage, or https://github.com/ernado/turn
// package for example of stun extension implementation.
package stun

import (
	"encoding/binary"
	"io"
)

// bin is shorthand to binary.BigEndian.
var bin = binary.BigEndian

func readFullOrPanic(r io.Reader, v []byte) int {
	n, err := io.ReadFull(r, v)
	if err != nil {
		panic(err)
	}
	return n
}

func writeOrPanic(w io.Writer, v []byte) int {
	n, err := w.Write(v)
	if err != nil {
		panic(err)
	}
	return n
}

// IANA assigned ports for "stun" protocol.
const (
	DefaultPort    = 3478
	DefaultTLSPort = 5349
)

type transactionIDSetter struct{}

func (transactionIDSetter) AddTo(m *Message) error {
	return m.NewTransactionID()
}

// TransactionID is Setter for m.TransactionID.
var TransactionID Setter = transactionIDSetter{}
<commit_msg>stun: update turn link in doc<commit_after>// Package stun implements Session Traversal Utilities for NAT (STUN) RFC 5389.
//
// The stun package is intended to use by package that implements extension
// to STUN (e.g. TURN) or client/server applications.
//
// Most methods are designed to be zero allocations. If it is not enough,
// low-level methods are available. On other hand, there are helpers that
// reduce code repeat.
//
// See examples for Message for basic usage, or https://github.com/gortc/turn
// package for example of stun extension implementation.
package stun

import (
	"encoding/binary"
	"io"
)

// bin is shorthand to binary.BigEndian.
var bin = binary.BigEndian

func readFullOrPanic(r io.Reader, v []byte) int {
	n, err := io.ReadFull(r, v)
	if err != nil {
		panic(err)
	}
	return n
}

func writeOrPanic(w io.Writer, v []byte) int {
	n, err := w.Write(v)
	if err != nil {
		panic(err)
	}
	return n
}

// IANA assigned ports for "stun" protocol.
const (
	DefaultPort    = 3478
	DefaultTLSPort = 5349
)

type transactionIDSetter struct{}

func (transactionIDSetter) AddTo(m *Message) error {
	return m.NewTransactionID()
}

// TransactionID is Setter for m.TransactionID.
var TransactionID Setter = transactionIDSetter{}
<|endoftext|>


<commit_before>package tailer

import (
	"fmt"
	"path/filepath"

	"github.com/ActiveState/tail"
	"github.com/golang/glog"
)

// TailFile tail -f the file and emit with publisher
func TailFile(pub Publisher, filename string, done chan bool) {
	defer func() { done <- true }()
	if RegexNotWatch.MatchString(filename) {
		glog.Warningf("Skip %s", filename)
		return
	}
	glog.Warningf("Tail %s", filename)
	t, err := tail.TailFile(filename, tail.Config{Follow: true})
	if err != nil {
		glog.Errorf("error: %v", err)
		return
	}
	base := filepath.Base(filename)
	for line := range t.Lines {
		err = pub.Publish([]byte(fmt.Sprintf("%s: %s", base, line.Text)))
		if err != nil {
			glog.Errorf("error: %v", err)
		}
	}
	err = t.Wait()
	if err != nil {
		glog.Errorf("error: %v", err)
	}
}
<commit_msg>fix notmatch in tail.go<commit_after>package tailer

import (
	"fmt"
	"path/filepath"

	"github.com/ActiveState/tail"
	"github.com/golang/glog"
)

// TailFile tail -f the file and emit with publisher
func TailFile(pub Publisher, filename string, done chan bool) {
	defer func() { done <- true }()
	base := filepath.Base(filename)
	if RegexNotWatch.MatchString(base) {
		glog.Warningf("Skip %s", filename)
		return
	}
	glog.Warningf("Tail %s", filename)
	t, err := tail.TailFile(filename, tail.Config{Follow: true})
	if err != nil {
		glog.Errorf("error: %v", err)
		return
	}
	for line := range t.Lines {
		err = pub.Publish([]byte(fmt.Sprintf("%s: %s", base, line.Text)))
		if err != nil {
			glog.Errorf("error: %v", err)
		}
	}
	err = t.Wait()
	if err != nil {
		glog.Errorf("error: %v", err)
	}
}
<|endoftext|>


<commit_before>/* Copyright 2017 Lukas Rist

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License. */

package tlsh

import (
	"bufio"
	"bytes"
	"encoding/hex"
	"io"
	"math"
	"os"
)

const (
	log1_5       = 0.4054651
	log1_3       = 0.26236426
	log1_1       = 0.095310180
	codeSize     = 32
	windowLength = 5
	effBuckets   = 128
	numBuckets   = 256
)

// Tlsh holds hash components
type Tlsh struct {
	checksum byte
	lValue   byte
	q1Ratio  byte
	q2Ratio  byte
	qRatio   byte
	code     [codeSize]byte
}

// New represents type factory for Tlsh
func New(checksum, lValue, q1Ratio, q2Ratio, qRatio byte, code [codeSize]byte) *Tlsh {
	return &Tlsh{
		checksum: checksum,
		lValue:   lValue,
		q1Ratio:  q1Ratio,
		q2Ratio:  q2Ratio,
		qRatio:   qRatio,
		code:     code,
	}
}

// Binary returns the binary representation of the hash
func (t *Tlsh) Binary() []byte {
	return append([]byte{swapByte(t.checksum), swapByte(t.lValue), t.qRatio}, t.code[:]...)
}

// String returns the string representation of the hash`
func (t *Tlsh) String() string {
	return hex.EncodeToString(t.Binary())
}

func quartilePoints(buckets [numBuckets]uint) (q1, q2, q3 uint) {
	var spl, spr uint
	p1 := uint(effBuckets/4 - 1)
	p2 := uint(effBuckets/2 - 1)
	p3 := uint(effBuckets - effBuckets/4 - 1)
	end := uint(effBuckets - 1)

	bucketCopy := make([]uint, effBuckets)
	copy(bucketCopy, buckets[:effBuckets])

	shortCutLeft := make([]uint, effBuckets)
	shortCutRight := make([]uint, effBuckets)

	for l, r := uint(0), end; ; {
		ret := partition(bucketCopy, l, r)
		if ret > p2 {
			r = ret - 1
			shortCutRight[spr] = ret
			spr++
		} else if ret < p2 {
			l = ret + 1
			shortCutLeft[spl] = ret
			spl++
		} else {
			q2 = bucketCopy[p2]
			break
		}
	}

	shortCutLeft[spl] = p2 - 1
	shortCutRight[spr] = p2 + 1

	for i, l := uint(0), uint(0); i <= spl; i++ {
		r := shortCutLeft[i]
		if r > p1 {
			for {
				ret := partition(bucketCopy, l, r)
				if ret > p1 {
					r = ret - 1
				} else if ret < p1 {
					l = ret + 1
				} else {
					q1 = bucketCopy[p1]
					break
				}
			}
			break
		} else if r < p1 {
			l = r
		} else {
			q1 = bucketCopy[p1]
			break
		}
	}

	for i, r := uint(0), end; i <= spr; i++ {
		l := shortCutRight[i]
		if l < p3 {
			for {
				ret := partition(bucketCopy, l, r)
				if ret > p3 {
					r = ret - 1
				} else if ret < p3 {
					l = ret + 1
				} else {
					q3 = bucketCopy[p3]
					break
				}
			}
			break
		} else if l > p3 {
			r = l
		} else {
			q3 = bucketCopy[p3]
			break
		}
	}

	return q1, q2, q3
}

func partition(buf []uint, left, right uint) uint {
	if left == right {
		return left
	}

	if left+1 == right {
		if buf[left] > buf[right] {
			buf[right], buf[left] = buf[left], buf[right]
		}
		return left
	}

	ret := left
	pivot := (left + right) >> 1
	val := buf[pivot]

	buf[pivot] = buf[right]
	buf[right] = val

	for i := left; i < right; i++ {
		if buf[i] < val {
			buf[i], buf[ret] = buf[ret], buf[i]
			ret++
		}
	}

	buf[right] = buf[ret]
	buf[ret] = val

	return ret
}

func lValue(length int) byte {
	var l byte

	if length <= 656 {
		l = byte(math.Floor(math.Log(float64(length)) / log1_5))
	} else if length <= 3199 {
		l = byte(math.Floor(math.Log(float64(length))/log1_3 - 8.72777))
	} else {
		l = byte(math.Floor(math.Log(float64(length))/log1_1 - 62.5472))
	}

	return l % 255
}

func swapByte(in byte) byte {
	var out byte

	out = ((in & 0xF0) >> 4) & 0x0F
	out |= ((in & 0x0F) << 4) & 0xF0

	return out
}

func bucketsBinaryRepresentation(buckets [numBuckets]uint, q1, q2, q3 uint) [codeSize]byte {
	var biHash [codeSize]byte

	for i := 0; i < codeSize; i++ {
		var h byte
		for j := 0; j < 4; j++ {
			k := buckets[4*i+j]
			if q3 < k {
				h += 3 << (byte(j) * 2)
			} else if q2 < k {
				h += 2 << (byte(j) * 2)
			} else if q1 < k {
				h += 1 << (byte(j) * 2)
			}
		}
		// Prepend the new h to the hash
		biHash[(codeSize-1)-i] = h
	}
	return biHash
}

func reverse(s [5]byte) [5]byte {
	for i, j := 0, len(s)-1; i < j; i, j = i+1, j-1 {
		s[i], s[j] = s[j], s[i]
	}
	return s
}

func fillBuckets(r FuzzyReader) ([numBuckets]uint, byte, int, error) {
	buckets := [numBuckets]uint{}
	chunkSlice := make([]byte, windowLength)
	chunk := [windowLength]byte{}
	salt := [6]byte{2, 3, 5, 7, 11, 13}
	fileSize := 0
	checksum := byte(0)

	n, err := r.Read(chunkSlice)
	if err != nil {
		return [numBuckets]uint{}, 0, 0, err
	}
	copy(chunk[:], chunkSlice[0:5])
	chunk = reverse(chunk)
	fileSize += n

	chunk3 := &[3]byte{}

	for {
		chunk3[0] = chunk[0]
		chunk3[1] = chunk[1]
		chunk3[2] = checksum
		checksum = pearsonHash(0, chunk3)

		chunk3[2] = chunk[2]
		buckets[pearsonHash(salt[0], chunk3)]++

		chunk3[2] = chunk[3]
		buckets[pearsonHash(salt[1], chunk3)]++

		chunk3[1] = chunk[2]
		buckets[pearsonHash(salt[2], chunk3)]++

		chunk3[2] = chunk[4]
		buckets[pearsonHash(salt[3], chunk3)]++

		chunk3[1] = chunk[1]
		buckets[pearsonHash(salt[4], chunk3)]++

		chunk3[1] = chunk[3]
		buckets[pearsonHash(salt[5], chunk3)]++

		copy(chunk[1:], chunk[0:4])
		chunk[0], err = r.ReadByte()
		if err != nil {
			if err != io.EOF {
				return [numBuckets]uint{}, 0, 0, err
			}
			break
		}
		fileSize++
	}
	return buckets, checksum, fileSize, nil
}

// hashCalculate calculate TLSH
func hashCalculate(r FuzzyReader) (*Tlsh, error) {
	buckets, checksum, fileSize, err := fillBuckets(r)
	if err != nil {
		return &Tlsh{}, err
	}

	q1, q2, q3 := quartilePoints(buckets)
	q1Ratio := byte(float32(q1)*100/float32(q3)) % 16
	q2Ratio := byte(float32(q2)*100/float32(q3)) % 16
	qRatio := ((q1Ratio & 0xF) << 4) | (q2Ratio & 0xF)

	biHash := bucketsBinaryRepresentation(buckets, q1, q2, q3)

	return New(checksum, lValue(fileSize), q1Ratio, q2Ratio, qRatio, biHash), nil
}

// FuzzyReader interface
type FuzzyReader interface {
	Read([]byte) (int, error)
	ReadByte() (byte, error)
}

//HashReader calculates the TLSH for the input reader
func HashReader(r FuzzyReader) (tlsh *Tlsh, err error) {
	tlsh, err = hashCalculate(r)
	if err != nil {
		return &Tlsh{}, err
	}
	return tlsh, err
}

//HashBytes calculates the TLSH for the input byte slice
func HashBytes(blob []byte) (tlsh *Tlsh, err error) {
	r := bytes.NewReader(blob)
	return HashReader(r)
}

//HashFilename calculates the TLSH for the input file
func HashFilename(filename string) (tlsh *Tlsh, err error) {
	f, err := os.Open(filename)
	defer f.Close()
	if err != nil {
		return &Tlsh{}, err
	}

	r := bufio.NewReader(f)
	return HashReader(r)
}

// Diff current hash with other hash
func (t *Tlsh) Diff(t2 *Tlsh) int {
	return diffTotal(t, t2, true)
}

// DiffFilenames calculate distance between two files
func DiffFilenames(filenameA, filenameB string) (int, error) {
	f, err := os.Open(filenameA)
	defer f.Close()
	if err != nil {
		return -1, err
	}
	r := bufio.NewReader(f)
	tlshA, err := hashCalculate(r)
	if err != nil {
		return -1, err
	}

	f, err = os.Open(filenameB)
	defer f.Close()
	if err != nil {
		return -1, err
	}
	r = bufio.NewReader(f)
	tlshB, err := hashCalculate(r)
	if err != nil {
		return -1, err
	}

	return tlshA.Diff(tlshB), nil
}
<commit_msg>Make FuzzyReader a composit, closing #18<commit_after>/* Copyright 2017 Lukas Rist

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License. */

package tlsh

import (
	"bufio"
	"bytes"
	"encoding/hex"
	"io"
	"math"
	"os"
)

const (
	log1_5       = 0.4054651
	log1_3       = 0.26236426
	log1_1       = 0.095310180
	codeSize     = 32
	windowLength = 5
	effBuckets   = 128
	numBuckets   = 256
)

// Tlsh holds hash components
type Tlsh struct {
	checksum byte
	lValue   byte
	q1Ratio  byte
	q2Ratio  byte
	qRatio   byte
	code     [codeSize]byte
}

// New represents type factory for Tlsh
func New(checksum, lValue, q1Ratio, q2Ratio, qRatio byte, code [codeSize]byte) *Tlsh {
	return &Tlsh{
		checksum: checksum,
		lValue:   lValue,
		q1Ratio:  q1Ratio,
		q2Ratio:  q2Ratio,
		qRatio:   qRatio,
		code:     code,
	}
}

// Binary returns the binary representation of the hash
func (t *Tlsh) Binary() []byte {
	return append([]byte{swapByte(t.checksum), swapByte(t.lValue), t.qRatio}, t.code[:]...)
}

// String returns the string representation of the hash`
func (t *Tlsh) String() string {
	return hex.EncodeToString(t.Binary())
}

func quartilePoints(buckets [numBuckets]uint) (q1, q2, q3 uint) {
	var spl, spr uint
	p1 := uint(effBuckets/4 - 1)
	p2 := uint(effBuckets/2 - 1)
	p3 := uint(effBuckets - effBuckets/4 - 1)
	end := uint(effBuckets - 1)

	bucketCopy := make([]uint, effBuckets)
	copy(bucketCopy, buckets[:effBuckets])

	shortCutLeft := make([]uint, effBuckets)
	shortCutRight := make([]uint, effBuckets)

	for l, r := uint(0), end; ; {
		ret := partition(bucketCopy, l, r)
		if ret > p2 {
			r = ret - 1
			shortCutRight[spr] = ret
			spr++
		} else if ret < p2 {
			l = ret + 1
			shortCutLeft[spl] = ret
			spl++
		} else {
			q2 = bucketCopy[p2]
			break
		}
	}

	shortCutLeft[spl] = p2 - 1
	shortCutRight[spr] = p2 + 1

	for i, l := uint(0), uint(0); i <= spl; i++ {
		r := shortCutLeft[i]
		if r > p1 {
			for {
				ret := partition(bucketCopy, l, r)
				if ret > p1 {
					r = ret - 1
				} else if ret < p1 {
					l = ret + 1
				} else {
					q1 = bucketCopy[p1]
					break
				}
			}
			break
		} else if r < p1 {
			l = r
		} else {
			q1 = bucketCopy[p1]
			break
		}
	}

	for i, r := uint(0), end; i <= spr; i++ {
		l := shortCutRight[i]
		if l < p3 {
			for {
				ret := partition(bucketCopy, l, r)
				if ret > p3 {
					r = ret - 1
				} else if ret < p3 {
					l = ret + 1
				} else {
					q3 = bucketCopy[p3]
					break
				}
			}
			break
		} else if l > p3 {
			r = l
		} else {
			q3 = bucketCopy[p3]
			break
		}
	}

	return q1, q2, q3
}

func partition(buf []uint, left, right uint) uint {
	if left == right {
		return left
	}

	if left+1 == right {
		if buf[left] > buf[right] {
			buf[right], buf[left] = buf[left], buf[right]
		}
		return left
	}

	ret := left
	pivot := (left + right) >> 1
	val := buf[pivot]

	buf[pivot] = buf[right]
	buf[right] = val

	for i := left; i < right; i++ {
		if buf[i] < val {
			buf[i], buf[ret] = buf[ret], buf[i]
			ret++
		}
	}

	buf[right] = buf[ret]
	buf[ret] = val

	return ret
}

func lValue(length int) byte {
	var l byte

	if length <= 656 {
		l = byte(math.Floor(math.Log(float64(length)) / log1_5))
	} else if length <= 3199 {
		l = byte(math.Floor(math.Log(float64(length))/log1_3 - 8.72777))
	} else {
		l = byte(math.Floor(math.Log(float64(length))/log1_1 - 62.5472))
	}

	return l % 255
}

func swapByte(in byte) byte {
	var out byte

	out = ((in & 0xF0) >> 4) & 0x0F
	out |= ((in & 0x0F) << 4) & 0xF0

	return out
}

func bucketsBinaryRepresentation(buckets [numBuckets]uint, q1, q2, q3 uint) [codeSize]byte {
	var biHash [codeSize]byte

	for i := 0; i < codeSize; i++ {
		var h byte
		for j := 0; j < 4; j++ {
			k := buckets[4*i+j]
			if q3 < k {
				h += 3 << (byte(j) * 2)
			} else if q2 < k {
				h += 2 << (byte(j) * 2)
			} else if q1 < k {
				h += 1 << (byte(j) * 2)
			}
		}
		// Prepend the new h to the hash
		biHash[(codeSize-1)-i] = h
	}
	return biHash
}

func reverse(s [5]byte) [5]byte {
	for i, j := 0, len(s)-1; i < j; i, j = i+1, j-1 {
		s[i], s[j] = s[j], s[i]
	}
	return s
}

func fillBuckets(r FuzzyReader) ([numBuckets]uint, byte, int, error) {
	buckets := [numBuckets]uint{}
	chunkSlice := make([]byte, windowLength)
	chunk := [windowLength]byte{}
	salt := [6]byte{2, 3, 5, 7, 11, 13}
	fileSize := 0
	checksum := byte(0)

	n, err := r.Read(chunkSlice)
	if err != nil {
		return [numBuckets]uint{}, 0, 0, err
	}
	copy(chunk[:], chunkSlice[0:5])
	chunk = reverse(chunk)
	fileSize += n

	chunk3 := &[3]byte{}

	for {
		chunk3[0] = chunk[0]
		chunk3[1] = chunk[1]
		chunk3[2] = checksum
		checksum = pearsonHash(0, chunk3)

		chunk3[2] = chunk[2]
		buckets[pearsonHash(salt[0], chunk3)]++

		chunk3[2] = chunk[3]
		buckets[pearsonHash(salt[1], chunk3)]++

		chunk3[1] = chunk[2]
		buckets[pearsonHash(salt[2], chunk3)]++

		chunk3[2] = chunk[4]
		buckets[pearsonHash(salt[3], chunk3)]++

		chunk3[1] = chunk[1]
		buckets[pearsonHash(salt[4], chunk3)]++

		chunk3[1] = chunk[3]
		buckets[pearsonHash(salt[5], chunk3)]++

		copy(chunk[1:], chunk[0:4])
		chunk[0], err = r.ReadByte()
		if err != nil {
			if err != io.EOF {
				return [numBuckets]uint{}, 0, 0, err
			}
			break
		}
		fileSize++
	}
	return buckets, checksum, fileSize, nil
}

// hashCalculate calculate TLSH
func hashCalculate(r FuzzyReader) (*Tlsh, error) {
	buckets, checksum, fileSize, err := fillBuckets(r)
	if err != nil {
		return &Tlsh{}, err
	}

	q1, q2, q3 := quartilePoints(buckets)
	q1Ratio := byte(float32(q1)*100/float32(q3)) % 16
	q2Ratio := byte(float32(q2)*100/float32(q3)) % 16
	qRatio := ((q1Ratio & 0xF) << 4) | (q2Ratio & 0xF)

	biHash := bucketsBinaryRepresentation(buckets, q1, q2, q3)

	return New(checksum, lValue(fileSize), q1Ratio, q2Ratio, qRatio, biHash), nil
}

// FuzzyReader interface
type FuzzyReader interface {
	io.Reader
	io.ByteReader
}

//HashReader calculates the TLSH for the input reader
func HashReader(r FuzzyReader) (tlsh *Tlsh, err error) {
	tlsh, err = hashCalculate(r)
	if err != nil {
		return &Tlsh{}, err
	}
	return tlsh, err
}

//HashBytes calculates the TLSH for the input byte slice
func HashBytes(blob []byte) (tlsh *Tlsh, err error) {
	r := bytes.NewReader(blob)
	return HashReader(r)
}

//HashFilename calculates the TLSH for the input file
func HashFilename(filename string) (tlsh *Tlsh, err error) {
	f, err := os.Open(filename)
	defer f.Close()
	if err != nil {
		return &Tlsh{}, err
	}

	r := bufio.NewReader(f)
	return HashReader(r)
}

// Diff current hash with other hash
func (t *Tlsh) Diff(t2 *Tlsh) int {
	return diffTotal(t, t2, true)
}

// DiffFilenames calculate distance between two files
func DiffFilenames(filenameA, filenameB string) (int, error) {
	f, err := os.Open(filenameA)
	defer f.Close()
	if err != nil {
		return -1, err
	}
	r := bufio.NewReader(f)
	tlshA, err := hashCalculate(r)
	if err != nil {
		return -1, err
	}

	f, err = os.Open(filenameB)
	defer f.Close()
	if err != nil {
		return -1, err
	}
	r = bufio.NewReader(f)
	tlshB, err := hashCalculate(r)
	if err != nil {
		return -1, err
	}

	return tlshA.Diff(tlshB), nil
}
<|endoftext|>


<commit_before>package main

import (
	//"os"
	"fmt"
	"github.com/urfave/cli"
)

var toolCommands = []cli.Command {
	{
		Name: "beep_off",
		Usage: "Beep off for ACS Reader",
		Action: beepOff,
		Flags: commonFlags,
	},
	{
		Name: "pin_status",
		Usage: "PINステータス",
		Action: pinStatus,
		Before: checkCard,
		Flags: commonFlags,
	},
	{
		Name: "find_ap",
		Usage: "search AP",
		Action: findAP,
		Flags: commonFlags,
	},
}

func beepOff(c *cli.Context) error {
	reader := NewReader(c)
	defer reader.Finalize()
	reader.WaitForCard()
	reader.Tx("FF 00 52 00 00")
	return nil
}

func pinStatus(c *cli.Context) error {
	reader := NewReader(c)
	defer reader.Finalize()
	reader.WaitForCard()

	aid := "D3 92 f0 00 26 01 00 00 00 01"
	apdu := "00 A4 04 0C" + " 0A " + aid
	sw1, sw2, _:= reader.Tx(apdu)

	reader.Tx("00 a4 02 0C 02 00 18") // IEF for AUTH
	sw1, sw2, _ = reader.Tx("00 20 00 80")
	if (sw1 == 0x63) {
		fmt.Printf("認証用PIN: のこり%d回\n", sw2 - 0xC0)
	}
	reader.Tx("00 a4 02 0C 02 00 1B") // IEF for SIGN
	sw1, sw2, _ = reader.Tx("00 20 00 80")
	if (sw1 == 0x63) {
		fmt.Printf("署名用PIN: のこり%d回\n", sw2 - 0xC0)
	}
	return nil
}

func findAP(c *cli.Context) error {
	var prefix = []byte{}

	reader := NewReader(c)
	defer reader.Finalize()
	reader.WaitForCard()
	ret := findDF(reader, prefix)
	for _, ap := range ret {
		fmt.Printf("found ap: % X\n", ap)
	}
	return nil
}

func findDF(reader *Reader, prefix []byte) [][]byte {
	var tmp [][]byte
	i := len(prefix)
	l := i + 1
	buf := append(prefix, 0)
	for n := 0; n<255; n++ {
		buf[i] = byte(n)
		apdu := "00 A4 04 0C " +
			fmt.Sprintf("%02X ", l) +
			fmt.Sprintf("% X", buf)
		sw1, sw2, _ := reader.Tx(apdu)
		if(sw1 == 0x90 && sw2 == 0x00){
			ret := findDF(reader, buf)
			if len(ret) == 0 {
				//fmt.Printf("found ap % X\n", buf)
				dup := make([]byte, len(buf))
				copy(dup, buf)
				tmp = append(tmp, dup)
			}else{
				tmp = append(tmp, ret...)
			}
		}
	}
	return tmp
}
<commit_msg>券面入力補助PIN残り回数を表示<commit_after>package main

import (
	//"os"
	"fmt"
	"github.com/urfave/cli"
)

var toolCommands = []cli.Command {
	{
		Name: "beep_off",
		Usage: "Beep off for ACS Reader",
		Action: beepOff,
		Flags: commonFlags,
	},
	{
		Name: "pin_status",
		Usage: "PINステータス",
		Action: pinStatus,
		Before: checkCard,
		Flags: commonFlags,
	},
	{
		Name: "find_ap",
		Usage: "search AP",
		Action: findAP,
		Flags: commonFlags,
	},
}

func beepOff(c *cli.Context) error {
	reader := NewReader(c)
	defer reader.Finalize()
	reader.WaitForCard()
	reader.Tx("FF 00 52 00 00")
	return nil
}

func pinStatus(c *cli.Context) error {
	reader := NewReader(c)
	defer reader.Finalize()
	reader.WaitForCard()

	aid := "D3 92 f0 00 26 01 00 00 00 01"
	apdu := "00 A4 04 0C" + " 0A " + aid
	sw1, sw2, _:= reader.Tx(apdu)

	reader.Tx("00 a4 02 0C 02 00 18") // IEF for AUTH
	sw1, sw2, _ = reader.Tx("00 20 00 80")
	if (sw1 == 0x63) {
		fmt.Printf("認証用PIN: のこり%d回\n", sw2 - 0xC0)
	}
	reader.Tx("00 a4 02 0C 02 00 1B") // IEF for SIGN
	sw1, sw2, _ = reader.Tx("00 20 00 80")
	if (sw1 == 0x63) {
		fmt.Printf("署名用PIN: のこり%d回\n", sw2 - 0xC0)
	}

	aid = "D3 92 10 00 31 00 01 01 04 08"
	apdu = "00 A4 04 0C" + " 0A " + aid
	reader.Tx(apdu)
	reader.Tx("00 a4 02 0C 02 00 11") // IEF for MYNUM
	reader.Tx("00 20 00 80")
	sw1, sw2, _ = reader.Tx("00 20 00 80")
	if (sw1 == 0x63) {
		fmt.Printf("券面入力補助PIN: のこり%d回\n", sw2 - 0xC0)
	}

	return nil
}

func findAP(c *cli.Context) error {
	var prefix = []byte{}

	reader := NewReader(c)
	defer reader.Finalize()
	reader.WaitForCard()
	ret := findDF(reader, prefix)
	for _, ap := range ret {
		fmt.Printf("found ap: % X\n", ap)
	}
	return nil
}

func findDF(reader *Reader, prefix []byte) [][]byte {
	var tmp [][]byte
	i := len(prefix)
	l := i + 1
	buf := append(prefix, 0)
	for n := 0; n<255; n++ {
		buf[i] = byte(n)
		apdu := "00 A4 04 0C " +
			fmt.Sprintf("%02X ", l) +
			fmt.Sprintf("% X", buf)
		sw1, sw2, _ := reader.Tx(apdu)
		if(sw1 == 0x90 && sw2 == 0x00){
			ret := findDF(reader, buf)
			if len(ret) == 0 {
				//fmt.Printf("found ap % X\n", buf)
				dup := make([]byte, len(buf))
				copy(dup, buf)
				tmp = append(tmp, dup)
			}else{
				tmp = append(tmp, ret...)
			}
		}
	}
	return tmp
}
<|endoftext|>


<commit_before>// Implementation of an R-Way Trie data structure.
//
// A Trie has a root Node which is the base of the tree.
// Each subsequent Node has a letter and children, which are
// nodes that have letter values associated with them.
package trie

import (
	"sort"
)

type Node struct {
	val      rune
	term     bool
	meta     interface{}
	mask     uint64
	parent   *Node
	children map[rune]*Node
}

type Trie struct {
	root *Node
	size int
}

type ByKeys []string

func (a ByKeys) Len() int           { return len(a) }
func (a ByKeys) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
func (a ByKeys) Less(i, j int) bool { return len(a[i]) < len(a[j]) }

const nul = 0x0

// Creates a new Trie with an initialized root Node.
func New() *Trie {
	node := newNode(nil, 0, 0, false)
	return &Trie{
		root: node,
		size: 0,
	}
}

// Returns the root node for the Trie.
func (t *Trie) Root() *Node {
	return t.root
}

// Adds the key to the Trie, including meta data. Meta data
// is stored as `interface{}` and must be type cast by
// the caller.
func (t *Trie) Add(key string, meta interface{}) *Node {
	t.size++
	runes := []rune(key)
	node := t.addrune(t.Root(), runes, 0)
	node.meta = meta
	return node
}

// Finds and returns meta data associated
// with `key`.
func (t *Trie) Find(key string) (*Node, bool) {
	node := t.nodeAtPath(key)
	if node != nil {
		node = node.Children()[nul]
	}

	if node == nil || !node.term {
		return nil, false
	}

	return node, true
}

// Removes a key from the trie, ensuring that
// all bitmasks up to root are appropriately recalculated.
func (t *Trie) Remove(key string) {
	var (
		i    int
		rs   = []rune(key)
		node = t.nodeAtPath(key)
	)

	t.size--
	for n := node.Parent(); n != nil; n = n.Parent() {
		i++
		if len(n.Children()) > 1 {
			r := rs[len(rs)-i]
			n.RemoveChild(r)
			break
		}
	}
}

// Returns all the keys currently stored in the trie.
func (t *Trie) Keys() []string {
	return t.PrefixSearch("")
}

// Performs a fuzzy search against the keys in the trie.
func (t Trie) FuzzySearch(pre string) []string {
	var (
		keys []string
		pm   []rune
	)

	fuzzycollect(t.Root(), 0, pm, []rune(pre), &keys)
	sort.Sort(ByKeys(keys))

	return keys
}

// Performs a prefix search against the keys in the trie.
func (t Trie) PrefixSearch(pre string) []string {
	var keys []string

	node := t.nodeAtPath(pre)
	if node == nil {
		return keys
	}

	collect(node, []rune(pre), &keys)
	return keys
}

func (t Trie) nodeAtPath(pre string) *Node {
	runes := []rune(pre)
	return findNode(t.Root(), runes)
}

func (t Trie) addrune(node *Node, runes []rune, i int) *Node {
	if len(runes) == 0 {
		return node.NewChild(0, 0, nul, true)
	}

	r := runes[0]
	c := node.Children()

	n, ok := c[r]
	bitmask := maskruneslice(runes)
	if !ok {
		n = node.NewChild(r, bitmask, r, false)
	}
	n.mask |= bitmask

	i++
	return t.addrune(n, runes[1:], i)
}

func newNode(parent *Node, val rune, m uint64, term bool) *Node {
	return &Node{
		val:      val,
		mask:     m,
		term:     term,
		parent:   parent,
		children: make(map[rune]*Node),
	}
}

// Creates and returns a pointer to a new child for the node.
func (n *Node) NewChild(r rune, bitmask uint64, val rune, term bool) *Node {
	node := newNode(n, val, bitmask, term)
	n.children[r] = node
	return node
}

func (n *Node) RemoveChild(r rune) {
	delete(n.children, r)

	n.recalculateMask()
	for parent := n.Parent(); parent != nil; parent = parent.Parent() {
		parent.recalculateMask()
	}
}

func (n *Node) recalculateMask() {
	n.mask = maskrune(n.Val())
	for k, c := range n.Children() {
		n.mask |= (maskrune(k) | c.Mask())
	}
}

// Returns the parent of this node.
func (n Node) Parent() *Node {
	return n.parent
}

// Returns the meta information of this node.
func (n Node) Meta() interface{} {
	return n.meta
}

// Returns the children of this node.
func (n Node) Children() map[rune]*Node {
	return n.children
}

func (n Node) Val() rune {
	return n.val
}

// Returns a uint64 representing the current
// mask of this node.
func (n Node) Mask() uint64 {
	return n.mask
}

func findNode(node *Node, runes []rune) *Node {
	if node == nil {
		return nil
	}

	if len(runes) == 0 {
		return node
	}

	n, ok := node.Children()[runes[0]]
	if !ok {
		return nil
	}

	var nrunes []rune
	if len(runes) > 1 {
		nrunes = runes[1:]
	} else {
		nrunes = runes[0:0]
	}

	return findNode(n, nrunes)
}

func maskruneslice(rs []rune) uint64 {
	var m uint64
	for _, r := range rs {
		m |= maskrune(r)
	}

	return m
}

func maskrune(r rune) uint64 {
	i := uint64(1)
	return i << (uint64(r) - 97)
}

func collect(node *Node, pre []rune, keys *[]string) {
	children := node.Children()
	for r, n := range children {
		if n.term {
			*keys = append(*keys, string(pre))
			continue
		}

		npre := append(pre, r)
		collect(n, npre, keys)
	}
}

func fuzzycollect(node *Node, idx int, partialmatch, partial []rune, keys *[]string) {
	var (
		m          uint64
		partiallen = len(partial)
	)

	if partiallen == idx {
		collect(node, partialmatch, keys)
		return
	}

	children := node.Children()
	m = maskruneslice(partial[idx:])
	for v, n := range children {
		if (n.mask & m) != m {
			continue
		}

		if v == partial[idx] {
			fuzzycollect(n, idx+1, append(partialmatch, v), partial, keys)
			continue
		}

		fuzzycollect(n, idx, append(partialmatch, v), partial, keys)
	}
}
<commit_msg>Style tweak.<commit_after>// Implementation of an R-Way Trie data structure.
//
// A Trie has a root Node which is the base of the tree.
// Each subsequent Node has a letter and children, which are
// nodes that have letter values associated with them.
package trie

import (
	"sort"
)

type Node struct {
	val      rune
	term     bool
	meta     interface{}
	mask     uint64
	parent   *Node
	children map[rune]*Node
}

type Trie struct {
	root *Node
	size int
}

type ByKeys []string

func (a ByKeys) Len() int           { return len(a) }
func (a ByKeys) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
func (a ByKeys) Less(i, j int) bool { return len(a[i]) < len(a[j]) }

const nul = 0x0

// Creates a new Trie with an initialized root Node.
func New() *Trie {
	node := newNode(nil, 0, 0, false)
	return &Trie{
		root: node,
		size: 0,
	}
}

// Returns the root node for the Trie.
func (t *Trie) Root() *Node {
	return t.root
}

// Adds the key to the Trie, including meta data. Meta data
// is stored as `interface{}` and must be type cast by
// the caller.
func (t *Trie) Add(key string, meta interface{}) *Node {
	t.size++
	runes := []rune(key)
	node := t.addrune(t.Root(), runes, 0)
	node.meta = meta
	return node
}

// Finds and returns meta data associated
// with `key`.
func (t *Trie) Find(key string) (*Node, bool) {
	node := t.nodeAtPath(key)
	if node == nil {
		return nil, false
	}
	node = node.Children()[nul]

	if !node.term {
		return nil, false
	}

	return node, true
}

// Removes a key from the trie, ensuring that
// all bitmasks up to root are appropriately recalculated.
func (t *Trie) Remove(key string) {
	var (
		i    int
		rs   = []rune(key)
		node = t.nodeAtPath(key)
	)

	t.size--
	for n := node.Parent(); n != nil; n = n.Parent() {
		i++
		if len(n.Children()) > 1 {
			r := rs[len(rs)-i]
			n.RemoveChild(r)
			break
		}
	}
}

// Returns all the keys currently stored in the trie.
func (t *Trie) Keys() []string {
	return t.PrefixSearch("")
}

// Performs a fuzzy search against the keys in the trie.
func (t Trie) FuzzySearch(pre string) []string {
	var (
		keys []string
		pm   []rune
	)

	fuzzycollect(t.Root(), 0, pm, []rune(pre), &keys)
	sort.Sort(ByKeys(keys))

	return keys
}

// Performs a prefix search against the keys in the trie.
func (t Trie) PrefixSearch(pre string) []string {
	var keys []string

	node := t.nodeAtPath(pre)
	if node == nil {
		return keys
	}

	collect(node, []rune(pre), &keys)
	return keys
}

func (t Trie) nodeAtPath(pre string) *Node {
	runes := []rune(pre)
	return findNode(t.Root(), runes)
}

func (t Trie) addrune(node *Node, runes []rune, i int) *Node {
	if len(runes) == 0 {
		return node.NewChild(0, 0, nul, true)
	}

	r := runes[0]
	c := node.Children()

	n, ok := c[r]
	bitmask := maskruneslice(runes)
	if !ok {
		n = node.NewChild(r, bitmask, r, false)
	}
	n.mask |= bitmask

	i++
	return t.addrune(n, runes[1:], i)
}

func newNode(parent *Node, val rune, m uint64, term bool) *Node {
	return &Node{
		val:      val,
		mask:     m,
		term:     term,
		parent:   parent,
		children: make(map[rune]*Node),
	}
}

// Creates and returns a pointer to a new child for the node.
func (n *Node) NewChild(r rune, bitmask uint64, val rune, term bool) *Node {
	node := newNode(n, val, bitmask, term)
	n.children[r] = node
	return node
}

func (n *Node) RemoveChild(r rune) {
	delete(n.children, r)

	n.recalculateMask()
	for parent := n.Parent(); parent != nil; parent = parent.Parent() {
		parent.recalculateMask()
	}
}

func (n *Node) recalculateMask() {
	n.mask = maskrune(n.Val())
	for k, c := range n.Children() {
		n.mask |= (maskrune(k) | c.Mask())
	}
}

// Returns the parent of this node.
func (n Node) Parent() *Node {
	return n.parent
}

// Returns the meta information of this node.
func (n Node) Meta() interface{} {
	return n.meta
}

// Returns the children of this node.
func (n Node) Children() map[rune]*Node {
	return n.children
}

func (n Node) Val() rune {
	return n.val
}

// Returns a uint64 representing the current
// mask of this node.
func (n Node) Mask() uint64 {
	return n.mask
}

func findNode(node *Node, runes []rune) *Node {
	if node == nil {
		return nil
	}

	if len(runes) == 0 {
		return node
	}

	n, ok := node.Children()[runes[0]]
	if !ok {
		return nil
	}

	var nrunes []rune
	if len(runes) > 1 {
		nrunes = runes[1:]
	} else {
		nrunes = runes[0:0]
	}

	return findNode(n, nrunes)
}

func maskruneslice(rs []rune) uint64 {
	var m uint64
	for _, r := range rs {
		m |= maskrune(r)
	}

	return m
}

func maskrune(r rune) uint64 {
	i := uint64(1)
	return i << (uint64(r) - 97)
}

func collect(node *Node, pre []rune, keys *[]string) {
	children := node.Children()
	for r, n := range children {
		if n.term {
			*keys = append(*keys, string(pre))
			continue
		}

		npre := append(pre, r)
		collect(n, npre, keys)
	}
}

func fuzzycollect(node *Node, idx int, partialmatch, partial []rune, keys *[]string) {
	var (
		m          uint64
		partiallen = len(partial)
	)

	if partiallen == idx {
		collect(node, partialmatch, keys)
		return
	}

	children := node.Children()
	m = maskruneslice(partial[idx:])
	for v, n := range children {
		if (n.mask & m) != m {
			continue
		}

		if v == partial[idx] {
			fuzzycollect(n, idx+1, append(partialmatch, v), partial, keys)
			continue
		}

		fuzzycollect(n, idx, append(partialmatch, v), partial, keys)
	}
}
<|endoftext|>


<commit_before>package trie

import (
	"bufio"
	"io"
	"log"
	"os"
	"strings"
)

// Implementation of an R-Way Trie data structure.
//
// A Trie has a root Node which is the base of the tree.
// Each subsequent Node has a letter and children, which are
// nodes that have letter values associated with them.

type Node struct {
	val       int
	mask      uint64
	children  map[rune]*Node
	childvals []rune
}

type Trie struct {
	root *Node
	size int
}

func newNode(val int, m uint64) *Node {
	return &Node{
		val:      val,
		mask:     m,
		children: make(map[rune]*Node),
	}
}

func (n *Node) NewChild(r rune, bitmask uint64, val int) *Node {
	node := newNode(val, bitmask)
	n.children[r] = node
	n.childvals = append(n.childvals, r)
	return node
}

// Returns the children of this node.
func (n Node) Children() map[rune]*Node {
	return n.children
}

func (n Node) ChildVals() []rune {
	return n.childvals
}

func (n Node) Val() int {
	return n.val
}

func (n Node) Mask() uint64 {
	return n.mask
}

// Creates a new Trie with an initialized root Node.
func CreateTrie() *Trie {
	node := newNode(0, 0)
	return &Trie{
		root: node,
		size: 0,
	}
}

// Returns the root node for the Trie.
func (t *Trie) Root() *Node {
	return t.root
}

// Adds the key to the Trie.
func (t *Trie) AddKey(key string) int {
	t.size++
	runes := []rune(key)
	return t.addrune(t.Root(), runes, 0)
}

func (t *Trie) AddKeysFromFile(path string) {
	file, err := os.Open(path)
	if err != nil {
		log.Fatal(err)
	}

	reader := bufio.NewReader(file)

	for {
		line, err := reader.ReadString('\n')
		if err != nil {
			if err == io.EOF {
				break
			}
			log.Fatal(err)
		}

		line = strings.TrimSuffix(line, "\n")
		t.AddKey(line)
	}
}

func (t *Trie) Keys() []string {
	return t.KeysWithPrefix("")
}

func (t Trie) FuzzySearch(pre string) []string {
	var (
		keys []string
		pm   = make([]rune, 35)
	)

	fuzzycollect(t.Root(), pm, []rune(pre), &keys)
	return keys
}

func (t Trie) KeysWithPrefix(pre string) []string {
	var keys []string

	node := t.nodeAtPath(pre)
	if node == nil {
		return keys
	}

	collect(node, []rune(pre), &keys)
	return keys
}

func (t Trie) nodeAtPath(pre string) *Node {
	runes := []rune(pre)
	return findNode(t.Root(), runes, 0)
}

func findNode(node *Node, runes []rune, d int) *Node {
	if node == nil {
		return nil
	}

	if len(runes) == 0 {
		return node
	}

	upper := len(runes)
	if d == upper {
		return node
	}

	n, ok := node.Children()[runes[d]]
	if !ok {
		return nil
	}

	d++
	return findNode(n, runes, d)
}

func (t Trie) addrune(node *Node, runes []rune, i int) int {
	if len(runes) == 0 {
		node.NewChild(0, 0, t.size)
		return i
	}

	r := runes[0]
	c := node.Children()

	n, ok := c[r]
	bitmask := maskruneslice(runes)
	if !ok {
		n = node.NewChild(r, bitmask, 0)
	}
	n.mask |= bitmask

	i++
	return t.addrune(n, runes[1:], i)
}

func maskruneslice(rs []rune) uint64 {
	var m uint64
	i := uint64(1)
	for _, r := range rs {
		h := i << (uint64(r) - 97)
		m |= h
	}

	return m
}

func maskrune(r rune) uint64 {
	var m uint64
	i := uint64(1)
	h := i << (uint64(r) - 97)
	m |= h

	return m
}

func collect(node *Node, pre []rune, keys *[]string) {
	children := node.Children()
	for _, r := range node.ChildVals() {
		n := children[r]
		if n.Val() > 0 {
			*keys = append(*keys, string(pre))
			continue
		}

		npre := append(pre, r)
		collect(n, npre, keys)
	}
}

func fuzzycollect(node *Node, partialmatch, partial []rune, keys *[]string) {
	partiallen := len(partial)

	if partiallen == 0 {
		collect(node, partialmatch, keys)
		return
	}

	m := maskruneslice(partial)
	children := node.Children()
	for _, v := range node.ChildVals() {
		n := children[v]

		xor := n.Mask() ^ m
		if (xor & m) != 0 {
			continue
		}

		npartial := partial
		if v == partial[0] {
			if partiallen > 1 {
				npartial = partial[1:]
			} else {
				npartial = partial[0:0]
			}
		}

		fuzzycollect(n, append(partialmatch, v), npartial, keys)
	}
}
<commit_msg>Add documentation<commit_after>/*
Implementation of an R-Way Trie data structure.

A Trie has a root Node which is the base of the tree.
Each subsequent Node has a letter and children, which are
nodes that have letter values associated with them.
*/

package trie

import (
	"bufio"
	"io"
	"log"
	"os"
	"strings"
)

type Node struct {
	val       int
	mask      uint64
	children  map[rune]*Node
	childvals []rune
}

type Trie struct {
	root *Node
	size int
}

func newNode(val int, m uint64) *Node {
	return &Node{
		val:      val,
		mask:     m,
		children: make(map[rune]*Node),
	}
}

// Creates and returns a pointer to a new child for the node.
func (n *Node) NewChild(r rune, bitmask uint64, val int) *Node {
	node := newNode(val, bitmask)
	n.children[r] = node
	n.childvals = append(n.childvals, r)
	return node
}

// Returns the children of this node.
func (n Node) Children() map[rune]*Node {
	return n.children
}

// Returns all runes stores beneath this node.
// This list does not contain duplicates.
func (n Node) ChildVals() []rune {
	return n.childvals
}

func (n Node) Val() int {
	return n.val
}

// Returns a uint64 representing the current
// mask of this node.
func (n Node) Mask() uint64 {
	return n.mask
}

// Creates a new Trie with an initialized root Node.
func CreateTrie() *Trie {
	node := newNode(0, 0)
	return &Trie{
		root: node,
		size: 0,
	}
}

// Returns the root node for the Trie.
func (t *Trie) Root() *Node {
	return t.root
}

// Adds the key to the Trie.
func (t *Trie) AddKey(key string) int {
	t.size++
	runes := []rune(key)
	return t.addrune(t.Root(), runes, 0)
}

// Reads words from a file and adds them to the
// trie. Expects words to be seperated by a newline.
func (t *Trie) AddKeysFromFile(path string) {
	file, err := os.Open(path)
	if err != nil {
		log.Fatal(err)
	}

	reader := bufio.NewReader(file)

	for {
		line, err := reader.ReadString('\n')
		if err != nil {
			if err == io.EOF {
				break
			}
			log.Fatal(err)
		}

		line = strings.TrimSuffix(line, "\n")
		t.AddKey(line)
	}
}

// Returns all the keys currently stored in the trie.
func (t *Trie) Keys() []string {
	return t.KeysWithPrefix("")
}

// Performs a fuzzy search against the keys in the trie.
func (t Trie) FuzzySearch(pre string) []string {
	var (
		keys []string
		pm   = make([]rune, 35)
	)

	fuzzycollect(t.Root(), pm, []rune(pre), &keys)
	return keys
}

// Performs a prefix search against the keys in the trie.
func (t Trie) KeysWithPrefix(pre string) []string {
	var keys []string

	node := t.nodeAtPath(pre)
	if node == nil {
		return keys
	}

	collect(node, []rune(pre), &keys)
	return keys
}

func (t Trie) nodeAtPath(pre string) *Node {
	runes := []rune(pre)
	return findNode(t.Root(), runes, 0)
}

func findNode(node *Node, runes []rune, d int) *Node {
	if node == nil {
		return nil
	}

	if len(runes) == 0 {
		return node
	}

	upper := len(runes)
	if d == upper {
		return node
	}

	n, ok := node.Children()[runes[d]]
	if !ok {
		return nil
	}

	d++
	return findNode(n, runes, d)
}

func (t Trie) addrune(node *Node, runes []rune, i int) int {
	if len(runes) == 0 {
		node.NewChild(0, 0, t.size)
		return i
	}

	r := runes[0]
	c := node.Children()

	n, ok := c[r]
	bitmask := maskruneslice(runes)
	if !ok {
		n = node.NewChild(r, bitmask, 0)
	}
	n.mask |= bitmask

	i++
	return t.addrune(n, runes[1:], i)
}

func maskruneslice(rs []rune) uint64 {
	var m uint64
	i := uint64(1)
	for _, r := range rs {
		h := i << (uint64(r) - 97)
		m |= h
	}

	return m
}

func maskrune(r rune) uint64 {
	var m uint64
	i := uint64(1)
	h := i << (uint64(r) - 97)
	m |= h

	return m
}

func collect(node *Node, pre []rune, keys *[]string) {
	children := node.Children()
	for _, r := range node.ChildVals() {
		n := children[r]
		if n.Val() > 0 {
			*keys = append(*keys, string(pre))
			continue
		}

		npre := append(pre, r)
		collect(n, npre, keys)
	}
}

func fuzzycollect(node *Node, partialmatch, partial []rune, keys *[]string) {
	partiallen := len(partial)

	if partiallen == 0 {
		collect(node, partialmatch, keys)
		return
	}

	m := maskruneslice(partial)
	children := node.Children()
	for _, v := range node.ChildVals() {
		n := children[v]

		xor := n.Mask() ^ m
		if (xor & m) != 0 {
			continue
		}

		npartial := partial
		if v == partial[0] {
			if partiallen > 1 {
				npartial = partial[1:]
			} else {
				npartial = partial[0:0]
			}
		}

		fuzzycollect(n, append(partialmatch, v), npartial, keys)
	}
}
<|endoftext|>


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

package core

import (
	"reflect"
	"sort"
	"strings"
	"time"
)

const (
	POSTGRES = "postgres"
	SQLITE   = "sqlite3"
	MYSQL    = "mysql"
	MSSQL    = "mssql"
	ORACLE   = "oracle"
)

// xorm SQL types
type SQLType struct {
	Name           string
	DefaultLength  int
	DefaultLength2 int
}

const (
	UNKNOW_TYPE = iota
	TEXT_TYPE
	BLOB_TYPE
	TIME_TYPE
	NUMERIC_TYPE
)

func (s *SQLType) IsType(st int) bool {
	if t, ok := SqlTypes[s.Name]; ok && t == st {
		return true
	}
	return false
}

func (s *SQLType) IsText() bool {
	return s.IsType(TEXT_TYPE)
}

func (s *SQLType) IsBlob() bool {
	return s.IsType(BLOB_TYPE)
}

func (s *SQLType) IsTime() bool {
	return s.IsType(TIME_TYPE)
}

func (s *SQLType) IsNumeric() bool {
	return s.IsType(NUMERIC_TYPE)
}

func (s *SQLType) IsJson() bool {
	return s.Name == Json || s.Name == Jsonb
}

var (
	Bit       = "BIT"
	TinyInt   = "TINYINT"
	SmallInt  = "SMALLINT"
	MediumInt = "MEDIUMINT"
	Int       = "INT"
	Integer   = "INTEGER"
	BigInt    = "BIGINT"

	Enum = "ENUM"
	Set  = "SET"

	Char             = "CHAR"
	Varchar          = "VARCHAR"
	NChar            = "NCHAR"
	NVarchar         = "NVARCHAR"
	TinyText         = "TINYTEXT"
	Text             = "TEXT"
	NText            = "NTEXT"
	Clob             = "CLOB"
	MediumText       = "MEDIUMTEXT"
	LongText         = "LONGTEXT"
	Uuid             = "UUID"
	UniqueIdentifier = "UNIQUEIDENTIFIER"
	SysName          = "SYSNAME"

	Date          = "DATE"
	DateTime      = "DATETIME"
	SmallDateTime = "SMALLDATETIME"
	Time          = "TIME"
	TimeStamp     = "TIMESTAMP"
	TimeStampz    = "TIMESTAMPZ"

	Decimal    = "DECIMAL"
	Numeric    = "NUMERIC"
	Money      = "MONEY"
	SmallMoney = "SMALLMONEY"

	Real   = "REAL"
	Float  = "FLOAT"
	Double = "DOUBLE"

	Binary     = "BINARY"
	VarBinary  = "VARBINARY"
	TinyBlob   = "TINYBLOB"
	Blob       = "BLOB"
	MediumBlob = "MEDIUMBLOB"
	LongBlob   = "LONGBLOB"
	Bytea      = "BYTEA"

	Bool    = "BOOL"
	Boolean = "BOOLEAN"

	Serial    = "SERIAL"
	BigSerial = "BIGSERIAL"

	Json  = "JSON"
	Jsonb = "JSONB"

	SqlTypes = map[string]int{
		Bit:       NUMERIC_TYPE,
		TinyInt:   NUMERIC_TYPE,
		SmallInt:  NUMERIC_TYPE,
		MediumInt: NUMERIC_TYPE,
		Int:       NUMERIC_TYPE,
		Integer:   NUMERIC_TYPE,
		BigInt:    NUMERIC_TYPE,

		Enum:  TEXT_TYPE,
		Set:   TEXT_TYPE,
		Json:  TEXT_TYPE,
		Jsonb: TEXT_TYPE,

		Char:       TEXT_TYPE,
		NChar:      TEXT_TYPE,
		Varchar:    TEXT_TYPE,
		NVarchar:   TEXT_TYPE,
		TinyText:   TEXT_TYPE,
		Text:       TEXT_TYPE,
		NText:      TEXT_TYPE,
		MediumText: TEXT_TYPE,
		LongText:   TEXT_TYPE,
		Uuid:       TEXT_TYPE,
		Clob:       TEXT_TYPE,
		SysName:    TEXT_TYPE,

		Date:          TIME_TYPE,
		DateTime:      TIME_TYPE,
		Time:          TIME_TYPE,
		TimeStamp:     TIME_TYPE,
		TimeStampz:    TIME_TYPE,
		SmallDateTime: TIME_TYPE,

		Decimal:    NUMERIC_TYPE,
		Numeric:    NUMERIC_TYPE,
		Real:       NUMERIC_TYPE,
		Float:      NUMERIC_TYPE,
		Double:     NUMERIC_TYPE,
		Money:      NUMERIC_TYPE,
		SmallMoney: NUMERIC_TYPE,

		Binary:    BLOB_TYPE,
		VarBinary: BLOB_TYPE,

		TinyBlob:         BLOB_TYPE,
		Blob:             BLOB_TYPE,
		MediumBlob:       BLOB_TYPE,
		LongBlob:         BLOB_TYPE,
		Bytea:            BLOB_TYPE,
		UniqueIdentifier: BLOB_TYPE,

		Bool: NUMERIC_TYPE,

		Serial:    NUMERIC_TYPE,
		BigSerial: NUMERIC_TYPE,
	}

	intTypes  = sort.StringSlice{"*int", "*int16", "*int32", "*int8"}
	uintTypes = sort.StringSlice{"*uint", "*uint16", "*uint32", "*uint8"}
)

// !nashtsai! treat following var as interal const values, these are used for reflect.TypeOf comparison
var (
	c_EMPTY_STRING       string
	c_BOOL_DEFAULT       bool
	c_BYTE_DEFAULT       byte
	c_COMPLEX64_DEFAULT  complex64
	c_COMPLEX128_DEFAULT complex128
	c_FLOAT32_DEFAULT    float32
	c_FLOAT64_DEFAULT    float64
	c_INT64_DEFAULT      int64
	c_UINT64_DEFAULT     uint64
	c_INT32_DEFAULT      int32
	c_UINT32_DEFAULT     uint32
	c_INT16_DEFAULT      int16
	c_UINT16_DEFAULT     uint16
	c_INT8_DEFAULT       int8
	c_UINT8_DEFAULT      uint8
	c_INT_DEFAULT        int
	c_UINT_DEFAULT       uint
	c_TIME_DEFAULT       time.Time
)

var (
	IntType   = reflect.TypeOf(c_INT_DEFAULT)
	Int8Type  = reflect.TypeOf(c_INT8_DEFAULT)
	Int16Type = reflect.TypeOf(c_INT16_DEFAULT)
	Int32Type = reflect.TypeOf(c_INT32_DEFAULT)
	Int64Type = reflect.TypeOf(c_INT64_DEFAULT)

	UintType   = reflect.TypeOf(c_UINT_DEFAULT)
	Uint8Type  = reflect.TypeOf(c_UINT8_DEFAULT)
	Uint16Type = reflect.TypeOf(c_UINT16_DEFAULT)
	Uint32Type = reflect.TypeOf(c_UINT32_DEFAULT)
	Uint64Type = reflect.TypeOf(c_UINT64_DEFAULT)

	Float32Type = reflect.TypeOf(c_FLOAT32_DEFAULT)
	Float64Type = reflect.TypeOf(c_FLOAT64_DEFAULT)

	Complex64Type  = reflect.TypeOf(c_COMPLEX64_DEFAULT)
	Complex128Type = reflect.TypeOf(c_COMPLEX128_DEFAULT)

	StringType = reflect.TypeOf(c_EMPTY_STRING)
	BoolType   = reflect.TypeOf(c_BOOL_DEFAULT)
	ByteType   = reflect.TypeOf(c_BYTE_DEFAULT)
	BytesType  = reflect.SliceOf(ByteType)

	TimeType = reflect.TypeOf(c_TIME_DEFAULT)
)

var (
	PtrIntType   = reflect.PtrTo(IntType)
	PtrInt8Type  = reflect.PtrTo(Int8Type)
	PtrInt16Type = reflect.PtrTo(Int16Type)
	PtrInt32Type = reflect.PtrTo(Int32Type)
	PtrInt64Type = reflect.PtrTo(Int64Type)

	PtrUintType   = reflect.PtrTo(UintType)
	PtrUint8Type  = reflect.PtrTo(Uint8Type)
	PtrUint16Type = reflect.PtrTo(Uint16Type)
	PtrUint32Type = reflect.PtrTo(Uint32Type)
	PtrUint64Type = reflect.PtrTo(Uint64Type)

	PtrFloat32Type = reflect.PtrTo(Float32Type)
	PtrFloat64Type = reflect.PtrTo(Float64Type)

	PtrComplex64Type  = reflect.PtrTo(Complex64Type)
	PtrComplex128Type = reflect.PtrTo(Complex128Type)

	PtrStringType = reflect.PtrTo(StringType)
	PtrBoolType   = reflect.PtrTo(BoolType)
	PtrByteType   = reflect.PtrTo(ByteType)

	PtrTimeType = reflect.PtrTo(TimeType)
)

// Type2SQLType generate SQLType acorrding Go's type
func Type2SQLType(t reflect.Type) (st SQLType) {
	switch k := t.Kind(); k {
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32:
		st = SQLType{Int, 0, 0}
	case reflect.Int64, reflect.Uint64:
		st = SQLType{BigInt, 0, 0}
	case reflect.Float32:
		st = SQLType{Float, 0, 0}
	case reflect.Float64:
		st = SQLType{Double, 0, 0}
	case reflect.Complex64, reflect.Complex128:
		st = SQLType{Varchar, 64, 0}
	case reflect.Array, reflect.Slice, reflect.Map:
		if t.Elem() == reflect.TypeOf(c_BYTE_DEFAULT) {
			st = SQLType{Blob, 0, 0}
		} else {
			st = SQLType{Text, 0, 0}
		}
	case reflect.Bool:
		st = SQLType{Bool, 0, 0}
	case reflect.String:
		st = SQLType{Varchar, 255, 0}
	case reflect.Struct:
		if t.ConvertibleTo(TimeType) {
			st = SQLType{DateTime, 0, 0}
		} else {
			// TODO need to handle association struct
			st = SQLType{Text, 0, 0}
		}
	case reflect.Ptr:
		st = Type2SQLType(t.Elem())
	default:
		st = SQLType{Text, 0, 0}
	}
	return
}

// default sql type change to go types
func SQLType2Type(st SQLType) reflect.Type {
	name := strings.ToUpper(st.Name)
	switch name {
	case Bit, TinyInt, SmallInt, MediumInt, Int, Integer, Serial:
		return reflect.TypeOf(1)
	case BigInt, BigSerial:
		return reflect.TypeOf(int64(1))
	case Float, Real:
		return reflect.TypeOf(float32(1))
	case Double:
		return reflect.TypeOf(float64(1))
	case Char, NChar, Varchar, NVarchar, TinyText, Text, NText, MediumText, LongText, Enum, Set, Uuid, Clob, SysName:
		return reflect.TypeOf("")
	case TinyBlob, Blob, LongBlob, Bytea, Binary, MediumBlob, VarBinary, UniqueIdentifier:
		return reflect.TypeOf([]byte{})
	case Bool:
		return reflect.TypeOf(true)
	case DateTime, Date, Time, TimeStamp, TimeStampz, SmallDateTime:
		return reflect.TypeOf(c_TIME_DEFAULT)
	case Decimal, Numeric, Money, SmallMoney:
		return reflect.TypeOf("")
	default:
		return reflect.TypeOf("")
	}
}
<commit_msg>Add Year type for supporting mysql<commit_after>// Copyright 2019 The Xorm Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package core

import (
	"reflect"
	"sort"
	"strings"
	"time"
)

const (
	POSTGRES = "postgres"
	SQLITE   = "sqlite3"
	MYSQL    = "mysql"
	MSSQL    = "mssql"
	ORACLE   = "oracle"
)

// xorm SQL types
type SQLType struct {
	Name           string
	DefaultLength  int
	DefaultLength2 int
}

const (
	UNKNOW_TYPE = iota
	TEXT_TYPE
	BLOB_TYPE
	TIME_TYPE
	NUMERIC_TYPE
)

func (s *SQLType) IsType(st int) bool {
	if t, ok := SqlTypes[s.Name]; ok && t == st {
		return true
	}
	return false
}

func (s *SQLType) IsText() bool {
	return s.IsType(TEXT_TYPE)
}

func (s *SQLType) IsBlob() bool {
	return s.IsType(BLOB_TYPE)
}

func (s *SQLType) IsTime() bool {
	return s.IsType(TIME_TYPE)
}

func (s *SQLType) IsNumeric() bool {
	return s.IsType(NUMERIC_TYPE)
}

func (s *SQLType) IsJson() bool {
	return s.Name == Json || s.Name == Jsonb
}

var (
	Bit       = "BIT"
	TinyInt   = "TINYINT"
	SmallInt  = "SMALLINT"
	MediumInt = "MEDIUMINT"
	Int       = "INT"
	Integer   = "INTEGER"
	BigInt    = "BIGINT"

	Enum = "ENUM"
	Set  = "SET"

	Char             = "CHAR"
	Varchar          = "VARCHAR"
	NChar            = "NCHAR"
	NVarchar         = "NVARCHAR"
	TinyText         = "TINYTEXT"
	Text             = "TEXT"
	NText            = "NTEXT"
	Clob             = "CLOB"
	MediumText       = "MEDIUMTEXT"
	LongText         = "LONGTEXT"
	Uuid             = "UUID"
	UniqueIdentifier = "UNIQUEIDENTIFIER"
	SysName          = "SYSNAME"

	Date          = "DATE"
	DateTime      = "DATETIME"
	SmallDateTime = "SMALLDATETIME"
	Time          = "TIME"
	TimeStamp     = "TIMESTAMP"
	TimeStampz    = "TIMESTAMPZ"
	Year          = "YEAR"

	Decimal    = "DECIMAL"
	Numeric    = "NUMERIC"
	Money      = "MONEY"
	SmallMoney = "SMALLMONEY"

	Real   = "REAL"
	Float  = "FLOAT"
	Double = "DOUBLE"

	Binary     = "BINARY"
	VarBinary  = "VARBINARY"
	TinyBlob   = "TINYBLOB"
	Blob       = "BLOB"
	MediumBlob = "MEDIUMBLOB"
	LongBlob   = "LONGBLOB"
	Bytea      = "BYTEA"

	Bool    = "BOOL"
	Boolean = "BOOLEAN"

	Serial    = "SERIAL"
	BigSerial = "BIGSERIAL"

	Json  = "JSON"
	Jsonb = "JSONB"

	SqlTypes = map[string]int{
		Bit:       NUMERIC_TYPE,
		TinyInt:   NUMERIC_TYPE,
		SmallInt:  NUMERIC_TYPE,
		MediumInt: NUMERIC_TYPE,
		Int:       NUMERIC_TYPE,
		Integer:   NUMERIC_TYPE,
		BigInt:    NUMERIC_TYPE,

		Enum:  TEXT_TYPE,
		Set:   TEXT_TYPE,
		Json:  TEXT_TYPE,
		Jsonb: TEXT_TYPE,

		Char:       TEXT_TYPE,
		NChar:      TEXT_TYPE,
		Varchar:    TEXT_TYPE,
		NVarchar:   TEXT_TYPE,
		TinyText:   TEXT_TYPE,
		Text:       TEXT_TYPE,
		NText:      TEXT_TYPE,
		MediumText: TEXT_TYPE,
		LongText:   TEXT_TYPE,
		Uuid:       TEXT_TYPE,
		Clob:       TEXT_TYPE,
		SysName:    TEXT_TYPE,

		Date:          TIME_TYPE,
		DateTime:      TIME_TYPE,
		Time:          TIME_TYPE,
		TimeStamp:     TIME_TYPE,
		TimeStampz:    TIME_TYPE,
		SmallDateTime: TIME_TYPE,
		Year:          TIME_TYPE,

		Decimal:    NUMERIC_TYPE,
		Numeric:    NUMERIC_TYPE,
		Real:       NUMERIC_TYPE,
		Float:      NUMERIC_TYPE,
		Double:     NUMERIC_TYPE,
		Money:      NUMERIC_TYPE,
		SmallMoney: NUMERIC_TYPE,

		Binary:    BLOB_TYPE,
		VarBinary: BLOB_TYPE,

		TinyBlob:         BLOB_TYPE,
		Blob:             BLOB_TYPE,
		MediumBlob:       BLOB_TYPE,
		LongBlob:         BLOB_TYPE,
		Bytea:            BLOB_TYPE,
		UniqueIdentifier: BLOB_TYPE,

		Bool: NUMERIC_TYPE,

		Serial:    NUMERIC_TYPE,
		BigSerial: NUMERIC_TYPE,
	}

	intTypes  = sort.StringSlice{"*int", "*int16", "*int32", "*int8"}
	uintTypes = sort.StringSlice{"*uint", "*uint16", "*uint32", "*uint8"}
)

// !nashtsai! treat following var as interal const values, these are used for reflect.TypeOf comparison
var (
	c_EMPTY_STRING       string
	c_BOOL_DEFAULT       bool
	c_BYTE_DEFAULT       byte
	c_COMPLEX64_DEFAULT  complex64
	c_COMPLEX128_DEFAULT complex128
	c_FLOAT32_DEFAULT    float32
	c_FLOAT64_DEFAULT    float64
	c_INT64_DEFAULT      int64
	c_UINT64_DEFAULT     uint64
	c_INT32_DEFAULT      int32
	c_UINT32_DEFAULT     uint32
	c_INT16_DEFAULT      int16
	c_UINT16_DEFAULT     uint16
	c_INT8_DEFAULT       int8
	c_UINT8_DEFAULT      uint8
	c_INT_DEFAULT        int
	c_UINT_DEFAULT       uint
	c_TIME_DEFAULT       time.Time
)

var (
	IntType   = reflect.TypeOf(c_INT_DEFAULT)
	Int8Type  = reflect.TypeOf(c_INT8_DEFAULT)
	Int16Type = reflect.TypeOf(c_INT16_DEFAULT)
	Int32Type = reflect.TypeOf(c_INT32_DEFAULT)
	Int64Type = reflect.TypeOf(c_INT64_DEFAULT)

	UintType   = reflect.TypeOf(c_UINT_DEFAULT)
	Uint8Type  = reflect.TypeOf(c_UINT8_DEFAULT)
	Uint16Type = reflect.TypeOf(c_UINT16_DEFAULT)
	Uint32Type = reflect.TypeOf(c_UINT32_DEFAULT)
	Uint64Type = reflect.TypeOf(c_UINT64_DEFAULT)

	Float32Type = reflect.TypeOf(c_FLOAT32_DEFAULT)
	Float64Type = reflect.TypeOf(c_FLOAT64_DEFAULT)

	Complex64Type  = reflect.TypeOf(c_COMPLEX64_DEFAULT)
	Complex128Type = reflect.TypeOf(c_COMPLEX128_DEFAULT)

	StringType = reflect.TypeOf(c_EMPTY_STRING)
	BoolType   = reflect.TypeOf(c_BOOL_DEFAULT)
	ByteType   = reflect.TypeOf(c_BYTE_DEFAULT)
	BytesType  = reflect.SliceOf(ByteType)

	TimeType = reflect.TypeOf(c_TIME_DEFAULT)
)

var (
	PtrIntType   = reflect.PtrTo(IntType)
	PtrInt8Type  = reflect.PtrTo(Int8Type)
	PtrInt16Type = reflect.PtrTo(Int16Type)
	PtrInt32Type = reflect.PtrTo(Int32Type)
	PtrInt64Type = reflect.PtrTo(Int64Type)

	PtrUintType   = reflect.PtrTo(UintType)
	PtrUint8Type  = reflect.PtrTo(Uint8Type)
	PtrUint16Type = reflect.PtrTo(Uint16Type)
	PtrUint32Type = reflect.PtrTo(Uint32Type)
	PtrUint64Type = reflect.PtrTo(Uint64Type)

	PtrFloat32Type = reflect.PtrTo(Float32Type)
	PtrFloat64Type = reflect.PtrTo(Float64Type)

	PtrComplex64Type  = reflect.PtrTo(Complex64Type)
	PtrComplex128Type = reflect.PtrTo(Complex128Type)

	PtrStringType = reflect.PtrTo(StringType)
	PtrBoolType   = reflect.PtrTo(BoolType)
	PtrByteType   = reflect.PtrTo(ByteType)

	PtrTimeType = reflect.PtrTo(TimeType)
)

// Type2SQLType generate SQLType acorrding Go's type
func Type2SQLType(t reflect.Type) (st SQLType) {
	switch k := t.Kind(); k {
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32:
		st = SQLType{Int, 0, 0}
	case reflect.Int64, reflect.Uint64:
		st = SQLType{BigInt, 0, 0}
	case reflect.Float32:
		st = SQLType{Float, 0, 0}
	case reflect.Float64:
		st = SQLType{Double, 0, 0}
	case reflect.Complex64, reflect.Complex128:
		st = SQLType{Varchar, 64, 0}
	case reflect.Array, reflect.Slice, reflect.Map:
		if t.Elem() == reflect.TypeOf(c_BYTE_DEFAULT) {
			st = SQLType{Blob, 0, 0}
		} else {
			st = SQLType{Text, 0, 0}
		}
	case reflect.Bool:
		st = SQLType{Bool, 0, 0}
	case reflect.String:
		st = SQLType{Varchar, 255, 0}
	case reflect.Struct:
		if t.ConvertibleTo(TimeType) {
			st = SQLType{DateTime, 0, 0}
		} else {
			// TODO need to handle association struct
			st = SQLType{Text, 0, 0}
		}
	case reflect.Ptr:
		st = Type2SQLType(t.Elem())
	default:
		st = SQLType{Text, 0, 0}
	}
	return
}

// default sql type change to go types
func SQLType2Type(st SQLType) reflect.Type {
	name := strings.ToUpper(st.Name)
	switch name {
	case Bit, TinyInt, SmallInt, MediumInt, Int, Integer, Serial:
		return reflect.TypeOf(1)
	case BigInt, BigSerial:
		return reflect.TypeOf(int64(1))
	case Float, Real:
		return reflect.TypeOf(float32(1))
	case Double:
		return reflect.TypeOf(float64(1))
	case Char, NChar, Varchar, NVarchar, TinyText, Text, NText, MediumText, LongText, Enum, Set, Uuid, Clob, SysName:
		return reflect.TypeOf("")
	case TinyBlob, Blob, LongBlob, Bytea, Binary, MediumBlob, VarBinary, UniqueIdentifier:
		return reflect.TypeOf([]byte{})
	case Bool:
		return reflect.TypeOf(true)
	case DateTime, Date, Time, TimeStamp, TimeStampz, SmallDateTime, Year:
		return reflect.TypeOf(c_TIME_DEFAULT)
	case Decimal, Numeric, Money, SmallMoney:
		return reflect.TypeOf("")
	default:
		return reflect.TypeOf("")
	}
}
<|endoftext|>


<commit_before>package main

import (
	cwe "github.com/aws/aws-sdk-go/service/cloudwatchevents"
)

// compare strings
// nil and empty string are same value
func CompareString(a, b *string) bool {
	if a == nil || *a == "" {
		if b == nil || *b == "" {
			return true
		} else {
			return false
		}
	} else if b == nil || *b == "" {
		if a == nil || *a == "" {
			return true
		} else {
			return false
		}
	}
	return *a == *b
}

// return ClowdWatchEvent Rules that deleted specified index rule.
func DeleteRuleFromSlice(src []*cwe.Rule, deleteIndex int) []*cwe.Rule {
	dest := []*cwe.Rule{}
	for i, rule := range src {
		if i != deleteIndex {
			dest = append(dest, rule)
		}
	}
	return dest
}

// return ClowdWatchEvent Targets that deleted specified index target.
func DeleteTargetFromSlice(src []*cwe.Target, deleteIndex int) []*cwe.Target {
	dest := []*cwe.Target{}
	for i, target := range src {
		if i != deleteIndex {
			dest = append(dest, target)
		}
	}
	return dest
}

// return string pointer if str is not empty
// if str is empty ("") retuen nil
func NilOrStringPtr(str string) *string {
	if str == "" {
		return nil
	}
	return &str
}

func NilSafeStr(str *string) string {
	if str == nil {
		return ""
	} else {
		return *str
	}
}
<commit_msg>Add comments to functions in util.go<commit_after>package main

import (
	cwe "github.com/aws/aws-sdk-go/service/cloudwatchevents"
)

// CompareString do compare strings
// nil and empty string are same value
// "" == "" => true
// nil == "" => true
// nil == nil => true
func CompareString(a, b *string) bool {
	if a == nil || *a == "" {
		if b == nil || *b == "" {
			return true
		} else {
			return false
		}
	} else if b == nil || *b == "" {
		if a == nil || *a == "" {
			return true
		} else {
			return false
		}
	}
	return *a == *b
}

// DeleteRuleFromSlice return ClowdWatchEvent Rules that deleted specified index rule.
func DeleteRuleFromSlice(src []*cwe.Rule, deleteIndex int) []*cwe.Rule {
	dest := []*cwe.Rule{}
	for i, rule := range src {
		if i != deleteIndex {
			dest = append(dest, rule)
		}
	}
	return dest
}

// DeleteTargetFromSlice return ClowdWatchEvent Targets that deleted specified index target.
func DeleteTargetFromSlice(src []*cwe.Target, deleteIndex int) []*cwe.Target {
	dest := []*cwe.Target{}
	for i, target := range src {
		if i != deleteIndex {
			dest = append(dest, target)
		}
	}
	return dest
}

// NilOrStringPtr return string pointer if str is not empty
// if str is empty ("") retuen nil
func NilOrStringPtr(str string) *string {
	if str == "" {
		return nil
	}
	return &str
}

// NilSafeStr retuen empty string or passed string
func NilSafeStr(str *string) string {
	if str == nil {
		return ""
	} else {
		return *str
	}
}
<|endoftext|>


<commit_before>// Copyright 2013 Michael Yang. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package id3

import (
	"errors"
	iconv "github.com/djimenez/iconv-go"
)

const (
	BytesPerInt     = 4
	SynchByteLength = 7
	NormByteLength  = 8
	NativeEncoding  = "UTF-8"
)

var (
	EncodingMap = [...]string{
		"ISO-8859-1",
		"UTF-16",
		"UTF-16BE",
		"ISO-8859-1",
	}
	Decoders = make([]*iconv.Converter, len(EncodingMap))
	Encoders = make([]*iconv.Converter, len(EncodingMap))
)

func init() {
	for i, e := range EncodingMap {
		Decoders[i], _ = iconv.NewConverter(e, NativeEncoding)
		Encoders[i], _ = iconv.NewConverter(NativeEncoding, e)
	}
}

func byteint(buf []byte, base uint) (i int32, err error) {
	if len(buf) != BytesPerInt {
		err = errors.New("byte integer: invalid []byte length")
		return
	}

	for _, b := range buf {
		if base < NormByteLength && b >= (1<<base) {
			err = errors.New("byte integer: exceed max bit")
			return
		}

		i = (i << base) | int32(b)
	}

	return
}

func synchint(buf []byte) (i int32, err error) {
	i, err = byteint(buf, SynchByteLength)
	return
}

func normint(buf []byte) (i int32, err error) {
	i, err = byteint(buf, NormByteLength)
	return
}

func encodingForIndex(b byte) string {
	encodingIndex := int(b)
	if encodingIndex < 0 || encodingIndex > len(EncodingMap) {
		encodingIndex = 0
	}

	return EncodingMap[encodingIndex]
}

func indexForEncoding(e string) byte {
	for i, v := range EncodingMap {
		if v == e {
			return byte(i)
		}
	}

	return 0
}
<commit_msg>Add variable byte length null detection<commit_after>// Copyright 2013 Michael Yang. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package id3

import (
	"bytes"
	"errors"
	iconv "github.com/djimenez/iconv-go"
)

const (
	BytesPerInt     = 4
	SynchByteLength = 7
	NormByteLength  = 8
	NativeEncoding  = "UTF-8"
	UTF16NullLength = 2
)

var (
	EncodingMap = [...]string{
		"ISO-8859-1",
		"UTF-16",
		"UTF-16BE",
		"ISO-8859-1",
	}
	Decoders = make([]*iconv.Converter, len(EncodingMap))
	Encoders = make([]*iconv.Converter, len(EncodingMap))
)

func init() {
	for i, e := range EncodingMap {
		Decoders[i], _ = iconv.NewConverter(e, NativeEncoding)
		Encoders[i], _ = iconv.NewConverter(NativeEncoding, e)
	}
}

func byteint(buf []byte, base uint) (i int32, err error) {
	if len(buf) != BytesPerInt {
		err = errors.New("byte integer: invalid []byte length")
		return
	}

	for _, b := range buf {
		if base < NormByteLength && b >= (1<<base) {
			err = errors.New("byte integer: exceed max bit")
			return
		}

		i = (i << base) | int32(b)
	}

	return
}

func synchint(buf []byte) (i int32, err error) {
	i, err = byteint(buf, SynchByteLength)
	return
}

func normint(buf []byte) (i int32, err error) {
	i, err = byteint(buf, NormByteLength)
	return
}

func encodingForIndex(b byte) string {
	encodingIndex := int(b)
	if encodingIndex < 0 || encodingIndex > len(EncodingMap) {
		encodingIndex = 0
	}

	return EncodingMap[encodingIndex]
}

func indexForEncoding(e string) byte {
	for i, v := range EncodingMap {
		if v == e {
			return byte(i)
		}
	}

	return 0
}

func afterNullIndex(data []byte, encoding string) int {
	if encoding == "UTF-16" || encoding == "UTF-16BE" {
		limit, byteCount := len(data), UTF16NullLength
		null := bytes.Repeat([]byte{0x0}, byteCount)

		for i, _ := range data[:limit/byteCount] {
			atIndex := byteCount * i
			afterIndex := atIndex + byteCount

			if bytes.Equal(data[atIndex:afterIndex], null) {
				return afterIndex
			}
		}
	} else {
		if index := bytes.IndexByte(data, 0x00); index >= 0 {
			return index + 1
		}
	}

	return -1
}
<|endoftext|>


<commit_before>package web

import (
	"bytes"
	"errors"
	"fmt"
	"net/http"
	"strconv"

	"github.com/asaskevich/govalidator"
	"github.com/eyecuelab/kit/brake"
	"github.com/eyecuelab/kit/log"
	"github.com/eyecuelab/kit/str"
	"github.com/google/jsonapi"
	"github.com/labstack/echo"
	"github.com/lib/pq"
	"database/sql"
)

//testCode is for internal testing
type testCode byte

const (
	alreadyCommited testCode = iota
	methodIsHead
	noContent
	problemRendering
	nilErr
	normal
)

var pq500s = map[string]bool{
	"undefined_function": true,
}

var criticalKeywords = []string{
	"reflect",
	"dereference",
	"runtime",
}

//errorHandler is the internal implementation of ErrorHandler. It returns a testCode,
//which does not fufill the interface expected by echo. Thus, it is wrapped by the function ErrorHandler.
func errorHandler(err error, c echo.Context) testCode {
	if c.Response().Committed {
		return alreadyCommited
	}
	if err == nil {
		trackErr(errors.New("nil error sent into ErrorHandler"), c, 0)
		return nilErr
	}

	status, apiError := toApiError(err)

	if c.Request().Method == "HEAD" {
		if err := c.NoContent(status); err != nil {
			trackErr(err, c, status)
			return noContent
		}
		return methodIsHead
	}

	if errRendering := renderApiErrors(c, apiError); errRendering != nil {
		trackErr(errRendering, c, 0)
		trackErr(err, c, status)
		return problemRendering
	}

	trackErr(err, c, status)
	return normal
}

//ErrorHandler handles errors
func ErrorHandler(err error, c echo.Context) {
	errorHandler(err, c)
}

func toApiError(err error) (status int, apiErr *jsonapi.ErrorObject) {
	var detail, code string
	status = http.StatusInternalServerError
	switch err := err.(type) {
	case nil:
		return 200, nil
	case *jsonapi.ErrorObject:
		if status, convErr := strconv.Atoi(err.Status); convErr == nil {
			return status, err
		}
		err.Detail += fmt.Sprintf(" bad status: %s", err.Status)

		return status, err

	case *echo.HTTPError:
		status = err.Code
		if err.Message != nil {
			detail = fmt.Sprint(err.Message)
		}
		return status, errorObj(status, http.StatusText(status), detail, code)

	case *pq.Error:
		detail = err.Message
		code = err.Code.Name()
		if _, ok := pq500s[code]; !ok {
			status = http.StatusBadRequest
		}
		return status, errorObj(status, http.StatusText(status), detail, code)

	case govalidator.Errors:
		status, detail = http.StatusBadRequest, err.Error()
		return status, errorObj(status, http.StatusText(status), detail, code)

	case error:
		switch err {
		case sql.ErrNoRows:
			status, detail = http.StatusNotFound, err.Error()
			return http.StatusNotFound, errorObj(status, http.StatusText(status), "", "")
		}
	}

	detail = err.Error()
	return status, errorObj(status, http.StatusText(status), detail, code)
}

func renderApiErrors(c echo.Context, errors ...*jsonapi.ErrorObject) (err error) {
	var b bytes.Buffer
	if emptyOrAllNil(errors) {
		return fmt.Errorf("no errors to render")
	}

	if err = jsonapi.MarshalErrors(&b, errors); err != nil {
		return err
	}
	code, err := strconv.Atoi(errors[0].Status)
	if err != nil {
		return err
	}
	return c.Blob(code, jsonapi.MediaType, b.Bytes())
}

func emptyOrAllNil(errs []*jsonapi.ErrorObject) bool {
	for _, err := range errs {
		if err != nil {
			return false
		}
	}
	return true
}

func errorObj(status int, title, detail, code string) *jsonapi.ErrorObject {
	return &jsonapi.ErrorObject{
		Status: fmt.Sprintf("%d", status),
		Title:  title,
		Detail: detail,
		Code:   code,
	}
}

func trackErr(err error, c echo.Context, status int) {
	notifyErr(err, c, status)
	if status == 0 || status >= 500 {
		logErr(err)
	}
}

func logErr(err error) {
	log.ErrorWrap(err, "Uncaught Error")
}

func notifyErr(err error, c echo.Context, status int) {
	if status == http.StatusUnauthorized {
		return
	}

	sev := brake.SeverityError
	if isCritical(err) {
		sev = brake.SeverityCritical
	} else if status > 0 && status < 500 {
		sev = brake.SeverityWarn
	}

	brake.Notify(err, c.Request(), sev)
}

func isCritical(err error) bool {
	return str.ContainsAny(err.Error(), criticalKeywords...)
}
<commit_msg>only report/log 500s<commit_after>package web

import (
	"bytes"
	"errors"
	"fmt"
	"net/http"
	"strconv"

	"github.com/asaskevich/govalidator"
	"github.com/eyecuelab/kit/brake"
	"github.com/eyecuelab/kit/log"
	"github.com/eyecuelab/kit/str"
	"github.com/google/jsonapi"
	"github.com/labstack/echo"
	"github.com/lib/pq"
	"database/sql"
)

//testCode is for internal testing
type testCode byte

const (
	alreadyCommited testCode = iota
	methodIsHead
	noContent
	problemRendering
	nilErr
	normal
)

var pq500s = map[string]bool{
	"undefined_function": true,
}

var criticalKeywords = []string{
	"reflect",
	"dereference",
	"runtime",
}

//errorHandler is the internal implementation of ErrorHandler. It returns a testCode,
//which does not fufill the interface expected by echo. Thus, it is wrapped by the function ErrorHandler.
func errorHandler(err error, c echo.Context) testCode {
	if c.Response().Committed {
		return alreadyCommited
	}
	if err == nil {
		trackErr(errors.New("nil error sent into ErrorHandler"), c, 0)
		return nilErr
	}

	status, apiError := toApiError(err)

	if c.Request().Method == "HEAD" {
		if err := c.NoContent(status); err != nil {
			trackErr(err, c, status)
			return noContent
		}
		return methodIsHead
	}

	if errRendering := renderApiErrors(c, apiError); errRendering != nil {
		trackErr(errRendering, c, 0)
		trackErr(err, c, status)
		return problemRendering
	}

	trackErr(err, c, status)
	return normal
}

//ErrorHandler handles errors
func ErrorHandler(err error, c echo.Context) {
	errorHandler(err, c)
}

func toApiError(err error) (status int, apiErr *jsonapi.ErrorObject) {
	var detail, code string
	status = http.StatusInternalServerError
	switch err := err.(type) {
	case nil:
		return 200, nil
	case *jsonapi.ErrorObject:
		if status, convErr := strconv.Atoi(err.Status); convErr == nil {
			return status, err
		}
		err.Detail += fmt.Sprintf(" bad status: %s", err.Status)

		return status, err

	case *echo.HTTPError:
		status = err.Code
		if err.Message != nil {
			detail = fmt.Sprint(err.Message)
		}
		return status, errorObj(status, http.StatusText(status), detail, code)

	case *pq.Error:
		detail = err.Message
		code = err.Code.Name()
		if _, ok := pq500s[code]; !ok {
			status = http.StatusBadRequest
		}
		return status, errorObj(status, http.StatusText(status), detail, code)

	case govalidator.Errors:
		status, detail = http.StatusBadRequest, err.Error()
		return status, errorObj(status, http.StatusText(status), detail, code)

	case error:
		switch err {
		case sql.ErrNoRows:
			status, detail = http.StatusNotFound, err.Error()
			return http.StatusNotFound, errorObj(status, http.StatusText(status), "", "")
		}
	}

	detail = err.Error()
	return status, errorObj(status, http.StatusText(status), detail, code)
}

func renderApiErrors(c echo.Context, errors ...*jsonapi.ErrorObject) (err error) {
	var b bytes.Buffer
	if emptyOrAllNil(errors) {
		return fmt.Errorf("no errors to render")
	}

	if err = jsonapi.MarshalErrors(&b, errors); err != nil {
		return err
	}
	code, err := strconv.Atoi(errors[0].Status)
	if err != nil {
		return err
	}
	return c.Blob(code, jsonapi.MediaType, b.Bytes())
}

func emptyOrAllNil(errs []*jsonapi.ErrorObject) bool {
	for _, err := range errs {
		if err != nil {
			return false
		}
	}
	return true
}

func errorObj(status int, title, detail, code string) *jsonapi.ErrorObject {
	return &jsonapi.ErrorObject{
		Status: fmt.Sprintf("%d", status),
		Title:  title,
		Detail: detail,
		Code:   code,
	}
}

func trackErr(err error, c echo.Context, status int) {
	if status > 0 && status < 500 {
		return
	}
	notifyErr(err, c, status)
	logErr(err)
}

func logErr(err error) {
	log.ErrorWrap(err, "Uncaught Error")
}

func notifyErr(err error, c echo.Context, status int) {
	if status == http.StatusUnauthorized {
		return
	}

	sev := brake.SeverityError
	if isCritical(err) {
		sev = brake.SeverityCritical
	} else if status > 0 && status < 500 {
		sev = brake.SeverityWarn
	}

	brake.Notify(err, c.Request(), sev)
}

func isCritical(err error) bool {
	return str.ContainsAny(err.Error(), criticalKeywords...)
}
<|endoftext|>


<commit_before>package web

import (
	"bytes"
	"fmt"
	"net/http"
	"strconv"

	"github.com/asaskevich/govalidator"
	"github.com/eyecuelab/kit/log"
	"github.com/google/jsonapi"
	"github.com/labstack/echo"
	"github.com/lib/pq"
)

var pq500s = map[string]bool{
	"undefined_function": true,
}

func ErrorHandler(err error, c echo.Context) {
	if c.Response().Committed {
		return
	}

	status, apiError := toApiError(err)

	if c.Request().Method == "HEAD" {
		if err := c.NoContent(status); err != nil {
			goto ERROR
		}
		return
	}

	if err := renderApiErrors(c, apiError); err != nil {
		//FIXME: are we supposed to log this error twice?
		logErr(err)
		goto ERROR
	}

	if status < 500 {
		return
	}
ERROR: //FIXME - I feel like we should justify a GOTO
	logErr(err)
}

func logErr(err error) {
	log.ErrorWrap(err, "Uncaught Error")
}

func toApiError(err error) (status int, apiErr *jsonapi.ErrorObject) {

	var (
		detail interface{}
		code   string
	)
	switch err := err.(type) {
	case *jsonapi.ErrorObject:
		status, _ = strconv.Atoi(err.Status)
		return status, err

	case *echo.HTTPError:
		status, detail = err.Code, err.Message
	case *pq.Error:
		detail = err.Message
		code = err.Code.Name()
		if _, ok := !pq500s[code]; !ok {
			status = http.StatusBadRequest
		}
	case govalidator.Errors:
		status, detail = http.StatusBadRequest, err.Error()
	default:
		status, detail = http.StatusInternalServerError, err.Error()

	}

	return status, valuesToApiError(status, http.StatusText(status), &detail, code)
}

func renderApiErrors(c echo.Context, errors ...*jsonapi.ErrorObject) error {
	var b bytes.Buffer
	if err := jsonapi.MarshalErrors(&b, errors); err != nil {
		return err
	}

	if i, err := strconv.Atoi(errors[0].Status); err != nil {
		return err
	} else {
		return c.Blob(i, jsonapi.MediaType, b.Bytes())
	}
}

func valuesToApiError(status int, title string, detail *interface{}, code string) *jsonapi.ErrorObject {
	var d string
	if *detail != nil {
		d = fmt.Sprint(*detail)
	}
	return &jsonapi.ErrorObject{
		Status: fmt.Sprintf("%d", status),
		Title:  title,
		Detail: d,
		Code:   code,
	}
}
<commit_msg>one last fix<commit_after>package web

import (
	"bytes"
	"fmt"
	"net/http"
	"strconv"

	"github.com/asaskevich/govalidator"
	"github.com/eyecuelab/kit/log"
	"github.com/google/jsonapi"
	"github.com/labstack/echo"
	"github.com/lib/pq"
)

var pq500s = map[string]bool{
	"undefined_function": true,
}

func ErrorHandler(err error, c echo.Context) {
	if c.Response().Committed {
		return
	}

	status, apiError := toApiError(err)

	if c.Request().Method == "HEAD" {
		if err := c.NoContent(status); err != nil {
			goto ERROR
		}
		return
	}

	if err := renderApiErrors(c, apiError); err != nil {
		//FIXME: are we supposed to log this error twice?
		logErr(err)
		goto ERROR
	}

	if status < 500 {
		return
	}
ERROR: //FIXME - I feel like we should justify a GOTO
	logErr(err)
}

func logErr(err error) {
	log.ErrorWrap(err, "Uncaught Error")
}

func toApiError(err error) (status int, apiErr *jsonapi.ErrorObject) {

	var (
		detail interface{}
		code   string
	)
	status = http.StatusInternalServerError
	switch err := err.(type) {
	case *jsonapi.ErrorObject:
		status, _ = strconv.Atoi(err.Status)
		return status, err

	case *echo.HTTPError:
		status, detail = err.Code, err.Message
	case *pq.Error:
		detail = err.Message
		code = err.Code.Name()
		if _, ok := !pq500s[code]; !ok {
			status = http.StatusBadRequest
		}
	case govalidator.Errors:
		status, detail = http.StatusBadRequest, err.Error()
	default:
		detail = err.Error()

	}

	return status, valuesToApiError(status, http.StatusText(status), &detail, code)
}

func renderApiErrors(c echo.Context, errors ...*jsonapi.ErrorObject) error {
	var b bytes.Buffer
	if err := jsonapi.MarshalErrors(&b, errors); err != nil {
		return err
	}

	if i, err := strconv.Atoi(errors[0].Status); err != nil {
		return err
	} else {
		return c.Blob(i, jsonapi.MediaType, b.Bytes())
	}
}

func valuesToApiError(status int, title string, detail *interface{}, code string) *jsonapi.ErrorObject {
	var d string
	if *detail != nil {
		d = fmt.Sprint(*detail)
	}
	return &jsonapi.ErrorObject{
		Status: fmt.Sprintf("%d", status),
		Title:  title,
		Detail: d,
		Code:   code,
	}
}
<|endoftext|>