<commit_before>// Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements;
// and to You under the Apache License, Version 2.0.  See LICENSE in project root for full license + copyright.

package keynuker

import (
	"context"
	"fmt"

	f "github.com/fauna/faunadb-go/faunadb"
	"github.com/go-kivik/kivik"

	_ "github.com/go-kivik/couchdb" // The CouchDB driver

	"strings"
	"log"
)

// Write an object specified in params to the underlying database, and return the
// written object back.
func WriteDocToDb(params ParamsWriteDoc) (interface{}, error) {

	switch {
	case params.IsCloudantDb():
		return WriteDocToCloudant(params)
	case params.IsFaunaDb():
		return WriteDocToFauna(params)
	default:
		return nil, fmt.Errorf("Unrecognized DB host: %v", params.Host)
	}

}

func CreateDBClient(params ParamsWriteDoc) (db *kivik.DB, err error) {

	ctx := context.TODO()

	// NOTE regarding http vs https.  I was previously using https, but I needed to revert to http
	// due to the following issue w/ Cloudant: https://gist.github.com/tleyden/d8c69f6cee3a2b32a7a1609539a1dade (filed to Cloudant support)
	dataSourceName := fmt.Sprintf(
		"http://%s:%s@%s",
		params.Username,
		params.Password,
		params.Host,
	)

	client, err := kivik.New(ctx, "couch", dataSourceName)
	if err != nil {
		return nil, err
	}

	return client.DB(ctx, params.DbName)

}

func WriteDocToCloudant(params ParamsWriteDoc) (interface{}, error) {

	ctx := context.TODO()

	db, err := CreateDBClient(params)
	if err != nil {
		return nil, err
	}

	// After maxTries, give up.. this far too many CAS errors than expected under normal operations
	maxTries := 100
	numTries := 0
	var lastErr error

	// Cas loop where we get the latest rev of the doc
	for {

		if numTries >= maxTries {
			return nil, fmt.Errorf("Giving up after %d tries.  Last error: %v", numTries, lastErr)
		}

		numTries++

		fetchedDocRow := db.Get(ctx, params.DocId)

		// Try to get existing doc
		fetchedDoc := map[string]interface{}{}
		scanDocErr := fetchedDocRow.ScanDoc(&fetchedDoc)

		if scanDocErr != nil {
			// Assume this will be the first rev of the doc, so do nothing in this case
		} else {
			// Got an existing doc, update the doc being inserted to be based on this rev
			// we had a valid previous rev
			revRaw, ok := fetchedDoc["_rev"]
			if !ok {
				return nil, fmt.Errorf("Doc does not have _rev field.  Doc: %+v", fetchedDoc)
			}
			rev := revRaw.(string)
			params.Doc["_rev"] = rev
		}

		_, err = db.Put(context.TODO(), params.DocId, params.Doc)
		if err != nil {
			// Assume this is a 409 conflict error
			// TODO: check error status and act accordingly, otherwise will end up in toxic busy loop
			log.Printf("Error putting doc %v into db.  Err: %v.  Assuming 409 conflict error, retrying", params.DocId, err)
			lastErr = err
			continue
		}

		break

	}

	// Read the doc back from the DB
	fetchedDocRow := db.Get(ctx, params.DocId)
	fetchedDoc := map[string]interface{}{}
	scanDocErr := fetchedDocRow.ScanDoc(&fetchedDoc)
	if scanDocErr != nil {
		return nil, scanDocErr
	}

	return fetchedDoc, nil

}

func DeleteDoc(params ParamsWriteDoc, rev string) (newRev string, err error) {

	ctx := context.TODO()

	db, err := CreateDBClient(params)
	if err != nil {
		return "", err
	}

	return db.Delete(ctx, params.DocId, rev)

}

type ParamsWriteDoc struct {
	Username string
	Password string
	Host     string
	DbName   string
	Doc      map[string]interface{}
	DocId    string
}

func (p ParamsWriteDoc) IsCloudantDb() bool {
	return strings.Contains(p.Host, "cloudant")
}

func (p ParamsWriteDoc) IsFaunaDb() bool {
	return strings.Contains(p.Host, "fauna")
}

// Experimenting w/ FaunaDB

var (
	data = f.ObjKey("data")
	ref  = f.ObjKey("ref")
)

func WriteDocToFauna(params ParamsWriteDoc) (interface{}, error) {

	client := f.NewFaunaClient(params.Password)

	// Concats a string .. just testing
	res, err := client.Query(f.Concat([]string{"Hello", "World"}))
	if err != nil {
		panic(err)
	}
	fmt.Println(res)

	// TODO: how do I lazily create a class if it doesn't already exist?  Just try it and ignore 400 error?
	//val, err := client.Query(f.CreateClass(f.Obj{"name": params.DocId}))
	//if err != nil {
	//	return nil, err
	//}

	val, err := client.Query(
		f.Create(
			f.Class(params.DocId),
			f.Obj{"data": f.Obj(params.Doc)},
		),
	)

	if err != nil {
		return nil, err
	}

	fmt.Printf("Val: %v\n", val)

	// TODO: I want to read the doc back out of the db, how do I get the ref?

	// Read the doc back
	val, err = client.Query(f.Get(f.Ref("classes/TestDoc/172286141322494465")))
	if err != nil {
		return nil, err
	}

	readTestDoc := map[string]interface{}{}
	//err = val.Get(&readTestDoc)
	//if err != nil {
	//	return nil, err
	//}

	_ = val.At(data).Get(&readTestDoc)

	// fmt.Printf("readTestDoc: %+v", readTestDoc)

	readTestDoc2 := f.ObjectV{}
	_ = val.At(data).Get(&readTestDoc2)

	readTestDoc2Bytes, err := readTestDoc2.MarshalJSON()
	if err != nil {
		return nil, err
	}
	fmt.Printf("readTestDoc2Bytes: %v", string(readTestDoc2Bytes))

	return readTestDoc, nil
}
<commit_msg>Switch to https by default<commit_after>// Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements;
// and to You under the Apache License, Version 2.0.  See LICENSE in project root for full license + copyright.

package keynuker

import (
	"context"
	"fmt"

	f "github.com/fauna/faunadb-go/faunadb"
	"github.com/go-kivik/kivik"

	_ "github.com/go-kivik/couchdb" // The CouchDB driver

	"strings"
	"log"
)

// Write an object specified in params to the underlying database, and return the
// written object back.
func WriteDocToDb(params ParamsWriteDoc) (interface{}, error) {

	switch {
	case params.IsCloudantDb():
		return WriteDocToCloudant(params)
	case params.IsFaunaDb():
		return WriteDocToFauna(params)
	default:
		return nil, fmt.Errorf("Unrecognized DB host: %v", params.Host)
	}

}

func CreateDBClient(params ParamsWriteDoc) (db *kivik.DB, err error) {

	ctx := context.TODO()

	// NOTE regarding http vs https.  I was previously using https, but I needed to revert to http
	// due to the following issue w/ Cloudant: https://gist.github.com/tleyden/d8c69f6cee3a2b32a7a1609539a1dade (filed to Cloudant support)
	dataSourceName := fmt.Sprintf(
		"https://%s:%s@%s",
		params.Username,
		params.Password,
		params.Host,
	)

	client, err := kivik.New(ctx, "couch", dataSourceName)
	if err != nil {
		return nil, err
	}

	return client.DB(ctx, params.DbName)

}

func WriteDocToCloudant(params ParamsWriteDoc) (interface{}, error) {

	ctx := context.TODO()

	db, err := CreateDBClient(params)
	if err != nil {
		return nil, err
	}

	// After maxTries, give up.. this far too many CAS errors than expected under normal operations
	maxTries := 100
	numTries := 0
	var lastErr error

	// Cas loop where we get the latest rev of the doc
	for {

		if numTries >= maxTries {
			return nil, fmt.Errorf("Giving up after %d tries.  Last error: %v", numTries, lastErr)
		}

		numTries++

		fetchedDocRow := db.Get(ctx, params.DocId)

		// Try to get existing doc
		fetchedDoc := map[string]interface{}{}
		scanDocErr := fetchedDocRow.ScanDoc(&fetchedDoc)

		if scanDocErr != nil {
			// Assume this will be the first rev of the doc, so do nothing in this case
		} else {
			// Got an existing doc, update the doc being inserted to be based on this rev
			// we had a valid previous rev
			revRaw, ok := fetchedDoc["_rev"]
			if !ok {
				return nil, fmt.Errorf("Doc does not have _rev field.  Doc: %+v", fetchedDoc)
			}
			rev := revRaw.(string)
			params.Doc["_rev"] = rev
		}

		_, err = db.Put(context.TODO(), params.DocId, params.Doc)
		if err != nil {
			// Assume this is a 409 conflict error
			// TODO: check error status and act accordingly, otherwise will end up in toxic busy loop
			log.Printf("Error putting doc %v into db.  Err: %v.  Assuming 409 conflict error, retrying", params.DocId, err)
			lastErr = err
			continue
		}

		break

	}

	// Read the doc back from the DB
	fetchedDocRow := db.Get(ctx, params.DocId)
	fetchedDoc := map[string]interface{}{}
	scanDocErr := fetchedDocRow.ScanDoc(&fetchedDoc)
	if scanDocErr != nil {
		return nil, scanDocErr
	}

	return fetchedDoc, nil

}

func DeleteDoc(params ParamsWriteDoc, rev string) (newRev string, err error) {

	ctx := context.TODO()

	db, err := CreateDBClient(params)
	if err != nil {
		return "", err
	}

	return db.Delete(ctx, params.DocId, rev)

}

type ParamsWriteDoc struct {
	Username string
	Password string
	Host     string
	DbName   string
	Doc      map[string]interface{}
	DocId    string
}

func (p ParamsWriteDoc) IsCloudantDb() bool {
	return strings.Contains(p.Host, "cloudant")
}

func (p ParamsWriteDoc) IsFaunaDb() bool {
	return strings.Contains(p.Host, "fauna")
}

// Experimenting w/ FaunaDB

var (
	data = f.ObjKey("data")
	ref  = f.ObjKey("ref")
)

func WriteDocToFauna(params ParamsWriteDoc) (interface{}, error) {

	client := f.NewFaunaClient(params.Password)

	// Concats a string .. just testing
	res, err := client.Query(f.Concat([]string{"Hello", "World"}))
	if err != nil {
		panic(err)
	}
	fmt.Println(res)

	// TODO: how do I lazily create a class if it doesn't already exist?  Just try it and ignore 400 error?
	//val, err := client.Query(f.CreateClass(f.Obj{"name": params.DocId}))
	//if err != nil {
	//	return nil, err
	//}

	val, err := client.Query(
		f.Create(
			f.Class(params.DocId),
			f.Obj{"data": f.Obj(params.Doc)},
		),
	)

	if err != nil {
		return nil, err
	}

	fmt.Printf("Val: %v\n", val)

	// TODO: I want to read the doc back out of the db, how do I get the ref?

	// Read the doc back
	val, err = client.Query(f.Get(f.Ref("classes/TestDoc/172286141322494465")))
	if err != nil {
		return nil, err
	}

	readTestDoc := map[string]interface{}{}
	//err = val.Get(&readTestDoc)
	//if err != nil {
	//	return nil, err
	//}

	_ = val.At(data).Get(&readTestDoc)

	// fmt.Printf("readTestDoc: %+v", readTestDoc)

	readTestDoc2 := f.ObjectV{}
	_ = val.At(data).Get(&readTestDoc2)

	readTestDoc2Bytes, err := readTestDoc2.MarshalJSON()
	if err != nil {
		return nil, err
	}
	fmt.Printf("readTestDoc2Bytes: %v", string(readTestDoc2Bytes))

	return readTestDoc, nil
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"io"
	"os"
	"os/signal"
	"strings"
	"time"

	"github.com/gorilla/websocket"
	"gopkg.in/readline.v1"
)

var (
	VERSION = "" // filled in by build

	showVersion = flag.Bool("version", false, "show version number and exit")
	verbose     = flag.Bool("v", false, "verbose output")
	useTsPrefix = flag.Bool("ts-prefix", true, "timestamp prefix")
)

func main() {
	flag.Parse()

	if *showVersion || *verbose || len(os.Args) < 2 {
		fmt.Printf("ws-client %s \n", VERSION)
		fmt.Println("https://github.com/oliver006/ws-client/")
		fmt.Println()
		if *showVersion {
			os.Exit(0)
		}
	}

	if len(os.Args) < 2 {
		fmt.Println("Usage:")
		fmt.Println("  ws-client <<ws:// or wss:// URL>>")
		os.Exit(-1)
	}

	addr := os.Args[len(os.Args)-1]
	if !strings.HasPrefix(addr, "ws://") && !strings.HasPrefix(addr, "wss://") {
		addr = "ws://" + addr
	}

	if *verbose {
		fmt.Printf("connecting to %s\n", addr)
	}
	c, _, err := websocket.DefaultDialer.Dial(addr, nil)
	if err != nil {
		fmt.Println(err)
		os.Exit(-1)
	}
	defer c.Close()
	fmt.Printf("connected to  %s\n", addr)

	interrupt := make(chan os.Signal, 1)
	signal.Notify(interrupt, os.Interrupt)

	rl, err := readline.NewEx(&readline.Config{
		Prompt: "\033[32m»\033[0m ",
	})
	if err != nil {
		panic(err)
	}

	defer rl.Close()

	if *useTsPrefix {
		tsStr := time.Now().Format("[15:04] ")
		rl.SetPrompt(fmt.Sprintf("%s\033[32m»\033[0m ", tsStr))
		go func() {
			c := time.Tick(30 * time.Second)
			for now := range c {
				tsStr := now.Format("[15:04] ")
				rl.SetPrompt(fmt.Sprintf("%s\033[32m»\033[0m ", tsStr))
				rl.Refresh()
			}
		}()
	}
	go func() {
		for {
			_, message, err := c.ReadMessage()
			if err != nil {
				fmt.Printf("<<server: %s>>\n", err)
				close(interrupt)
				return
			}
			tsStr := ""

			if *useTsPrefix {
				tsStr = time.Now().Format("[15:04] ")
			}
			io.WriteString(rl.Stdout(), fmt.Sprintf("%s\033[31m«\033[0m %s\n", tsStr, message))
		}
	}()

	go func() {
		for {
			line, err := rl.Readline()
			if err == readline.ErrInterrupt {
				interrupt <- os.Interrupt
				return
			} else if err != nil {
				close(interrupt)
				return
			}
			if len(line) == 0 {
				continue
			}
			err = c.WriteMessage(websocket.TextMessage, []byte(line))
			if err != nil {
				fmt.Println("err:", err)
				return
			}
		}
	}()

	select {
	case <-interrupt:
		c.WriteMessage(websocket.CloseMessage, websocket.FormatCloseMessage(websocket.CloseNormalClosure, ""))
		fmt.Println("<<client: sent websocket close frame>>")
		c.Close()
		os.Exit(0)
	}
}
<commit_msg>dummy test<commit_after>package main

import (
	"flag"
	"fmt"
	"io"
	"os"
	"os/signal"
	"strings"
	"time"

	"github.com/gorilla/websocket"
	"gopkg.in/readline.v1"
)

var (
	VERSION = "// filled in by build //"

	showVersion = flag.Bool("version", false, "show version number and exit")
	verbose     = flag.Bool("v", false, "verbose output")
	useTsPrefix = flag.Bool("ts-prefix", true, "timestamp prefix")
)

func main() {
	flag.Parse()

	if *showVersion || *verbose || len(os.Args) < 2 {
		fmt.Printf("ws-client %s \n", VERSION)
		fmt.Println("https://github.com/oliver006/ws-client/")
		fmt.Println()
		if *showVersion {
			os.Exit(0)
		}
	}

	if len(os.Args) < 2 {
		fmt.Println("Usage:")
		fmt.Println("  ws-client <<ws:// or wss:// URL>>")
		os.Exit(-1)
	}

	addr := os.Args[len(os.Args)-1]
	if !strings.HasPrefix(addr, "ws://") && !strings.HasPrefix(addr, "wss://") {
		addr = "ws://" + addr
	}

	if *verbose {
		fmt.Printf("connecting to %s\n", addr)
	}
	c, _, err := websocket.DefaultDialer.Dial(addr, nil)
	if err != nil {
		fmt.Println(err)
		os.Exit(-1)
	}
	defer c.Close()
	fmt.Printf("connected to  %s\n", addr)

	interrupt := make(chan os.Signal, 1)
	signal.Notify(interrupt, os.Interrupt)

	rl, err := readline.NewEx(&readline.Config{
		Prompt: "\033[32m»\033[0m ",
	})
	if err != nil {
		panic(err)
	}

	defer rl.Close()

	if *useTsPrefix {
		tsStr := time.Now().Format("[15:04] ")
		rl.SetPrompt(fmt.Sprintf("%s\033[32m»\033[0m ", tsStr))
		go func() {
			c := time.Tick(30 * time.Second)
			for now := range c {
				tsStr := now.Format("[15:04] ")
				rl.SetPrompt(fmt.Sprintf("%s\033[32m»\033[0m ", tsStr))
				rl.Refresh()
			}
		}()
	}
	go func() {
		for {
			_, message, err := c.ReadMessage()
			if err != nil {
				fmt.Printf("<<server: %s>>\n", err)
				close(interrupt)
				return
			}
			tsStr := ""

			if *useTsPrefix {
				tsStr = time.Now().Format("[15:04] ")
			}
			io.WriteString(rl.Stdout(), fmt.Sprintf("%s\033[31m«\033[0m %s\n", tsStr, message))
		}
	}()

	go func() {
		for {
			line, err := rl.Readline()
			if err == readline.ErrInterrupt {
				interrupt <- os.Interrupt
				return
			} else if err != nil {
				close(interrupt)
				return
			}
			if len(line) == 0 {
				continue
			}
			err = c.WriteMessage(websocket.TextMessage, []byte(line))
			if err != nil {
				fmt.Println("err:", err)
				return
			}
		}
	}()

	select {
	case <-interrupt:
		c.WriteMessage(websocket.CloseMessage, websocket.FormatCloseMessage(websocket.CloseNormalClosure, ""))
		fmt.Println("<<client: sent websocket close frame>>")
		c.Close()
		os.Exit(0)
	}
}
<|endoftext|>


<commit_before>/*
Package xlog provides a Logger interface and provides an implememntation of
this interface that keeps quiet.

A possibility would be to ioutil.Discard, but this would imply the cost of
formating the messages.

The Logger interface provides all methods that makes sense for a debug logger.

The glog package, full path github.com/golang/glog, provides more functionality
but depends on flag.Parse() to be called. This is not what I need for simple
debugging of test functions.
*/
package xlog

import "log"

// We use this interface to handle a logger.
type Logger interface {
	Print(v ...interface{})
	Printf(format string, v ...interface{})
	Println(v ...interface{})
	SetFlags(flags int)
	SetPrefix(prefix string)
	Flags() int
	Prefix() string
}

// A logger that keeps quiet.
var Quiet = &xLogger{flags: log.LstdFlags}

// xLogger is a logger that does nothing.
type xLogger struct {
	flags  int
	prefix string
}

func (x *xLogger) Flags() int                             { return x.flags }
func (x *xLogger) Prefix() string                         { return x.prefix }
func (x *xLogger) Print(v ...interface{})                 {}
func (x *xLogger) Printf(format string, v ...interface{}) {}
func (x *xLogger) Println(v ...interface{})               {}
func (x *xLogger) SetFlags(flags int)                     { x.flags = flags }
func (x *xLogger) SetPrefix(prefix string)                { x.prefix = prefix }
<commit_msg>xlog: added new package xlog<commit_after>package xlog

import (
	"fmt"
	"io"
	"os"
	"runtime"
	"sync"
	"time"
)

const (
	Ldate = 1 << iota
	Ltime
	Lmicroseconds
	Llongfile
	Lshortfile
	Lnopanic
	Lnofatal
	Lnowarn
	Lnoprint
	Lnodebug
	Lstdflags = Ldate | Ltime
)

type Logger struct {
	mu     sync.Mutex
	prefix string
	flag   int
	out    io.Writer
	buf    []byte
}

func New(out io.Writer, prefix string, flag int) *Logger {
	return &Logger{out: out, prefix: prefix, flag: flag}
}

var std = New(os.Stderr, "", Lstdflags)

func itoa(buf *[]byte, i int, wid int) {
	var u uint = uint(i)
	if u == 0 && wid <= 1 {
		*buf = append(*buf, '0')
		return
	}
	var b [32]byte
	bp := len(b)
	for ; u > 0 || wid > 0; u /= 10 {
		bp--
		wid--
		b[bp] = byte(u%10) + '0'
	}
	*buf = append(*buf, b[bp:]...)
}

func (l *Logger) formatHeader(t time.Time, file string, line int) {
	l.buf = append(l.buf, l.prefix...)
	if l.flag&(Ldate|Ltime|Lmicroseconds) != 0 {
		if l.flag&Ldate != 0 {
			year, month, day := t.Date()
			itoa(&l.buf, year, 4)
			l.buf = append(l.buf, '-')
			itoa(&l.buf, int(month), 2)
			l.buf = append(l.buf, '-')
			itoa(&l.buf, day, 2)
			l.buf = append(l.buf, ' ')
		}
		if l.flag&(Ltime|Lmicroseconds) != 0 {
			hour, min, sec := t.Clock()
			itoa(&l.buf, hour, 2)
			l.buf = append(l.buf, ':')
			itoa(&l.buf, min, 2)
			l.buf = append(l.buf, ':')
			itoa(&l.buf, sec, 2)
			if l.flag&Lmicroseconds != 0 {
				l.buf = append(l.buf, '.')
				itoa(&l.buf, t.Nanosecond()/1e3, 6)
			}
			l.buf = append(l.buf, ' ')
		}
	}
	if l.flag&(Lshortfile|Llongfile) != 0 {
		if l.flag&Lshortfile != 0 {
			short := file
			for i := len(file) - 1; i > 0; i-- {
				if file[i] == '/' {
					short = file[i+1:]
					break
				}
			}
			file = short
		}
		l.buf = append(l.buf, file...)
		l.buf = append(l.buf, ':')
		itoa(&l.buf, line, -1)
		l.buf = append(l.buf, ": "...)
	}
}

func (l *Logger) Output(calldepth int, s string) error {
	now := time.Now()
	var file string
	var line int
	l.mu.Lock()
	defer l.mu.Unlock()
	if l.flag&(Lshortfile|Llongfile) != 0 {
		l.mu.Unlock()
		var ok bool
		_, file, line, ok = runtime.Caller(calldepth)
		if !ok {
			file = "???"
			line = 0
		}
		l.mu.Lock()
	}
	l.buf = l.buf[:0]
	l.formatHeader(now, file, line)
	l.buf = append(l.buf, s...)
	if len(s) == 0 || s[len(s)-1] != '\n' {
		l.buf = append(l.buf, '\n')
	}
	_, err := l.out.Write(l.buf)
	return err
}

func (l *Logger) Panic(v ...interface{}) {
	s := fmt.Sprint(v...)
	// no need for locking because integer access is atomic
	if l.flag&Lnopanic == 0 {
		l.Output(2, s)
	}
	panic(s)
}

func Panic(v ...interface{}) {
	s := fmt.Sprint(v...)
	// no need for locking because integer access is atomic
	if std.flag&Lnopanic == 0 {
		std.Output(2, s)
	}
	panic(s)
}

func (l *Logger) Panicf(format string, v ...interface{}) {
	s := fmt.Sprintf(format, v...)
	if l.flag&Lnopanic == 0 {
		l.Output(2, s)
	}
	panic(s)
}

func Panicf(format string, v ...interface{}) {
	s := fmt.Sprintf(format, v...)
	if std.flag&Lnopanic == 0 {
		std.Output(2, s)
	}
	panic(s)
}

func (l *Logger) Panicln(v ...interface{}) {
	s := fmt.Sprintln(v...)
	if l.flag&Lnopanic == 0 {
		l.Output(2, s)
	}
	panic(s)
}

func Panicln(v ...interface{}) {
	s := fmt.Sprintln(v...)
	if std.flag&Lnopanic == 0 {
		std.Output(2, s)
	}
	panic(s)
}

func (l *Logger) Fatal(v ...interface{}) {
	if l.flag&Lnofatal == 0 {
		l.Output(2, fmt.Sprint(v...))
	}
	os.Exit(1)
}

func Fatal(v ...interface{}) {
	if std.flag&Lnofatal == 0 {
		std.Output(2, fmt.Sprint(v...))
	}
	os.Exit(1)
}

func (l *Logger) Fatalf(format string, v ...interface{}) {
	if l.flag&Lnofatal == 0 {
		l.Output(2, fmt.Sprintf(format, v...))
	}
	os.Exit(1)
}

func Fatalf(format string, v ...interface{}) {
	if std.flag&Lnofatal == 0 {
		std.Output(2, fmt.Sprintf(format, v...))
	}
	os.Exit(1)
}

func (l *Logger) Fatalln(format string, v ...interface{}) {
	if l.flag&Lnofatal == 0 {
		l.Output(2, fmt.Sprintln(v...))
	}
	os.Exit(1)
}

func Fatalln(format string, v ...interface{}) {
	if std.flag&Lnofatal == 0 {
		std.Output(2, fmt.Sprintln(v...))
	}
	os.Exit(1)
}

func (l *Logger) Warn(v ...interface{}) {
	if l.flag&Lnowarn == 0 {
		l.Output(2, fmt.Sprint(v...))
	}
}

func Warn(v ...interface{}) {
	if std.flag&Lnowarn == 0 {
		std.Output(2, fmt.Sprint(v...))
	}
}

func (l *Logger) Warnf(format string, v ...interface{}) {
	if l.flag&Lnowarn == 0 {
		l.Output(2, fmt.Sprintf(format, v...))
	}
}

func Warnf(format string, v ...interface{}) {
	if std.flag&Lnowarn == 0 {
		std.Output(2, fmt.Sprintf(format, v...))
	}
}

func (l *Logger) Warnln(v ...interface{}) {
	if l.flag&Lnowarn == 0 {
		l.Output(2, fmt.Sprintln(v...))
	}
}

func Warnln(v ...interface{}) {
	if std.flag&Lnowarn == 0 {
		std.Output(2, fmt.Sprintln(v...))
	}
}

func (l *Logger) Print(v ...interface{}) {
	if l.flag&Lnoprint == 0 {
		l.Output(2, fmt.Sprint(v...))
	}
}

func Print(v ...interface{}) {
	if std.flag&Lnoprint == 0 {
		std.Output(2, fmt.Sprint(v...))
	}
}

func (l *Logger) Printf(format string, v ...interface{}) {
	if l.flag&Lnoprint == 0 {
		l.Output(2, fmt.Sprintf(format, v...))
	}
}

func Printf(format string, v ...interface{}) {
	if std.flag&Lnoprint == 0 {
		std.Output(2, fmt.Sprintf(format, v...))
	}
}

func (l *Logger) Println(v ...interface{}) {
	if l.flag&Lnoprint == 0 {
		l.Output(2, fmt.Sprintln(v...))
	}
}

func Println(v ...interface{}) {
	if std.flag&Lnoprint == 0 {
		std.Output(2, fmt.Sprintln(v...))
	}
}

func (l *Logger) Debug(v ...interface{}) {
	if l.flag&Lnodebug == 0 {
		l.Output(2, fmt.Sprint(v...))
	}
}

func Debug(v ...interface{}) {
	if std.flag&Lnodebug == 0 {
		std.Output(2, fmt.Sprint(v...))
	}
}

func (l *Logger) Debugf(format string, v ...interface{}) {
	if l.flag&Lnodebug == 0 {
		l.Output(2, fmt.Sprintf(format, v...))
	}
}

func Debugf(format string, v ...interface{}) {
	if std.flag&Lnodebug == 0 {
		std.Output(2, fmt.Sprintf(format, v...))
	}
}

func (l *Logger) Debugln(v ...interface{}) {
	if l.flag&Lnodebug == 0 {
		l.Output(2, fmt.Sprintln(v...))
	}
}

func Debugln(v ...interface{}) {
	if std.flag&Lnodebug == 0 {
		std.Output(2, fmt.Sprintln(v...))
	}
}

func (l *Logger) Flags() int {
	// access to an int int is always atomic
	return l.flag
}

func Flags() int {
	// access to an int int is always atomic
	return std.flag
}

func (l *Logger) SetFlags(flag int) {
	l.flag = flag
}

func SetFlags(flag int) {
	std.flag = flag
}

func (l *Logger) Prefix() string {
	l.mu.Lock()
	defer l.mu.Unlock()
	return l.prefix
}

func Prefix() string {
	return std.Prefix()
}

func (l *Logger) SetPrefix(prefix string) {
	l.mu.Lock()
	defer l.mu.Unlock()
	l.prefix = prefix
}

func SetPrefix(prefix string) {
	std.SetPrefix(prefix)
}

func (l *Logger) SetOutput(w io.Writer) {
	l.mu.Lock()
	defer l.mu.Unlock()
	l.out = w
}

func SetOutput(w io.Writer) {
	std.SetOutput(w)
}
<|endoftext|>


<commit_before>// Copyright 2020 Google LLC
//
// 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 storage

import (
	"context"
	"errors"
	"io"
	"net/url"
	"testing"

	"golang.org/x/xerrors"

	"google.golang.org/api/googleapi"
)

func TestInvoke(t *testing.T) {
	t.Parallel()
	ctx := context.Background()
	// Time-based tests are flaky. We just make sure that invoke eventually
	// returns with the right error.

	for _, test := range []struct {
		count             int   // Number of times to return retryable error.
		initialErr        error // Error to return initially.
		finalErr          error // Error to return after count returns of retryCode.
		retry             *retryConfig
		isIdempotentValue bool
		expectFinalErr    bool
	}{
		{
			count:             0,
			initialErr:        &googleapi.Error{Code: 0},
			finalErr:          nil,
			isIdempotentValue: true,
			expectFinalErr:    true,
		},
		{
			count:             0,
			initialErr:        &googleapi.Error{Code: 0},
			finalErr:          errors.New("foo"),
			isIdempotentValue: true,
			expectFinalErr:    true,
		},
		{
			count:             1,
			initialErr:        &googleapi.Error{Code: 429},
			finalErr:          nil,
			isIdempotentValue: true,
			expectFinalErr:    true,
		},
		{
			count:             1,
			initialErr:        &googleapi.Error{Code: 429},
			finalErr:          errors.New("bar"),
			isIdempotentValue: true,
			expectFinalErr:    true,
		},
		{
			count:             2,
			initialErr:        &googleapi.Error{Code: 518},
			finalErr:          nil,
			isIdempotentValue: true,
			expectFinalErr:    true,
		},
		{
			count:             2,
			initialErr:        &googleapi.Error{Code: 599},
			finalErr:          &googleapi.Error{Code: 428},
			isIdempotentValue: true,
			expectFinalErr:    true,
		},
		{
			count:             1,
			initialErr:        &url.Error{Op: "blah", URL: "blah", Err: errors.New("connection refused")},
			finalErr:          nil,
			isIdempotentValue: true,
			expectFinalErr:    true,
		},
		{
			count:             1,
			initialErr:        io.ErrUnexpectedEOF,
			finalErr:          nil,
			isIdempotentValue: true,
			expectFinalErr:    true,
		},
		{
			count:             1,
			initialErr:        xerrors.Errorf("Test unwrapping of a temporary error: %w", &googleapi.Error{Code: 500}),
			finalErr:          nil,
			isIdempotentValue: true,
			expectFinalErr:    true,
		},
		{
			count:             0,
			initialErr:        xerrors.Errorf("Test unwrapping of a non-retriable error: %w", &googleapi.Error{Code: 400}),
			finalErr:          &googleapi.Error{Code: 400},
			isIdempotentValue: true,
			expectFinalErr:    true,
		},
	} {
		t.Run("", func(s *testing.T) {
			counter := 0
			call := func() error {
				counter++
				if counter <= test.count {
					return test.initialErr
				}
				return test.finalErr
			}
			got := run(ctx, call, test.retry, test.isIdempotentValue)
			if got != test.finalErr {
				s.Errorf("%+v: got %v, want %v", test, got, test.finalErr)
			}
		})
	}
}
<commit_msg>test(storage): fill out invoke tests (#5301)<commit_after>// Copyright 2020 Google LLC
//
// 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 storage

import (
	"context"
	"errors"
	"io"
	"net/url"
	"testing"

	"golang.org/x/xerrors"

	"google.golang.org/api/googleapi"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/status"
)

func TestInvoke(t *testing.T) {
	t.Parallel()
	ctx := context.Background()
	// Time-based tests are flaky. We just make sure that invoke eventually
	// returns with the right error.

	for _, test := range []struct {
		desc              string
		count             int   // Number of times to return retryable error.
		initialErr        error // Error to return initially.
		finalErr          error // Error to return after count returns of retryCode.
		retry             *retryConfig
		isIdempotentValue bool
		expectFinalErr    bool
	}{
		{
			desc:              "test fn never returns initial error with count=0",
			count:             0,
			initialErr:        &googleapi.Error{Code: 0}, //non-retryable
			finalErr:          nil,
			isIdempotentValue: true,
			expectFinalErr:    true,
		},
		{
			desc:              "non-retryable error is returned without retrying",
			count:             1,
			initialErr:        &googleapi.Error{Code: 0},
			finalErr:          nil,
			isIdempotentValue: true,
			expectFinalErr:    false,
		},
		{
			desc:              "retryable error is retried",
			count:             1,
			initialErr:        &googleapi.Error{Code: 429},
			finalErr:          nil,
			isIdempotentValue: true,
			expectFinalErr:    true,
		},
		{
			desc:              "returns non-retryable error after retryable error",
			count:             1,
			initialErr:        &googleapi.Error{Code: 429},
			finalErr:          errors.New("bar"),
			isIdempotentValue: true,
			expectFinalErr:    true,
		},
		{
			desc:              "retryable 5xx error is retried",
			count:             2,
			initialErr:        &googleapi.Error{Code: 518},
			finalErr:          nil,
			isIdempotentValue: true,
			expectFinalErr:    true,
		},
		{
			desc:              "retriable error not retried when non-idempotent",
			count:             2,
			initialErr:        &googleapi.Error{Code: 599},
			finalErr:          nil,
			isIdempotentValue: false,
			expectFinalErr:    false,
		},
		{

			desc:              "non-idempotent retriable error retried when policy is RetryAlways",
			count:             2,
			initialErr:        &googleapi.Error{Code: 500},
			finalErr:          nil,
			isIdempotentValue: false,
			retry:             &retryConfig{policy: RetryAlways},
			expectFinalErr:    true,
		},
		{
			desc:              "retriable error not retried when policy is RetryNever",
			count:             2,
			initialErr:        &url.Error{Op: "blah", URL: "blah", Err: errors.New("connection refused")},
			finalErr:          nil,
			isIdempotentValue: true,
			retry:             &retryConfig{policy: RetryNever},
			expectFinalErr:    false,
		},
		{
			desc:              "non-retriable error not retried when policy is RetryAlways",
			count:             2,
			initialErr:        xerrors.Errorf("non-retriable error: %w", &googleapi.Error{Code: 400}),
			finalErr:          nil,
			isIdempotentValue: true,
			retry:             &retryConfig{policy: RetryAlways},
			expectFinalErr:    false,
		},

		{
			desc:              "non-retriable error retried with custom fn",
			count:             2,
			initialErr:        io.ErrNoProgress,
			finalErr:          nil,
			isIdempotentValue: true,
			retry: &retryConfig{
				shouldRetry: func(err error) bool {
					return err == io.ErrNoProgress
				},
			},
			expectFinalErr: true,
		},
		{
			desc:              "retriable error not retried with custom fn",
			count:             2,
			initialErr:        io.ErrUnexpectedEOF,
			finalErr:          nil,
			isIdempotentValue: true,
			retry: &retryConfig{
				shouldRetry: func(err error) bool {
					return err == io.ErrNoProgress
				},
			},
			expectFinalErr: false,
		},
		{
			desc:              "error not retried when policy is RetryNever despite custom fn",
			count:             2,
			initialErr:        io.ErrUnexpectedEOF,
			finalErr:          nil,
			isIdempotentValue: true,
			retry: &retryConfig{
				shouldRetry: func(err error) bool {
					return err == io.ErrUnexpectedEOF
				},
				policy: RetryNever,
			},
			expectFinalErr: false,
		},
	} {
		t.Run(test.desc, func(s *testing.T) {
			counter := 0
			call := func() error {
				counter++
				if counter <= test.count {
					return test.initialErr
				}
				return test.finalErr
			}
			got := run(ctx, call, test.retry, test.isIdempotentValue)
			if test.expectFinalErr && got != test.finalErr {
				s.Errorf("got %v, want %v", got, test.finalErr)
			} else if !test.expectFinalErr && got != test.initialErr {
				s.Errorf("got %v, want %v", got, test.initialErr)
			}
		})
	}
}

func TestShouldRetry(t *testing.T) {
	t.Parallel()

	for _, test := range []struct {
		desc        string
		inputErr    error
		shouldRetry bool
	}{
		{
			desc:        "googleapi.Error{Code: 0}",
			inputErr:    &googleapi.Error{Code: 0},
			shouldRetry: false,
		},
		{
			desc:        "googleapi.Error{Code: 429}",
			inputErr:    &googleapi.Error{Code: 429},
			shouldRetry: true,
		},
		{
			desc:        "errors.New(foo)",
			inputErr:    errors.New("foo"),
			shouldRetry: false,
		},
		{
			desc:        "googleapi.Error{Code: 518}",
			inputErr:    &googleapi.Error{Code: 518},
			shouldRetry: true,
		},
		{
			desc:        "googleapi.Error{Code: 599}",
			inputErr:    &googleapi.Error{Code: 599},
			shouldRetry: true,
		},
		{
			desc:        "googleapi.Error{Code: 428}",
			inputErr:    &googleapi.Error{Code: 428},
			shouldRetry: false,
		},
		{
			desc:        "googleapi.Error{Code: 518}",
			inputErr:    &googleapi.Error{Code: 518},
			shouldRetry: true,
		},
		{
			desc:        "url.Error{Err: errors.New(\"connection refused\")}",
			inputErr:    &url.Error{Op: "blah", URL: "blah", Err: errors.New("connection refused")},
			shouldRetry: true,
		},
		{
			desc:        "io.ErrUnexpectedEOF",
			inputErr:    io.ErrUnexpectedEOF,
			shouldRetry: true,
		},
		{
			desc:        "wrapped retryable error",
			inputErr:    xerrors.Errorf("Test unwrapping of a temporary error: %w", &googleapi.Error{Code: 500}),
			shouldRetry: true,
		},
		{
			desc:        "wrapped non-retryable error",
			inputErr:    xerrors.Errorf("Test unwrapping of a non-retriable error: %w", &googleapi.Error{Code: 400}),
			shouldRetry: false,
		},
		{
			desc:        "googleapi.Error{Code: 400}",
			inputErr:    &googleapi.Error{Code: 400},
			shouldRetry: false,
		},
		{
			desc:        "googleapi.Error{Code: 408}",
			inputErr:    &googleapi.Error{Code: 408},
			shouldRetry: true,
		},
		{
			desc:        "retryable gRPC error",
			inputErr:    status.Error(codes.Unavailable, "retryable gRPC error"),
			shouldRetry: true,
		},
		{
			desc:        "non-retryable gRPC error",
			inputErr:    status.Error(codes.PermissionDenied, "non-retryable gRPC error"),
			shouldRetry: false,
		},
	} {
		t.Run(test.desc, func(s *testing.T) {
			got := shouldRetry(test.inputErr)

			if got != test.shouldRetry {
				s.Errorf("got %v, want %v", got, test.shouldRetry)
			}
		})
	}
}
<|endoftext|>


<commit_before>package redis

import (
    "sync"
    "time"
    "strconv"
    "github.com/BluePecker/JwtAuth/storage"
    "github.com/go-redis/redis"
)

type Redis struct {
    create time.Time
    mu     sync.RWMutex
    mem    storage.MemStore
    client *redis.Client
}

func (er *Redis) Initializer(opt storage.Options) error {
    er.client = redis.NewClient(&redis.Options{
        Network: "tcp",
        Addr: opt.Host + ":" + strconv.Itoa(opt.Port),
        PoolSize: opt.PoolSize,
    })
    err := er.client.Ping().Err()
    if err != nil {
        defer er.client.Close()
    }
    return err
}

func (er *Redis) TTL(key string) int {
    er.mu.RLock()
    defer er.mu.RUnlock()
    if !er.mem.Exist(key) {
        return int(er.client.TTL(key).Val().Seconds())
    }
    return er.mem.TTL(key)
}

func (er *Redis) Read(key string) (interface{}, error) {
    er.mu.RLock()
    defer er.mu.RUnlock()
    if v, err := er.mem.Get(key); err != nil {
        status := er.client.Get(key)
        return status.Val(), status.Err()
    } else {
        return v, nil
    }
}

func (er *Redis) ReadInt(key string) (int, error) {
    er.mu.RLock()
    defer er.mu.RUnlock()
    v, err := er.mem.GetInt(key)
    if err != nil {
        status := er.client.Get(key)
        if status.Err() != nil {
            return 0, status.Err()
        }
        return strconv.Atoi(status.Val()), nil
    }
    return v, nil
}

func (er *Redis) ReadString(key string) (string, error) {
    er.mu.RLock()
    defer er.mu.RUnlock()
    v, err := er.mem.GetString(key)
    if err != nil {
        status := er.client.Get(key)
        if status.Err() != nil {
            return 0, status.Err()
        }
        return status.Val(), nil
    }
    return v, nil
}

func (er *Redis) Upgrade(key string, expire int) {
    er.mu.Lock()
    defer er.mu.Unlock()
    if v, err := er.Read(key); err != nil {
        er.Write(key, v, expire)
    }

}

func (er *Redis) Write(key string, value interface{}, expire int) {
    er.mu.Lock()
    defer er.mu.Unlock()
    if er.mem.Set(key, value, expire) == nil {
        er.flushToDB(key, value, expire)
    }
}

func (er *Redis) WriteImmutable(key string, value interface{}, expire int) {
    er.mu.Lock()
    defer er.mu.Unlock()
    if er.mem.SetImmutable(key, value, expire) == nil {
        er.flushToDB(key, value, expire)
    }
}

func (er *Redis) flushToDB(key string, value interface{}, expire int) {
    cmdStatus := er.client.Set(key, value, time.Duration(expire) * time.Second)
    return cmdStatus.Err()
}

func init() {
    storage.Register("redis", &Redis{})
}<commit_msg>redis driver<commit_after>package redis

import (
    "sync"
    "time"
    "strconv"
    "github.com/BluePecker/JwtAuth/storage"
    "github.com/go-redis/redis"
)

type Redis struct {
    create time.Time
    mu     sync.RWMutex
    mem    storage.MemStore
    client *redis.Client
}

func (er *Redis) Initializer(opt storage.Options) error {
    er.client = redis.NewClient(&redis.Options{
        Network: "tcp",
        Addr: opt.Host + ":" + strconv.Itoa(opt.Port),
        PoolSize: opt.PoolSize,
    })
    err := er.client.Ping().Err()
    if err != nil {
        defer er.client.Close()
    }
    return err
}

func (er *Redis) TTL(key string) int {
    er.mu.RLock()
    defer er.mu.RUnlock()
    if !er.mem.Exist(key) {
        return int(er.client.TTL(key).Val().Seconds())
    }
    return er.mem.TTL(key)
}

func (er *Redis) Read(key string) (interface{}, error) {
    er.mu.RLock()
    defer er.mu.RUnlock()
    if v, err := er.mem.Get(key); err != nil {
        status := er.client.Get(key)
        return status.Val(), status.Err()
    } else {
        return v, nil
    }
}

func (er *Redis) ReadInt(key string) (int, error) {
    er.mu.RLock()
    defer er.mu.RUnlock()
    v, err := er.mem.GetInt(key)
    if err != nil {
        status := er.client.Get(key)
        if status.Err() != nil {
            return 0, status.Err()
        }
        return strconv.Atoi(status.Val())
    }
    return v, nil
}

func (er *Redis) ReadString(key string) (string, error) {
    er.mu.RLock()
    defer er.mu.RUnlock()
    v, err := er.mem.GetString(key)
    if err != nil {
        status := er.client.Get(key)
        if status.Err() != nil {
            return "", status.Err()
        }
        return status.Val(), nil
    }
    return v, nil
}

func (er *Redis) Upgrade(key string, expire int) {
    er.mu.Lock()
    defer er.mu.Unlock()
    if v, err := er.Read(key); err != nil {
        er.Write(key, v, expire)
    }

}

func (er *Redis) Write(key string, value interface{}, expire int) {
    er.mu.Lock()
    defer er.mu.Unlock()
    if er.mem.Set(key, value, expire) == nil {
        er.flushToDB(key, value, expire)
    }
}

func (er *Redis) WriteImmutable(key string, value interface{}, expire int) {
    er.mu.Lock()
    defer er.mu.Unlock()
    if er.mem.SetImmutable(key, value, expire) == nil {
        er.flushToDB(key, value, expire)
    }
}

func (er *Redis) flushToDB(key string, value interface{}, expire int) error {
    cmdStatus := er.client.Set(key, value, time.Duration(expire) * time.Second)
    return cmdStatus.Err()
}

func init() {
    storage.Register("redis", &Redis{})
}<|endoftext|>


<commit_before>package main

import "fmt"
import "os"
import "unsafe"

type PrintCyclicer interface {
	PrintCyclic(prefix string, seen map[unsafe.Pointer]bool)
}

func genNode(format string, objs ...interface{}) {
	fmt.Printf("%s%p [label=\"" + format + "\"]\n", objs...)
}

func genLink(seen map[unsafe.Pointer]bool, format string, objs ...interface{}) {
	fmt.Printf("%s%p -> %[1]s%[3]p [label=\"" + format + "\"]\n", objs...)
	objs[2].(PrintCyclicer).PrintCyclic(objs[0].(string), seen)
}

type TaggedTreeList struct {
	left, right *TaggedTreeList
	size, termCount int
	leaf *TermNode
}

func NewTaggedTreeList(term *TermNode) *TaggedTreeList {
	t := 0
	if term.varNode == nil {
		t = 1
	}
	return &TaggedTreeList{
		nil,
		nil,
		1,
		t,
		term,
	}
}

func (l *TaggedTreeList) Append(term *TermNode) *TaggedTreeList {
	return l.Concat(NewTaggedTreeList(term))
}

func (l *TaggedTreeList) Concat(r *TaggedTreeList) *TaggedTreeList {
	return &TaggedTreeList{
		l,
		r,
		l.size + r.size,
		l.termCount + r.termCount,
		nil,
	}
}

func (l *TaggedTreeList) Slice() []*TermNode {
	s := make([]*TermNode, 0, l.size)
	return l.slice(s)
}

func (l *TaggedTreeList) slice(s []*TermNode) []*TermNode {
	if l.leaf == nil {
		s = l.left.slice(s)
		s = l.right.slice(s)
	} else {
		s = append(s, l.leaf)
	}
	return s
}

func (l *TaggedTreeList) TermCount() int {
	if l == nil {
		return 0
	}
	return l.termCount
}

func (l *TaggedTreeList) PrintCyclicRoot(prefix string) {
	fmt.Println("subgraph {")
	l.PrintCyclic(prefix, make(map[unsafe.Pointer]bool))
	fmt.Println("}")
}

func (l *TaggedTreeList) PrintCyclic(prefix string, seen map[unsafe.Pointer]bool) {
	ptr := unsafe.Pointer(l)
	if !seen[ptr] {
		seen[ptr] = true
		genNode("%d/%d", prefix, l, l.termCount, l.size)
		if l.leaf != nil {
			genLink(seen, "leaf", prefix, l, l.leaf)
		} else {
			genLink(seen, "left", prefix, l, l.left)
			genLink(seen, "right", prefix, l, l.right)
		}
	}
}

type Symbol struct {
	name string
	arity int
}

func (s *Symbol) PrintCyclic(prefix string, seen map[unsafe.Pointer]bool) {
	ptr := unsafe.Pointer(s)
	if !seen[ptr] {
		seen[ptr] = true
		genNode("%s/%d", prefix, s, s.name, s.arity)
	}
}

type TermNode struct {
	symbol *Symbol
	varNode *VarNode
	child []*TermNode
	done bool
}

func (t *TermNode) Substitute() {
	if !t.done {
		t.done = true
		for i, c := range t.child {
			if c.varNode == nil {
				c.Substitute()
			} else {
				ts := rep(c.varNode).terms.Slice()
				if len(ts) != 1 {
					panic("Attempted to substitute variable with multiple terms")
				}
				t.child[i] = ts[0]
			}
		}
	}
}

func (t *TermNode) PrintCyclic(prefix string, seen map[unsafe.Pointer]bool) {
	ptr := unsafe.Pointer(t)
	if !seen[ptr] {
		seen[ptr] = true
		suffix := ""
		if t.done {
			suffix = " ✓"
		}
		if t.symbol != nil {
			genNode("%s%s", prefix, t, t.symbol.name, suffix)
		} else if t.varNode != nil {
			genNode("%s%s", prefix, t, t.varNode.symbol, suffix)
			genLink(seen, "var", prefix, t, t.varNode)
		}
		for i, c := range t.child {
			genLink(seen, "#%d", prefix, t, c, i)
		}
	}
}

type VarNode struct {
	symbol string
	rep *VarNode
	terms *TaggedTreeList
	varCount int
}

func (v *VarNode) PrintCyclic(prefix string, seen map[unsafe.Pointer]bool) {
	ptr := unsafe.Pointer(v)
	if !seen[ptr] {
		seen[ptr] = true
		genNode("%s (%d)", prefix, v, v.symbol, v.varCount)
		if v.rep != nil {
			genLink(seen, "rep", prefix, v, v.rep)
		}
		if v.terms != nil {
			genLink(seen, "terms", prefix, v, v.terms)
		}
	}
}

type UnificationError struct {
	left, right *Symbol
}

var queue []*VarNode

func add(v *VarNode, t *TermNode) {
	if v.terms.TermCount() == 1 {
		queue = append(queue, v)
	}
	if v.terms == nil {
		v.terms = NewTaggedTreeList(t)
	} else {
		v.terms = v.terms.Append(t)
	}
}

func merge(v1, v2 *VarNode) {
	r1, r2 := v1.varCount, v2.varCount
	var bigV, v *VarNode
	if r1 >= r2 {
		bigV, v = v1, v2
	} else {
		bigV, v = v2, v1
	}
	k1, k2 := bigV.terms.TermCount(), v.terms.TermCount()
	if k1 <= 1 && k1 + k2 > 1 {
		queue = append(queue, bigV)
	}
	if bigV.terms == nil {
		bigV.terms = v.terms
	} else if v.terms != nil {
		bigV.terms = bigV.terms.Concat(v.terms)
	}
	v.rep, v.terms, v.varCount = bigV, nil, 0
	bigV.varCount = r1 + r1
}

func rep(v *VarNode) *VarNode {
	v0 := v.rep
	for v0 != v0.rep {
		v0 = v0.rep
	}
	for v.rep != v0 {
		v.rep, v = v0, v.rep
	}
	return v0
}

func commonFrontier(index int, parents, t_list []*TermNode) *UnificationError {
	sym := t_list[0].symbol
	for _, term := range t_list {
		if term.symbol != sym {
			return &UnificationError{
				left:  sym,
				right: term.symbol,
			}
		}
	}
	a := sym.arity
	t0_list := make([]*TermNode, len(t_list))
	s0Backing := make([]int, len(t_list))
	s1Backing := make([]int, len(t_list))
	for i := 0; i < a; i++ {
		for j := range t_list {
			t0_list[j] = t_list[j].child[i]
		}
		s0 := s0Backing[0:0]
		s1 := s1Backing[0:0]
		for j, term := range t0_list {
			if term.varNode != nil {
				s0 = append(s0, j)
			} else {
				s1 = append(s1, j)
			}
		}
		if len(s0) != 0 {
			j := s0[0]
			s0 := s0[1:]
			// In the original this unconditionally swaps them in memory
			if parents != nil {
				tmp := parents[0].child[index]
				parents[0].child[index] = parents[j].child[index]
				parents[j].child[index] = tmp
			}
			v := rep(t0_list[j].varNode)
			for _, k := range s0 {
				v2 := rep(t0_list[k].varNode)
				if v != v2 {
					merge(v, v2)
				}
			}
			for _, k := range s1 {
				add(v, t0_list[k])
			}
		} else {
			return commonFrontier(i, t_list, t0_list)
		}
	}
	return nil
}

func unify(t_list []*TermNode) *UnificationError {
	queue = make([]*VarNode, 0)
	err := commonFrontier(0, nil, t_list)
	if err != nil {
		return err
	}
	for len(queue) != 0 {
		v := queue[0]
		queue = queue[1:]
		k := v.terms.TermCount()
		if k >= 2 {
			t := v.terms.Slice()
			v.terms = NewTaggedTreeList(t[0])
			err = commonFrontier(0, nil, t)
			if err != nil {
				return err
			}
		}
	}
	return nil
}

func main() {
	sym := func(name string, arity int) *Symbol {
		return &Symbol{ name, arity }
	}
	varNode := func(name string) *VarNode {
		v := &VarNode{ name, nil, nil, 1 }
		v.rep = v
		return v
	}
	varTerm := func(node *VarNode) *TermNode {
		return &TermNode{ nil, node, nil, false }
	}
	funcTerm := func(symbol *Symbol, children ...*TermNode) *TermNode {
		return &TermNode{ symbol, nil, children, false }
	}
	f := sym("f", 2)
	x := varTerm(varNode("x"))
	z := varTerm(varNode("z"))
	expr1 := funcTerm(f, x, x)
	expr2 := funcTerm(f, funcTerm(f, z, z), funcTerm(f, z, x))
	root := NewTaggedTreeList(expr1).Append(expr2)
	fmt.Println("digraph {")
	root.PrintCyclicRoot("initial")
	err := unify(root.Slice())
	if err != nil {
		fmt.Printf("Error: %+v\n", err)
		os.Exit(1)
	}
	root.PrintCyclicRoot("unify")
	expr1.Substitute()
	expr2.Substitute()
	root.PrintCyclicRoot("substitute")
	fmt.Println("}")
}
<commit_msg>Add mutability comments<commit_after>package main

import "fmt"
import "os"
import "unsafe"

type PrintCyclicer interface {
	PrintCyclic(prefix string, seen map[unsafe.Pointer]bool)
}

func genNode(format string, objs ...interface{}) {
	fmt.Printf("%s%p [label=\"" + format + "\"]\n", objs...)
}

func genLink(seen map[unsafe.Pointer]bool, format string, objs ...interface{}) {
	fmt.Printf("%s%p -> %[1]s%[3]p [label=\"" + format + "\"]\n", objs...)
	objs[2].(PrintCyclicer).PrintCyclic(objs[0].(string), seen)
}

// immutable
type TaggedTreeList struct {
	left, right *TaggedTreeList
	size, termCount int
	leaf *TermNode
}

func NewTaggedTreeList(term *TermNode) *TaggedTreeList {
	t := 0
	if term.varNode == nil {
		t = 1
	}
	return &TaggedTreeList{
		nil,
		nil,
		1,
		t,
		term,
	}
}

func (l *TaggedTreeList) Append(term *TermNode) *TaggedTreeList {
	return l.Concat(NewTaggedTreeList(term))
}

func (l *TaggedTreeList) Concat(r *TaggedTreeList) *TaggedTreeList {
	return &TaggedTreeList{
		l,
		r,
		l.size + r.size,
		l.termCount + r.termCount,
		nil,
	}
}

func (l *TaggedTreeList) Slice() []*TermNode {
	s := make([]*TermNode, 0, l.size)
	return l.slice(s)
}

func (l *TaggedTreeList) slice(s []*TermNode) []*TermNode {
	if l.leaf == nil {
		s = l.left.slice(s)
		s = l.right.slice(s)
	} else {
		s = append(s, l.leaf)
	}
	return s
}

func (l *TaggedTreeList) TermCount() int {
	if l == nil {
		return 0
	}
	return l.termCount
}

func (l *TaggedTreeList) PrintCyclicRoot(prefix string) {
	fmt.Println("subgraph {")
	l.PrintCyclic(prefix, make(map[unsafe.Pointer]bool))
	fmt.Println("}")
}

func (l *TaggedTreeList) PrintCyclic(prefix string, seen map[unsafe.Pointer]bool) {
	ptr := unsafe.Pointer(l)
	if !seen[ptr] {
		seen[ptr] = true
		genNode("%d/%d", prefix, l, l.termCount, l.size)
		if l.leaf != nil {
			genLink(seen, "leaf", prefix, l, l.leaf)
		} else {
			genLink(seen, "left", prefix, l, l.left)
			genLink(seen, "right", prefix, l, l.right)
		}
	}
}

// immutable
type Symbol struct {
	name string
	arity int
}

func (s *Symbol) PrintCyclic(prefix string, seen map[unsafe.Pointer]bool) {
	ptr := unsafe.Pointer(s)
	if !seen[ptr] {
		seen[ptr] = true
		genNode("%s/%d", prefix, s, s.name, s.arity)
	}
}

type TermNode struct {
	symbol *Symbol // immutable
	varNode *VarNode // const
	child []*TermNode // const (slice object only)
	done bool // mutable
}

func (t *TermNode) Substitute() {
	if !t.done {
		t.done = true
		for i, c := range t.child {
			if c.varNode == nil {
				c.Substitute()
			} else {
				ts := rep(c.varNode).terms.Slice()
				if len(ts) != 1 {
					panic("Attempted to substitute variable with multiple terms")
				}
				t.child[i] = ts[0]
			}
		}
	}
}

func (t *TermNode) PrintCyclic(prefix string, seen map[unsafe.Pointer]bool) {
	ptr := unsafe.Pointer(t)
	if !seen[ptr] {
		seen[ptr] = true
		suffix := ""
		if t.done {
			suffix = " ✓"
		}
		if t.symbol != nil {
			genNode("%s%s", prefix, t, t.symbol.name, suffix)
		} else if t.varNode != nil {
			genNode("%s%s", prefix, t, t.varNode.symbol, suffix)
			genLink(seen, "var", prefix, t, t.varNode)
		}
		for i, c := range t.child {
			genLink(seen, "#%d", prefix, t, c, i)
		}
	}
}

type VarNode struct {
	symbol string // immutable
	rep *VarNode // mutable
	terms *TaggedTreeList // mutable
	varCount int // mutable
}

func (v *VarNode) PrintCyclic(prefix string, seen map[unsafe.Pointer]bool) {
	ptr := unsafe.Pointer(v)
	if !seen[ptr] {
		seen[ptr] = true
		genNode("%s (%d)", prefix, v, v.symbol, v.varCount)
		if v.rep != nil {
			genLink(seen, "rep", prefix, v, v.rep)
		}
		if v.terms != nil {
			genLink(seen, "terms", prefix, v, v.terms)
		}
	}
}

type UnificationError struct {
	left, right *Symbol
}

var queue []*VarNode

func add(v *VarNode, t *TermNode) {
	if v.terms.TermCount() == 1 {
		queue = append(queue, v)
	}
	if v.terms == nil {
		v.terms = NewTaggedTreeList(t)
	} else {
		v.terms = v.terms.Append(t)
	}
}

func merge(v1, v2 *VarNode) {
	r1, r2 := v1.varCount, v2.varCount
	var bigV, v *VarNode
	if r1 >= r2 {
		bigV, v = v1, v2
	} else {
		bigV, v = v2, v1
	}
	k1, k2 := bigV.terms.TermCount(), v.terms.TermCount()
	if k1 <= 1 && k1 + k2 > 1 {
		queue = append(queue, bigV)
	}
	if bigV.terms == nil {
		bigV.terms = v.terms
	} else if v.terms != nil {
		bigV.terms = bigV.terms.Concat(v.terms)
	}
	v.rep, v.terms, v.varCount = bigV, nil, 0
	bigV.varCount = r1 + r1
}

func rep(v *VarNode) *VarNode {
	v0 := v.rep
	for v0 != v0.rep {
		v0 = v0.rep
	}
	for v.rep != v0 {
		v.rep, v = v0, v.rep
	}
	return v0
}

func commonFrontier(index int, parents, t_list []*TermNode) *UnificationError {
	sym := t_list[0].symbol
	for _, term := range t_list {
		if term.symbol != sym {
			return &UnificationError{
				left:  sym,
				right: term.symbol,
			}
		}
	}
	a := sym.arity
	t0_list := make([]*TermNode, len(t_list))
	s0Backing := make([]int, len(t_list))
	s1Backing := make([]int, len(t_list))
	for i := 0; i < a; i++ {
		for j := range t_list {
			t0_list[j] = t_list[j].child[i]
		}
		s0 := s0Backing[0:0]
		s1 := s1Backing[0:0]
		for j, term := range t0_list {
			if term.varNode != nil {
				s0 = append(s0, j)
			} else {
				s1 = append(s1, j)
			}
		}
		if len(s0) != 0 {
			j := s0[0]
			s0 := s0[1:]
			// In the original this unconditionally swaps them in memory
			if parents != nil {
				tmp := parents[0].child[index]
				parents[0].child[index] = parents[j].child[index]
				parents[j].child[index] = tmp
			}
			v := rep(t0_list[j].varNode)
			for _, k := range s0 {
				v2 := rep(t0_list[k].varNode)
				if v != v2 {
					merge(v, v2)
				}
			}
			for _, k := range s1 {
				add(v, t0_list[k])
			}
		} else {
			return commonFrontier(i, t_list, t0_list)
		}
	}
	return nil
}

func unify(t_list []*TermNode) *UnificationError {
	queue = make([]*VarNode, 0)
	err := commonFrontier(0, nil, t_list)
	if err != nil {
		return err
	}
	for len(queue) != 0 {
		v := queue[0]
		queue = queue[1:]
		k := v.terms.TermCount()
		if k >= 2 {
			t := v.terms.Slice()
			v.terms = NewTaggedTreeList(t[0])
			err = commonFrontier(0, nil, t)
			if err != nil {
				return err
			}
		}
	}
	return nil
}

func main() {
	sym := func(name string, arity int) *Symbol {
		return &Symbol{ name, arity }
	}
	varNode := func(name string) *VarNode {
		v := &VarNode{ name, nil, nil, 1 }
		v.rep = v
		return v
	}
	varTerm := func(node *VarNode) *TermNode {
		return &TermNode{ nil, node, nil, false }
	}
	funcTerm := func(symbol *Symbol, children ...*TermNode) *TermNode {
		return &TermNode{ symbol, nil, children, false }
	}
	f := sym("f", 2)
	x := varTerm(varNode("x"))
	z := varTerm(varNode("z"))
	expr1 := funcTerm(f, x, x)
	expr2 := funcTerm(f, funcTerm(f, z, z), funcTerm(f, z, x))
	root := NewTaggedTreeList(expr1).Append(expr2)
	fmt.Println("digraph {")
	root.PrintCyclicRoot("initial")
	err := unify(root.Slice())
	if err != nil {
		fmt.Printf("Error: %+v\n", err)
		os.Exit(1)
	}
	root.PrintCyclicRoot("unify")
	expr1.Substitute()
	expr2.Substitute()
	root.PrintCyclicRoot("substitute")
	fmt.Println("}")
}
<|endoftext|>


<commit_before>package text

import (
	"image"
	"image/color"
	"image/draw"
	"unicode"
	"unicode/utf8"

	"github.com/faiface/pixel"
	"golang.org/x/image/font"
	"golang.org/x/image/math/fixed"
)

var ASCII []rune

func init() {
	ASCII = make([]rune, unicode.MaxASCII-32)
	for i := range ASCII {
		ASCII[i] = rune(32 + i)
	}
}

func RangeTable(table *unicode.RangeTable) []rune {
	var runes []rune
	for _, rng := range table.R16 {
		for r := rng.Lo; r <= rng.Hi; r += rng.Stride {
			runes = append(runes, rune(r))
		}
	}
	for _, rng := range table.R32 {
		for r := rng.Lo; r <= rng.Hi; r += rng.Stride {
			runes = append(runes, rune(r))
		}
	}
	return runes
}

type Text struct {
	Dot pixel.Vec

	color pixel.RGBA

	prevR rune
	atlas atlas
	glyph pixel.TrianglesData
	tris  pixel.TrianglesData
	d     pixel.Drawer
}

func New(face font.Face, runeSets ...[]rune) *Text {
	runes := []rune{unicode.ReplacementChar}
	for _, set := range runeSets {
		runes = append(runes, set...)
	}

	txt := &Text{
		color: pixel.Alpha(1),
		atlas: makeAtlas(face, runes),
	}
	txt.glyph.SetLen(6)
	txt.d.Picture = txt.atlas.pic
	txt.d.Triangles = &txt.tris

	txt.Clear()

	return txt
}

func (txt *Text) Color(c color.Color) {
	txt.color = pixel.ToRGBA(c)
}

func (txt *Text) Clear() {
	txt.prevR = -1
	txt.tris.SetLen(0)
	txt.d.Dirty()
}

func (txt *Text) Write(p []byte) (n int, err error) {
	if len(p) == 0 {
		return 0, nil
	}

	n = len(p)

	for i := range txt.glyph {
		txt.glyph[i].Color = txt.color
		txt.glyph[i].Intensity = 1
	}

	for len(p) > 0 {
		r, size := utf8.DecodeRune(p)
		p = p[size:]

		switch r {
		case '\n':
			txt.Dot -= pixel.Y(txt.atlas.lineHeight)
			txt.Dot = txt.Dot.WithX(0)
			continue
		case '\r':
			txt.Dot = txt.Dot.WithX(0)
			continue
		case '\t':
			//TODO
			continue
		}

		glyph, ok := txt.atlas.mapping[r]
		if !ok {
			glyph = txt.atlas.mapping[unicode.ReplacementChar]
		}

		if txt.prevR >= 0 {
			txt.Dot += pixel.X(txt.atlas.kern[struct{ r0, r1 rune }{txt.prevR, r}])
		}

		a := pixel.V(glyph.frame.Min.X(), glyph.frame.Min.Y())
		b := pixel.V(glyph.frame.Max.X(), glyph.frame.Min.Y())
		c := pixel.V(glyph.frame.Max.X(), glyph.frame.Max.Y())
		d := pixel.V(glyph.frame.Min.X(), glyph.frame.Max.Y())

		for i, v := range []pixel.Vec{a, b, c, a, c, d} {
			txt.glyph[i].Position = v - glyph.orig + txt.Dot
			txt.glyph[i].Picture = v
		}

		txt.tris = append(txt.tris, txt.glyph...)

		txt.Dot += pixel.X(glyph.advance)
		txt.prevR = r
	}

	txt.d.Dirty()

	return n, nil
}

func (txt *Text) Draw(t pixel.Target) {
	txt.d.Draw(t)
}

type atlas struct {
	pic        pixel.Picture
	mapping    map[rune]glyph
	kern       map[struct{ r0, r1 rune }]float64
	lineHeight float64
}

type glyph struct {
	orig    pixel.Vec
	frame   pixel.Rect
	advance float64
}

func makeAtlas(face font.Face, runes []rune) atlas {
	//FIXME: don't put glyphs in just one row, make a square

	width := fixed.Int26_6(0)
	for _, r := range runes {
		b, _, ok := face.GlyphBounds(r)
		if !ok && r != unicode.ReplacementChar {
			continue
		}
		width += b.Max.X - b.Min.X

		// padding to avoid filtering artifacts
		width = fixed.I(width.Ceil())
		width += fixed.I(2)
	}

	atlasImg := image.NewRGBA(image.Rect(
		0, 0,
		width.Ceil(), (face.Metrics().Ascent + face.Metrics().Descent).Ceil(),
	))
	atlasHeight := float64(atlasImg.Bounds().Dy())

	mapping := make(map[rune]glyph)

	dot := fixed.Point26_6{
		X: 0,
		Y: face.Metrics().Ascent,
	}

	for _, r := range runes {
		b, _, ok := face.GlyphBounds(r)
		if !ok && r != unicode.ReplacementChar {
			continue
		}

		dot.X -= b.Min.X

		dr, mask, maskp, _, _ := face.Glyph(dot, r)
		draw.Draw(atlasImg, dr, mask, maskp, draw.Src)

		orig := pixel.V(
			float64(dot.X)/(1<<6),
			atlasHeight-float64(dot.Y)/(1<<6),
		)

		frame := pixel.R(
			float64(dr.Min.X),
			atlasHeight-float64(dr.Min.Y),
			float64(dr.Max.X),
			atlasHeight-float64(dr.Max.Y),
		).Norm()

		adv, _ := face.GlyphAdvance(r)
		advance := float64(adv) / (1 << 6)

		mapping[r] = glyph{orig, frame, advance}

		dot.X += b.Max.X

		// padding
		dot.X = fixed.I(dot.X.Ceil())
		dot.X += fixed.I(2)
	}

	kern := make(map[struct{ r0, r1 rune }]float64)
	for _, r0 := range runes {
		for _, r1 := range runes {
			kern[struct{ r0, r1 rune }{r0, r1}] = float64(face.Kern(r0, r1)) / (1 << 6)
		}
	}

	return atlas{
		pixel.PictureDataFromImage(atlasImg),
		mapping,
		kern,
		float64(face.Metrics().Height) / (1 << 6),
	}
}
<commit_msg>add Text.Orig (start of the text)<commit_after>package text

import (
	"image"
	"image/color"
	"image/draw"
	"unicode"
	"unicode/utf8"

	"github.com/faiface/pixel"
	"golang.org/x/image/font"
	"golang.org/x/image/math/fixed"
)

var ASCII []rune

func init() {
	ASCII = make([]rune, unicode.MaxASCII-32)
	for i := range ASCII {
		ASCII[i] = rune(32 + i)
	}
}

func RangeTable(table *unicode.RangeTable) []rune {
	var runes []rune
	for _, rng := range table.R16 {
		for r := rng.Lo; r <= rng.Hi; r += rng.Stride {
			runes = append(runes, rune(r))
		}
	}
	for _, rng := range table.R32 {
		for r := rng.Lo; r <= rng.Hi; r += rng.Stride {
			runes = append(runes, rune(r))
		}
	}
	return runes
}

type Text struct {
	Orig pixel.Vec
	Dot  pixel.Vec

	color pixel.RGBA

	prevR rune
	atlas atlas
	glyph pixel.TrianglesData
	tris  pixel.TrianglesData
	d     pixel.Drawer
}

func New(face font.Face, runeSets ...[]rune) *Text {
	runes := []rune{unicode.ReplacementChar}
	for _, set := range runeSets {
		runes = append(runes, set...)
	}

	txt := &Text{
		color: pixel.Alpha(1),
		atlas: makeAtlas(face, runes),
	}
	txt.glyph.SetLen(6)
	txt.d.Picture = txt.atlas.pic
	txt.d.Triangles = &txt.tris

	txt.Clear()

	return txt
}

func (txt *Text) Color(c color.Color) {
	txt.color = pixel.ToRGBA(c)
}

func (txt *Text) Clear() {
	txt.prevR = -1
	txt.tris.SetLen(0)
	txt.d.Dirty()
}

func (txt *Text) Write(p []byte) (n int, err error) {
	if len(p) == 0 {
		return 0, nil
	}

	n = len(p)

	for i := range txt.glyph {
		txt.glyph[i].Color = txt.color
		txt.glyph[i].Intensity = 1
	}

	for len(p) > 0 {
		r, size := utf8.DecodeRune(p)
		p = p[size:]

		switch r {
		case '\n':
			txt.Dot -= pixel.Y(txt.atlas.lineHeight)
			txt.Dot = txt.Dot.WithX(txt.Orig.X())
			continue
		case '\r':
			txt.Dot = txt.Dot.WithX(txt.Orig.X())
			continue
		case '\t':
			//TODO
			continue
		}

		glyph, ok := txt.atlas.mapping[r]
		if !ok {
			glyph = txt.atlas.mapping[unicode.ReplacementChar]
		}

		if txt.prevR >= 0 {
			txt.Dot += pixel.X(txt.atlas.kern[struct{ r0, r1 rune }{txt.prevR, r}])
		}

		a := pixel.V(glyph.frame.Min.X(), glyph.frame.Min.Y())
		b := pixel.V(glyph.frame.Max.X(), glyph.frame.Min.Y())
		c := pixel.V(glyph.frame.Max.X(), glyph.frame.Max.Y())
		d := pixel.V(glyph.frame.Min.X(), glyph.frame.Max.Y())

		for i, v := range []pixel.Vec{a, b, c, a, c, d} {
			txt.glyph[i].Position = v - glyph.orig + txt.Dot
			txt.glyph[i].Picture = v
		}

		txt.tris = append(txt.tris, txt.glyph...)

		txt.Dot += pixel.X(glyph.advance)
		txt.prevR = r
	}

	txt.d.Dirty()

	return n, nil
}

func (txt *Text) Draw(t pixel.Target) {
	txt.d.Draw(t)
}

type atlas struct {
	pic        pixel.Picture
	mapping    map[rune]glyph
	kern       map[struct{ r0, r1 rune }]float64
	lineHeight float64
}

type glyph struct {
	orig    pixel.Vec
	frame   pixel.Rect
	advance float64
}

func makeAtlas(face font.Face, runes []rune) atlas {
	//FIXME: don't put glyphs in just one row, make a square

	width := fixed.Int26_6(0)
	for _, r := range runes {
		b, _, ok := face.GlyphBounds(r)
		if !ok && r != unicode.ReplacementChar {
			continue
		}
		width += b.Max.X - b.Min.X

		// padding to avoid filtering artifacts
		width = fixed.I(width.Ceil())
		width += fixed.I(2)
	}

	atlasImg := image.NewRGBA(image.Rect(
		0, 0,
		width.Ceil(), (face.Metrics().Ascent + face.Metrics().Descent).Ceil(),
	))
	atlasHeight := float64(atlasImg.Bounds().Dy())

	mapping := make(map[rune]glyph)

	dot := fixed.Point26_6{
		X: 0,
		Y: face.Metrics().Ascent,
	}

	for _, r := range runes {
		b, _, ok := face.GlyphBounds(r)
		if !ok && r != unicode.ReplacementChar {
			continue
		}

		dot.X -= b.Min.X

		dr, mask, maskp, _, _ := face.Glyph(dot, r)
		draw.Draw(atlasImg, dr, mask, maskp, draw.Src)

		orig := pixel.V(
			float64(dot.X)/(1<<6),
			atlasHeight-float64(dot.Y)/(1<<6),
		)

		frame := pixel.R(
			float64(dr.Min.X),
			atlasHeight-float64(dr.Min.Y),
			float64(dr.Max.X),
			atlasHeight-float64(dr.Max.Y),
		).Norm()

		adv, _ := face.GlyphAdvance(r)
		advance := float64(adv) / (1 << 6)

		mapping[r] = glyph{orig, frame, advance}

		dot.X += b.Max.X

		// padding
		dot.X = fixed.I(dot.X.Ceil())
		dot.X += fixed.I(2)
	}

	kern := make(map[struct{ r0, r1 rune }]float64)
	for _, r0 := range runes {
		for _, r1 := range runes {
			kern[struct{ r0, r1 rune }{r0, r1}] = float64(face.Kern(r0, r1)) / (1 << 6)
		}
	}

	return atlas{
		pixel.PictureDataFromImage(atlasImg),
		mapping,
		kern,
		float64(face.Metrics().Height) / (1 << 6),
	}
}
<|endoftext|>


<commit_before>package wrap

import (
	"bytes"
	"fmt"
	"io"
	"os"
	"os/exec"
	"time"

	"github.com/Songmu/wrapcommander"
	"github.com/mackerelio/mackerel-agent/config"
	"github.com/mackerelio/mkr/logger"
	"golang.org/x/sync/errgroup"
	cli "gopkg.in/urfave/cli.v1"
)

// CommandPlugin is definition of mkr plugin
var Command = cli.Command{
	Name:      "wrap",
	Usage:     "wrap command status",
	ArgsUsage: "[--verbose | -v] [--name | -n <name>] [--memo | -m <memo>] -- /path/to/batch",
	Description: `
    wrap command line
`,
	Action: doWrap,
	Flags: []cli.Flag{
		cli.StringFlag{Name: "name, n", Value: "", Usage: "monitor <name>"},
		cli.BoolFlag{Name: "verbose, v", Usage: "verbose output mode"},
		cli.StringFlag{Name: "memo, m", Value: "", Usage: "monitor <memo>"},
		cli.StringFlag{Name: "H, host", Value: "", Usage: "<hostId>"},
		cli.BoolFlag{Name: "warning, w", Usage: "alert as warning"},
	},
}

func doWrap(c *cli.Context) error {
	confFile := c.GlobalString("conf")
	conf, err := config.LoadConfig(confFile)
	if err != nil {
		return err
	}
	apibase := c.GlobalString("apibase")
	apikey := conf.Apikey
	if apikey == "" {
		apikey = os.Getenv("MACKEREL_APIKEY")
	}
	if apikey == "" {
		logger.Log("error", "[mkr wrap] failed to detect Mackerel APIKey. Try to specify in mackerel-agent.conf or export MACKEREL_APIKEY='<Your apikey>'")
	}
	hostID, _ := conf.LoadHostID()
	if c.String("host") != "" {
		hostID = c.String("host")
	}
	if hostID == "" {
		logger.Log("error", "[mkr wrap] failed to load hostID. Try to specify -host option explicitly")
	}
	// Since command execution has the highest priority, even when apikey or
	// hostID is empty, we don't return errors and only output the log here.

	cmd := c.Args()
	if len(cmd) > 0 && cmd[0] == "--" {
		cmd = cmd[1:]
	}
	if len(cmd) < 1 {
		return fmt.Errorf("no commands specified")
	}

	return (&app{
		apibase: apibase,
		name:    c.String("name"),
		verbose: c.Bool("verbose"),
		memo:    c.String("memo"),
		warning: c.Bool("warning"),
		hostID:  hostID,
		apikey:  apikey,
		cmd:     cmd,
	}).run()
}

type app struct {
	apibase string
	name    string
	verbose bool
	memo    string
	warning bool
	hostID  string
	apikey  string
	cmd     []string
}

type result struct {
	cmd        []string
	name, memo string

	output, stdout, stderr string
	pid, exitCode          *int
	signaled               bool
	startAt, endAt         time.Time

	msg     string
	success bool
}

func (ap *app) run() error {
	re := ap.runCmd()
	_ = re
	return nil
}

func (ap *app) runCmd() *result {
	cmd := exec.Command(ap.cmd[0], ap.cmd[1:]...)
	re := &result{
		cmd:  ap.cmd,
		name: ap.name,
		memo: ap.memo,
	}

	stdoutPipe, err := cmd.StdoutPipe()
	if err != nil {
		re.msg = fmt.Sprintf("command invocation failed with follwing error: %s", err)
		return re
	}
	defer stdoutPipe.Close()

	stderrPipe, err := cmd.StderrPipe()
	if err != nil {
		re.msg = fmt.Sprintf("command invocation failed with follwing error: %s", err)
		return re
	}
	defer stderrPipe.Close()

	var (
		bufStdout = &bytes.Buffer{}
		bufStderr = &bytes.Buffer{}
		bufMerged = &bytes.Buffer{}
	)
	stdoutPipe2 := io.TeeReader(stdoutPipe, io.MultiWriter(bufStdout, bufMerged))
	stderrPipe2 := io.TeeReader(stderrPipe, io.MultiWriter(bufStderr, bufMerged))

	re.startAt = time.Now()
	err = cmd.Start()
	if err != nil {
		re.msg = fmt.Sprintf("command invocation failed with follwing error: %s", err)
		return re
	}
	re.pid = &cmd.Process.Pid
	eg := &errgroup.Group{}

	eg.Go(func() error {
		defer stdoutPipe.Close()
		_, err := io.Copy(os.Stdout, stdoutPipe2)
		return err
	})
	eg.Go(func() error {
		defer stderrPipe.Close()
		_, err := io.Copy(os.Stderr, stderrPipe2)
		return err
	})
	eg.Wait()

	cmdErr := cmd.Wait()
	re.endAt = time.Now()
	ex := wrapcommander.ResolveExitCode(cmdErr)
	re.exitCode = &ex
	if *re.exitCode > 128 {
		w, ok := wrapcommander.ErrorToWaitStatus(cmdErr)
		if ok {
			re.signaled = w.Signaled()
		}
	}
	if !re.signaled {
		re.msg = fmt.Sprintf("command exited with code: %d", *re.exitCode)
	} else {
		re.msg = fmt.Sprintf("command died with signal: %d", *re.exitCode&127)
	}
	re.stdout = bufStdout.String()
	re.stderr = bufStderr.String()
	re.output = bufMerged.String()

	re.success = *re.exitCode == 0
	return re
}
<commit_msg>adjustment<commit_after>package wrap

import (
	"bytes"
	"fmt"
	"io"
	"os"
	"os/exec"
	"time"

	"github.com/Songmu/wrapcommander"
	"github.com/mackerelio/mackerel-agent/config"
	"github.com/mackerelio/mkr/logger"
	"golang.org/x/sync/errgroup"
	cli "gopkg.in/urfave/cli.v1"
)

// CommandPlugin is definition of mkr plugin
var Command = cli.Command{
	Name:      "wrap",
	Usage:     "wrap command status",
	ArgsUsage: "[--verbose | -v] [--name | -n <name>] [--memo | -m <memo>] -- /path/to/batch",
	Description: `
    wrap command line
`,
	Action: doWrap,
	Flags: []cli.Flag{
		cli.StringFlag{Name: "name, n", Value: "", Usage: "monitor <name>"},
		cli.BoolFlag{Name: "verbose, v", Usage: "verbose output mode"},
		cli.StringFlag{Name: "memo, m", Value: "", Usage: "monitor <memo>"},
		cli.StringFlag{Name: "H, host", Value: "", Usage: "<hostId>"},
		cli.BoolFlag{Name: "warning, w", Usage: "alert as warning"},
	},
}

func doWrap(c *cli.Context) error {
	confFile := c.GlobalString("conf")
	conf, err := config.LoadConfig(confFile)
	if err != nil {
		return err
	}
	apibase := c.GlobalString("apibase")
	apikey := conf.Apikey
	if apikey == "" {
		apikey = os.Getenv("MACKEREL_APIKEY")
	}
	if apikey == "" {
		logger.Log("error", "[mkr wrap] failed to detect Mackerel APIKey. Try to specify in mackerel-agent.conf or export MACKEREL_APIKEY='<Your apikey>'")
	}
	hostID, _ := conf.LoadHostID()
	if c.String("host") != "" {
		hostID = c.String("host")
	}
	if hostID == "" {
		logger.Log("error", "[mkr wrap] failed to load hostID. Try to specify -host option explicitly")
	}
	// Since command execution has the highest priority, even when apikey or
	// hostID is empty, we don't return errors and only output the log here.

	cmd := c.Args()
	if len(cmd) > 0 && cmd[0] == "--" {
		cmd = cmd[1:]
	}
	if len(cmd) < 1 {
		return fmt.Errorf("no commands specified")
	}

	return (&app{
		apibase: apibase,
		name:    c.String("name"),
		verbose: c.Bool("verbose"),
		memo:    c.String("memo"),
		warning: c.Bool("warning"),
		hostID:  hostID,
		apikey:  apikey,
		cmd:     cmd,
	}).run()
}

type app struct {
	apibase string
	name    string
	verbose bool
	memo    string
	warning bool
	hostID  string
	apikey  string
	cmd     []string
}

type result struct {
	cmd        []string
	name, memo string

	output, stdout, stderr string
	pid                    int
	exitCode               *int
	signaled               bool
	startAt, endAt         time.Time

	msg     string
	success bool
}

func (ap *app) run() error {
	re := ap.runCmd()
	return ap.report(re)
}

func (ap *app) runCmd() *result {
	cmd := exec.Command(ap.cmd[0], ap.cmd[1:]...)
	re := &result{
		cmd:  ap.cmd,
		name: ap.name,
		memo: ap.memo,
	}

	stdoutPipe, err := cmd.StdoutPipe()
	if err != nil {
		re.msg = fmt.Sprintf("command invocation failed with follwing error: %s", err)
		return re
	}
	defer stdoutPipe.Close()

	stderrPipe, err := cmd.StderrPipe()
	if err != nil {
		re.msg = fmt.Sprintf("command invocation failed with follwing error: %s", err)
		return re
	}
	defer stderrPipe.Close()

	var (
		bufStdout = &bytes.Buffer{}
		bufStderr = &bytes.Buffer{}
		bufMerged = &bytes.Buffer{}
	)
	stdoutPipe2 := io.TeeReader(stdoutPipe, io.MultiWriter(bufStdout, bufMerged))
	stderrPipe2 := io.TeeReader(stderrPipe, io.MultiWriter(bufStderr, bufMerged))

	re.startAt = time.Now()
	err = cmd.Start()
	if err != nil {
		re.msg = fmt.Sprintf("command invocation failed with follwing error: %s", err)
		return re
	}
	re.pid = cmd.Process.Pid
	eg := &errgroup.Group{}

	eg.Go(func() error {
		defer stdoutPipe.Close()
		_, err := io.Copy(os.Stdout, stdoutPipe2)
		return err
	})
	eg.Go(func() error {
		defer stderrPipe.Close()
		_, err := io.Copy(os.Stderr, stderrPipe2)
		return err
	})
	eg.Wait()

	cmdErr := cmd.Wait()
	re.endAt = time.Now()
	ex := wrapcommander.ResolveExitCode(cmdErr)
	re.exitCode = &ex
	if *re.exitCode > 128 {
		w, ok := wrapcommander.ErrorToWaitStatus(cmdErr)
		if ok {
			re.signaled = w.Signaled()
		}
	}
	if !re.signaled {
		re.msg = fmt.Sprintf("command exited with code: %d", *re.exitCode)
	} else {
		re.msg = fmt.Sprintf("command died with signal: %d", *re.exitCode&127)
	}
	re.stdout = bufStdout.String()
	re.stderr = bufStderr.String()
	re.output = bufMerged.String()

	re.success = *re.exitCode == 0
	return re
}

func (ap *app) report(re *result) error {
	return nil
}
<|endoftext|>


<commit_before>package bongo

import (
	"errors"
	// "fmt"
	"gopkg.in/mgo.v2"
	"gopkg.in/mgo.v2/bson"
	"time"
	// "math"
	// "strings"
)

type BeforeSaveHook interface {
	BeforeSave(*Collection) error
}

type AfterSaveHook interface {
	AfterSave(*Collection) error
}

type BeforeDeleteHook interface {
	BeforeDelete(*Collection) error
}

type AfterDeleteHook interface {
	AfterDelete(*Collection) error
}

type AfterFindHook interface {
	AfterFind(*Collection) error
}

type ValidateHook interface {
	Validate(*Collection) []error
}

type ValidationError struct {
	Errors []error
}

type TimeTracker interface {
	SetCreated(time.Time)
	SetModified(time.Time)
}

type Document interface {
	GetId() bson.ObjectId
	SetId(bson.ObjectId)
}

type CascadingDocument interface {
	GetCascade(*Collection) []*CascadeConfig
}

func (v *ValidationError) Error() string {
	return "Validation failed"
}

type Collection struct {
	Name       string
	Connection *Connection
}

type NewTracker interface {
	SetIsNew(bool)
	IsNew() bool
}

type DocumentNotFoundError struct{}

func (d DocumentNotFoundError) Error() string {
	return "Document not found"
}

func (c *Collection) Collection() *mgo.Collection {
	return c.Connection.Session.DB(c.Connection.Config.Database).C(c.Name)
}

func (c *Collection) collectionOnSession(sess *mgo.Session) *mgo.Collection {
	return sess.DB(c.Connection.Config.Database).C(c.Name)
}

func (c *Collection) Save(doc Document) error {
	var err error
	sess := c.Connection.Session.Clone()
	defer sess.Close()

	// Per mgo's recommendation, create a clone of the session so there is no blocking
	col := c.collectionOnSession(sess)

	// Validate?
	if validator, ok := doc.(ValidateHook); ok {
		errs := validator.Validate(c)

		if len(errs) > 0 {
			return &ValidationError{errs}
		}
	}

	if hook, ok := doc.(BeforeSaveHook); ok {
		err := hook.BeforeSave(c)
		if err != nil {
			return err
		}
	}

	// If the model implements the NewTracker interface, we'll use that to determine newness. Otherwise always assume it's new

	isNew := true
	if newt, ok := doc.(NewTracker); ok {
		isNew = newt.IsNew()
	}

	// Add created/modified time. Also set on the model itself if it has those fields.
	now := time.Now()

	if tt, ok := doc.(TimeTracker); ok {
		if isNew {
			tt.SetCreated(now)
		}
		tt.SetModified(now)
	}

	go CascadeSave(c, doc)

	id := doc.GetId()

	if !isNew && !id.Valid() {
		return errors.New("New tracker says this document isn't new but there is no valid Id field")
	}

	if isNew && !id.Valid() {
		// Generate an Id
		id = bson.NewObjectId()
		doc.SetId(id)
	}

	_, err = col.UpsertId(id, doc)

	if err != nil {
		return err
	}

	if hook, ok := doc.(AfterSaveHook); ok {
		err = hook.AfterSave(c)
		if err != nil {
			return err
		}
	}

	// We saved it, no longer new
	if newt, ok := doc.(NewTracker); ok {
		newt.SetIsNew(false)
	}

	return nil
}

func (c *Collection) FindById(id bson.ObjectId, doc interface{}) error {

	err := c.Collection().FindId(id).One(doc)

	// Handle errors coming from mgo - we want to convert it to a DocumentNotFoundError so people can figure out
	// what the error type is without looking at the text
	if err != nil {
		if err.Error() == "not found" {
			return &DocumentNotFoundError{}
		} else {
			return err
		}
	}

	if hook, ok := doc.(AfterFindHook); ok {
		err = hook.AfterFind(c)
		if err != nil {
			return err
		}
	}

	// We retrieved it, so set new to false
	if newt, ok := doc.(NewTracker); ok {
		newt.SetIsNew(false)
	}
	return nil
}

// This doesn't actually do any DB interaction, it just creates the result set so we can
// start looping through on the iterator
func (c *Collection) Find(query interface{}) *ResultSet {
	col := c.Collection()

	// Count for testing
	q := col.Find(query)

	resultset := new(ResultSet)

	resultset.Query = q
	resultset.Params = query
	resultset.Collection = c

	return resultset
}

func (c *Collection) FindOne(query interface{}, doc interface{}) error {

	// Now run a find
	results := c.Find(query)
	results.Query.Limit(1)

	hasNext := results.Next(doc)

	if !hasNext {
		// There could have been an error fetching the next one, which would set the Error property on the resultset
		if results.Error != nil {
			return results.Error
		} else {
			return &DocumentNotFoundError{}
		}

	}

	if newt, ok := doc.(NewTracker); ok {
		newt.SetIsNew(false)
	}

	return nil
}

func (c *Collection) DeleteDocument(doc Document) error {
	var err error
	// Create a new session per mgo's suggestion to avoid blocking
	sess := c.Connection.Session.Clone()
	defer sess.Close()
	col := c.collectionOnSession(sess)

	if hook, ok := doc.(BeforeDeleteHook); ok {
		err := hook.BeforeDelete(c)
		if err != nil {
			return err
		}
	}

	err = col.Remove(bson.M{"_id": doc.GetId()})

	if err != nil {
		return err
	}

	go CascadeDelete(c, doc)

	if hook, ok := doc.(AfterDeleteHook); ok {
		err = hook.AfterDelete(c)
		if err != nil {
			return err
		}
	}

	return nil

}

// Convenience method which just delegates to mgo. Note that hooks are NOT run
func (c *Collection) Delete(query bson.M) (*mgo.ChangeInfo, error) {
	sess := c.Connection.Session.Clone()
	defer sess.Close()
	col := c.collectionOnSession(sess)
	return col.RemoveAll(query)
}

// Convenience method which just delegates to mgo. Note that hooks are NOT run
func (c *Collection) DeleteOne(query bson.M) error {
	sess := c.Connection.Session.Clone()
	defer sess.Close()
	col := c.collectionOnSession(sess)
	return col.Remove(query)
}
<commit_msg>Split out validation and pre save hooks into PreSave so we can use that separately for "fake save"<commit_after>package bongo

import (
	"errors"
	// "fmt"
	"gopkg.in/mgo.v2"
	"gopkg.in/mgo.v2/bson"
	"time"
	// "math"
	// "strings"
)

type BeforeSaveHook interface {
	BeforeSave(*Collection) error
}

type AfterSaveHook interface {
	AfterSave(*Collection) error
}

type BeforeDeleteHook interface {
	BeforeDelete(*Collection) error
}

type AfterDeleteHook interface {
	AfterDelete(*Collection) error
}

type AfterFindHook interface {
	AfterFind(*Collection) error
}

type ValidateHook interface {
	Validate(*Collection) []error
}

type ValidationError struct {
	Errors []error
}

type TimeTracker interface {
	SetCreated(time.Time)
	SetModified(time.Time)
}

type Document interface {
	GetId() bson.ObjectId
	SetId(bson.ObjectId)
}

type CascadingDocument interface {
	GetCascade(*Collection) []*CascadeConfig
}

func (v *ValidationError) Error() string {
	return "Validation failed"
}

type Collection struct {
	Name       string
	Connection *Connection
}

type NewTracker interface {
	SetIsNew(bool)
	IsNew() bool
}

type DocumentNotFoundError struct{}

func (d DocumentNotFoundError) Error() string {
	return "Document not found"
}

func (c *Collection) Collection() *mgo.Collection {
	return c.Connection.Session.DB(c.Connection.Config.Database).C(c.Name)
}

func (c *Collection) collectionOnSession(sess *mgo.Session) *mgo.Collection {
	return sess.DB(c.Connection.Config.Database).C(c.Name)
}

func (c *Collection) PreSave(doc Document) error {
	// Validate?
	if validator, ok := doc.(ValidateHook); ok {
		errs := validator.Validate(c)

		if len(errs) > 0 {
			return &ValidationError{errs}
		}
	}

	if hook, ok := doc.(BeforeSaveHook); ok {
		err := hook.BeforeSave(c)
		if err != nil {
			return err
		}
	}

	return nil
}

func (c *Collection) Save(doc Document) error {
	var err error
	sess := c.Connection.Session.Clone()
	defer sess.Close()

	// Per mgo's recommendation, create a clone of the session so there is no blocking
	col := c.collectionOnSession(sess)

	err = c.PreSave(doc)
	if err != nil {
		return err
	}
	// If the model implements the NewTracker interface, we'll use that to determine newness. Otherwise always assume it's new

	isNew := true
	if newt, ok := doc.(NewTracker); ok {
		isNew = newt.IsNew()
	}

	// Add created/modified time. Also set on the model itself if it has those fields.
	now := time.Now()

	if tt, ok := doc.(TimeTracker); ok {
		if isNew {
			tt.SetCreated(now)
		}
		tt.SetModified(now)
	}

	go CascadeSave(c, doc)

	id := doc.GetId()

	if !isNew && !id.Valid() {
		return errors.New("New tracker says this document isn't new but there is no valid Id field")
	}

	if isNew && !id.Valid() {
		// Generate an Id
		id = bson.NewObjectId()
		doc.SetId(id)
	}

	_, err = col.UpsertId(id, doc)

	if err != nil {
		return err
	}

	if hook, ok := doc.(AfterSaveHook); ok {
		err = hook.AfterSave(c)
		if err != nil {
			return err
		}
	}

	// We saved it, no longer new
	if newt, ok := doc.(NewTracker); ok {
		newt.SetIsNew(false)
	}

	return nil
}

func (c *Collection) FindById(id bson.ObjectId, doc interface{}) error {

	err := c.Collection().FindId(id).One(doc)

	// Handle errors coming from mgo - we want to convert it to a DocumentNotFoundError so people can figure out
	// what the error type is without looking at the text
	if err != nil {
		if err.Error() == "not found" {
			return &DocumentNotFoundError{}
		} else {
			return err
		}
	}

	if hook, ok := doc.(AfterFindHook); ok {
		err = hook.AfterFind(c)
		if err != nil {
			return err
		}
	}

	// We retrieved it, so set new to false
	if newt, ok := doc.(NewTracker); ok {
		newt.SetIsNew(false)
	}
	return nil
}

// This doesn't actually do any DB interaction, it just creates the result set so we can
// start looping through on the iterator
func (c *Collection) Find(query interface{}) *ResultSet {
	col := c.Collection()

	// Count for testing
	q := col.Find(query)

	resultset := new(ResultSet)

	resultset.Query = q
	resultset.Params = query
	resultset.Collection = c

	return resultset
}

func (c *Collection) FindOne(query interface{}, doc interface{}) error {

	// Now run a find
	results := c.Find(query)
	results.Query.Limit(1)

	hasNext := results.Next(doc)

	if !hasNext {
		// There could have been an error fetching the next one, which would set the Error property on the resultset
		if results.Error != nil {
			return results.Error
		} else {
			return &DocumentNotFoundError{}
		}

	}

	if newt, ok := doc.(NewTracker); ok {
		newt.SetIsNew(false)
	}

	return nil
}

func (c *Collection) DeleteDocument(doc Document) error {
	var err error
	// Create a new session per mgo's suggestion to avoid blocking
	sess := c.Connection.Session.Clone()
	defer sess.Close()
	col := c.collectionOnSession(sess)

	if hook, ok := doc.(BeforeDeleteHook); ok {
		err := hook.BeforeDelete(c)
		if err != nil {
			return err
		}
	}

	err = col.Remove(bson.M{"_id": doc.GetId()})

	if err != nil {
		return err
	}

	go CascadeDelete(c, doc)

	if hook, ok := doc.(AfterDeleteHook); ok {
		err = hook.AfterDelete(c)
		if err != nil {
			return err
		}
	}

	return nil

}

// Convenience method which just delegates to mgo. Note that hooks are NOT run
func (c *Collection) Delete(query bson.M) (*mgo.ChangeInfo, error) {
	sess := c.Connection.Session.Clone()
	defer sess.Close()
	col := c.collectionOnSession(sess)
	return col.RemoveAll(query)
}

// Convenience method which just delegates to mgo. Note that hooks are NOT run
func (c *Collection) DeleteOne(query bson.M) error {
	sess := c.Connection.Session.Clone()
	defer sess.Close()
	col := c.collectionOnSession(sess)
	return col.Remove(query)
}
<|endoftext|>