<commit_before>// Package surf ensembles other packages into a usable browser.
package surf

import (
	"github.com/headzoo/surf/browser"
	"github.com/headzoo/surf/jar"
	"net/http"
	"net/http/cookiejar"
)

// NewBrowser creates and returns a *browser.Browser type.
func NewBrowser() (*browser.Browser, error) {
	cookies, err := cookiejar.New(nil)
	if err != nil {
		return nil, err
	}

	bow := &browser.Browser{}
	bow.SetUserAgent(browser.DefaultUserAgent)
	bow.SetCookieJar(cookies)
	bow.SetBookmarksJar(jar.NewMemoryBookmarks())
	bow.SetHistoryJar(jar.NewMemoryHistory())
	bow.SetHeaders(make(http.Header, 10))
	bow.SetAttributes(browser.AttributeMap{
		browser.SendReferer:         browser.DefaultSendReferer,
		browser.MetaRefreshHandling: browser.DefaultMetaRefreshHandling,
		browser.FollowRedirects:     browser.DefaultFollowRedirects,
	})

	return bow, nil
}
<commit_msg>NewBrowser() no longer returns an error.<commit_after>// Package surf ensembles other packages into a usable browser.
package surf

import (
	"github.com/headzoo/surf/browser"
	"github.com/headzoo/surf/jar"
	"net/http"
)

// NewBrowser creates and returns a *browser.Browser type.
func NewBrowser() *browser.Browser {
	bow := &browser.Browser{}
	bow.SetUserAgent(browser.DefaultUserAgent)
	bow.SetCookieJar(jar.NewMemoryCookies())
	bow.SetBookmarksJar(jar.NewMemoryBookmarks())
	bow.SetHistoryJar(jar.NewMemoryHistory())
	bow.SetHeaders(make(http.Header, 10))
	bow.SetAttributes(browser.AttributeMap{
		browser.SendReferer:         browser.DefaultSendReferer,
		browser.MetaRefreshHandling: browser.DefaultMetaRefreshHandling,
		browser.FollowRedirects:     browser.DefaultFollowRedirects,
	})

	return bow
}
<|endoftext|>


<commit_before>// Package term manages POSIX terminals. As POSIX terminals are connected to,
// or emulate, a UART, this package also provides control over the various
// UART and serial line parameters.
package term

import (
	"io"
	"os"
	"syscall"

	"github.com/pkg/term/termios"
)

// Term represents an asynchronous communications port.
type Term struct {
	name string
	fd   int
	orig syscall.Termios // original state of the terminal, see Open and Restore
}

// Open opens an asynchronous communications port.
func Open(name string, options ...func(*Term) error) (*Term, error) {
	fd, e := syscall.Open(name, syscall.O_NOCTTY|syscall.O_CLOEXEC|syscall.O_RDWR, 0666)
	if e != nil {
		return nil, &os.PathError{"open", name, e}
	}
	t := Term{name: name, fd: fd}
	if err := termios.Tcgetattr(uintptr(t.fd), &t.orig); err != nil {
		return nil, err
	}
	return &t, t.SetOption(options...)
}

// SetOption takes one or more optoin function and applies them in order to Term.
func (t *Term) SetOption(options ...func(*Term) error) error {
	for _, opt := range options {
		if err := opt(t); err != nil {
			return err
		}
	}
	return nil
}

// Read reads up to len(b) bytes from the terminal. It returns the number of
// bytes read and an error, if any. EOF is signaled by a zero count with
// err set to io.EOF.
func (t *Term) Read(b []byte) (int, error) {
	n, e := syscall.Read(t.fd, b)
	if n < 0 {
		n = 0
	}
	if n == 0 && len(b) > 0 && e == nil {
		return 0, io.EOF
	}
	if e != nil {
		return n, &os.PathError{"read", t.name, e}
	}
	return n, nil
}

// Write writes len(b) bytes to the terminal. It returns the number of bytes
// written and an error, if any. Write returns a non-nil error when n !=
// len(b).
func (t *Term) Write(b []byte) (int, error) {
	n, e := syscall.Write(t.fd, b)
	if n < 0 {
		n = 0
	}
	if n != len(b) {
		return n, io.ErrShortWrite
	}
	if e != nil {
		return n, &os.PathError{"write", t.name, e}
	}
	return n, nil
}

// Close closes the device and releases any associated resources.
func (t *Term) Close() error {
	err := syscall.Close(t.fd)
	t.fd = -1
	return err
}

// SetCbreak sets cbreak mode.
func (t *Term) SetCbreak() error {
	return t.SetOption(CBreakMode)
}

// CBreakMode places the terminal into cbreak mode.
func CBreakMode(t *Term) error {
	var a attr
	if err := termios.Tcgetattr(uintptr(t.fd), (*syscall.Termios)(&a)); err != nil {
		return err
	}
	termios.Cfmakecbreak((*syscall.Termios)(&a))
	return termios.Tcsetattr(uintptr(t.fd), termios.TCSANOW, (*syscall.Termios)(&a))
}

// SetRaw sets raw mode.
func (t *Term) SetRaw() error {
	return t.SetOption(RawMode)
}

// RawMode places the terminal into raw mode.
func RawMode(t *Term) error {
	var a attr
	if err := termios.Tcgetattr(uintptr(t.fd), (*syscall.Termios)(&a)); err != nil {
		return err
	}
	termios.Cfmakeraw((*syscall.Termios)(&a))
	return termios.Tcsetattr(uintptr(t.fd), termios.TCSANOW, (*syscall.Termios)(&a))
}

// Speed sets the baud rate option for the terminal.
func Speed(baud int) func(*Term) error {
	return func(t *Term) error {
		return t.setSpeed(baud)
	}
}

// SetSpeed sets the receive and transmit baud rates.
func (t *Term) SetSpeed(baud int) error {
	return t.SetOption(Speed(baud))
}

func (t *Term) setSpeed(baud int) error {
	var a attr
	if err := termios.Tcgetattr(uintptr(t.fd), (*syscall.Termios)(&a)); err != nil {
		return err
	}
	a.setSpeed(baud)
	return termios.Tcsetattr(uintptr(t.fd), termios.TCSANOW, (*syscall.Termios)(&a))
}

// Flush flushes both data received but not read, and data written but not transmitted.
func (t *Term) Flush() error {
	return termios.Tcflush(uintptr(t.fd), termios.TCIOFLUSH)
}

// SendBreak sends a break signal.
func (t *Term) SendBreak() error {
	return termios.Tcsendbreak(uintptr(t.fd), 0)
}

// SetDTR sets the DTR (data terminal ready) signal.
func (t *Term) SetDTR(v bool) error {
	bits := syscall.TIOCM_DTR
	if v {
		return termios.Tiocmbis(uintptr(t.fd), &bits)
	} else {
		return termios.Tiocmbic(uintptr(t.fd), &bits)
	}
}

// DTR returns the state of the DTR (data terminal ready) signal.
func (t *Term) DTR() (bool, error) {
	var status int
	err := termios.Tiocmget(uintptr(t.fd), &status)
	return status&syscall.TIOCM_DTR == syscall.TIOCM_DTR, err
}

// Restore restores the state of the terminal captured at the point that
// the terminal was originally opened.
func (t *Term) Restore() error {
	return termios.Tcsetattr(uintptr(t.fd), termios.TCIOFLUSH, &t.orig)
}
<commit_msg>added support for RTS line<commit_after>// Package term manages POSIX terminals. As POSIX terminals are connected to,
// or emulate, a UART, this package also provides control over the various
// UART and serial line parameters.
package term

import (
	"io"
	"os"
	"syscall"

	"github.com/pkg/term/termios"
)

// Term represents an asynchronous communications port.
type Term struct {
	name string
	fd   int
	orig syscall.Termios // original state of the terminal, see Open and Restore
}

// Open opens an asynchronous communications port.
func Open(name string, options ...func(*Term) error) (*Term, error) {
	fd, e := syscall.Open(name, syscall.O_NOCTTY|syscall.O_CLOEXEC|syscall.O_RDWR, 0666)
	if e != nil {
		return nil, &os.PathError{"open", name, e}
	}
	t := Term{name: name, fd: fd}
	if err := termios.Tcgetattr(uintptr(t.fd), &t.orig); err != nil {
		return nil, err
	}
	return &t, t.SetOption(options...)
}

// SetOption takes one or more optoin function and applies them in order to Term.
func (t *Term) SetOption(options ...func(*Term) error) error {
	for _, opt := range options {
		if err := opt(t); err != nil {
			return err
		}
	}
	return nil
}

// Read reads up to len(b) bytes from the terminal. It returns the number of
// bytes read and an error, if any. EOF is signaled by a zero count with
// err set to io.EOF.
func (t *Term) Read(b []byte) (int, error) {
	n, e := syscall.Read(t.fd, b)
	if n < 0 {
		n = 0
	}
	if n == 0 && len(b) > 0 && e == nil {
		return 0, io.EOF
	}
	if e != nil {
		return n, &os.PathError{"read", t.name, e}
	}
	return n, nil
}

// Write writes len(b) bytes to the terminal. It returns the number of bytes
// written and an error, if any. Write returns a non-nil error when n !=
// len(b).
func (t *Term) Write(b []byte) (int, error) {
	n, e := syscall.Write(t.fd, b)
	if n < 0 {
		n = 0
	}
	if n != len(b) {
		return n, io.ErrShortWrite
	}
	if e != nil {
		return n, &os.PathError{"write", t.name, e}
	}
	return n, nil
}

// Close closes the device and releases any associated resources.
func (t *Term) Close() error {
	err := syscall.Close(t.fd)
	t.fd = -1
	return err
}

// SetCbreak sets cbreak mode.
func (t *Term) SetCbreak() error {
	return t.SetOption(CBreakMode)
}

// CBreakMode places the terminal into cbreak mode.
func CBreakMode(t *Term) error {
	var a attr
	if err := termios.Tcgetattr(uintptr(t.fd), (*syscall.Termios)(&a)); err != nil {
		return err
	}
	termios.Cfmakecbreak((*syscall.Termios)(&a))
	return termios.Tcsetattr(uintptr(t.fd), termios.TCSANOW, (*syscall.Termios)(&a))
}

// SetRaw sets raw mode.
func (t *Term) SetRaw() error {
	return t.SetOption(RawMode)
}

// RawMode places the terminal into raw mode.
func RawMode(t *Term) error {
	var a attr
	if err := termios.Tcgetattr(uintptr(t.fd), (*syscall.Termios)(&a)); err != nil {
		return err
	}
	termios.Cfmakeraw((*syscall.Termios)(&a))
	return termios.Tcsetattr(uintptr(t.fd), termios.TCSANOW, (*syscall.Termios)(&a))
}

// Speed sets the baud rate option for the terminal.
func Speed(baud int) func(*Term) error {
	return func(t *Term) error {
		return t.setSpeed(baud)
	}
}

// SetSpeed sets the receive and transmit baud rates.
func (t *Term) SetSpeed(baud int) error {
	return t.SetOption(Speed(baud))
}

func (t *Term) setSpeed(baud int) error {
	var a attr
	if err := termios.Tcgetattr(uintptr(t.fd), (*syscall.Termios)(&a)); err != nil {
		return err
	}
	a.setSpeed(baud)
	return termios.Tcsetattr(uintptr(t.fd), termios.TCSANOW, (*syscall.Termios)(&a))
}

// Flush flushes both data received but not read, and data written but not transmitted.
func (t *Term) Flush() error {
	return termios.Tcflush(uintptr(t.fd), termios.TCIOFLUSH)
}

// SendBreak sends a break signal.
func (t *Term) SendBreak() error {
	return termios.Tcsendbreak(uintptr(t.fd), 0)
}

// SetDTR sets the DTR (data terminal ready) signal.
func (t *Term) SetDTR(v bool) error {
	bits := syscall.TIOCM_DTR
	if v {
		return termios.Tiocmbis(uintptr(t.fd), &bits)
	} else {
		return termios.Tiocmbic(uintptr(t.fd), &bits)
	}
}

// DTR returns the state of the DTR (data terminal ready) signal.
func (t *Term) DTR() (bool, error) {
	var status int
	err := termios.Tiocmget(uintptr(t.fd), &status)
	return status&syscall.TIOCM_DTR == syscall.TIOCM_DTR, err
}

// SetRTS sets the RTS (data terminal ready) signal.
func (t *Term) SetRTS(v bool) error {
	bits := syscall.TIOCM_RTS
	if v {
		return termios.Tiocmbis(uintptr(t.fd), &bits)
	} else {
		return termios.Tiocmbic(uintptr(t.fd), &bits)
	}
}

// RTS returns the state of the RTS (data terminal ready) signal.
func (t *Term) RTS() (bool, error) {
	var status int
	err := termios.Tiocmget(uintptr(t.fd), &status)
	return status&syscall.TIOCM_RTS == syscall.TIOCM_RTS, err
}

// Restore restores the state of the terminal captured at the point that
// the terminal was originally opened.
func (t *Term) Restore() error {
	return termios.Tcsetattr(uintptr(t.fd), termios.TCIOFLUSH, &t.orig)
}
<|endoftext|>


<commit_before>package leakybucket

import (
	"math"
	"sync"
	"testing"
	"time"
)

// CreateTest returns a test of bucket creation for a given storage backend.
// It is meant to be used by leakybucket implementers who wish to test this.
func CreateTest(s Storage) func(*testing.T) {
	return func(t *testing.T) {
		now := time.Now()
		bucket, err := s.Create("testbucket", 100, time.Minute)
		if err != nil {
			t.Fatal(err)
		}
		if capacity := bucket.Capacity(); capacity != 100 {
			t.Fatalf("expected capacity of %d, got %d", 100, capacity)
		}
		e := float64(1 * time.Second) // margin of error
		if error := float64(bucket.Reset().Sub(now.Add(time.Minute))); math.Abs(error) > e {
			t.Fatalf("expected reset time close to %s, got %s", now.Add(time.Minute),
				bucket.Reset())
		}
	}
}

// AddTest returns a test that adding to a single bucket works.
// It is meant to be used by leakybucket implementers who wish to test this.
func AddTest(s Storage) func(*testing.T) {
	return func(t *testing.T) {
		bucket, err := s.Create("testbucket", 10, time.Minute)
		if err != nil {
			t.Fatal(err)
		}

		if state, err := bucket.Add(1); err != nil {
			t.Fatal(err)
		} else if bucket.Remaining() != state.Remaining {
			t.Fatalf("expected bucket and state remaining to match, bucket is %d, state is %d",
				bucket.Remaining(), state.Remaining)
		} else if state.Remaining != 9 {
			t.Fatalf("expected 9 remaining, got %d", state.Remaining)
		}

		if state, err := bucket.Add(3); err != nil {
			t.Fatal(err)
		} else if bucket.Remaining() != state.Remaining {
			t.Fatalf("expected bucket and state remaining to match, bucket is %d, state is %d",
				bucket.Remaining(), state.Remaining)
		} else if state.Remaining != 6 {
			t.Fatalf("expected 6 remaining, got %d", state.Remaining)
		}

		if state, err := bucket.Add(6); err != nil {
			t.Fatal(err)
		} else if bucket.Remaining() != state.Remaining {
			t.Fatalf("expected bucket and state remaining to match, bucket is %d, state is %d",
				bucket.Remaining(), state.Remaining)
		} else if state.Remaining != 0 {
			t.Fatalf("expected 0 remaining, got %d", state.Remaining)
		}

		if _, err := bucket.Add(1); err == nil {
			t.Fatalf("expected ErrorFull, received no error")
		} else if err != ErrorFull {
			t.Fatalf("expected ErrorFull, received %v", err)
		}
	}
}

// ThreadSafeAddTest returns a test that adding to a single bucket is thread-safe.
// It is meant to be used by leakybucket implementers who wish to test this.
func ThreadSafeAddTest(s Storage) func(*testing.T) {
	return func(t *testing.T) {
		// Make a bucket of size `n`. Spawn `n+1` goroutines that each try to take one token.
		// We should see the bucket transition through having `n-1`, `n-2`, ... 0 remaining capacity.
		// We should also witness one error when the bucket has reached capacity.
		n := 100
		bucket, err := s.Create("testbucket", uint(n), time.Minute)
		if err != nil {
			t.Fatal(err)
		}
		remaining := map[uint]bool{}     // record observed "remaining" counts. (ab)using map as set here
		remainingMutex := sync.RWMutex{} // maps are not threadsafe
		errors := []error{}              // record observed errors
		var wg sync.WaitGroup
		for i := 0; i < n+1; i++ {
			wg.Add(1)
			go func() {
				defer wg.Done()
				state, err := bucket.Add(1)
				if err != nil {
					errors = append(errors, err)
				} else {
					remainingMutex.Lock()
					defer remainingMutex.Unlock()
					remaining[state.Remaining] = true
				}
			}()
		}
		wg.Wait()
		if len(remaining) != n {
			t.Fatalf("Did not observe correct bucket states: %#v, %#v", remaining, errors)
		}
		if len(errors) != 1 && errors[0] != ErrorFull {
			t.Fatalf("Did not observe one full error: %#v", errors)
		}
	}
}
<commit_msg>test: AddTest: DRY<commit_after>package leakybucket

import (
	"math"
	"sync"
	"testing"
	"time"
)

// CreateTest returns a test of bucket creation for a given storage backend.
// It is meant to be used by leakybucket implementers who wish to test this.
func CreateTest(s Storage) func(*testing.T) {
	return func(t *testing.T) {
		now := time.Now()
		bucket, err := s.Create("testbucket", 100, time.Minute)
		if err != nil {
			t.Fatal(err)
		}
		if capacity := bucket.Capacity(); capacity != 100 {
			t.Fatalf("expected capacity of %d, got %d", 100, capacity)
		}
		e := float64(1 * time.Second) // margin of error
		if error := float64(bucket.Reset().Sub(now.Add(time.Minute))); math.Abs(error) > e {
			t.Fatalf("expected reset time close to %s, got %s", now.Add(time.Minute),
				bucket.Reset())
		}
	}
}

// AddTest returns a test that adding to a single bucket works.
// It is meant to be used by leakybucket implementers who wish to test this.
func AddTest(s Storage) func(*testing.T) {
	return func(t *testing.T) {
		bucket, err := s.Create("testbucket", 10, time.Minute)
		if err != nil {
			t.Fatal(err)
		}

		addAndTestRemaining := func(add, remaining uint) {
			if state, err := bucket.Add(add); err != nil {
				t.Fatal(err)
			} else if bucket.Remaining() != state.Remaining {
				t.Fatalf("expected bucket and state remaining to match, bucket is %d, state is %d",
					bucket.Remaining(), state.Remaining)
			} else if state.Remaining != remaining {
				t.Fatalf("expected %d remaining, got %d", remaining, state.Remaining)
			}
		}

		addAndTestRemaining(1, 9)
		addAndTestRemaining(3, 6)
		addAndTestRemaining(6, 0)

		if _, err := bucket.Add(1); err == nil {
			t.Fatalf("expected ErrorFull, received no error")
		} else if err != ErrorFull {
			t.Fatalf("expected ErrorFull, received %v", err)
		}
	}
}

// ThreadSafeAddTest returns a test that adding to a single bucket is thread-safe.
// It is meant to be used by leakybucket implementers who wish to test this.
func ThreadSafeAddTest(s Storage) func(*testing.T) {
	return func(t *testing.T) {
		// Make a bucket of size `n`. Spawn `n+1` goroutines that each try to take one token.
		// We should see the bucket transition through having `n-1`, `n-2`, ... 0 remaining capacity.
		// We should also witness one error when the bucket has reached capacity.
		n := 100
		bucket, err := s.Create("testbucket", uint(n), time.Minute)
		if err != nil {
			t.Fatal(err)
		}
		remaining := map[uint]bool{}     // record observed "remaining" counts. (ab)using map as set here
		remainingMutex := sync.RWMutex{} // maps are not threadsafe
		errors := []error{}              // record observed errors
		var wg sync.WaitGroup
		for i := 0; i < n+1; i++ {
			wg.Add(1)
			go func() {
				defer wg.Done()
				state, err := bucket.Add(1)
				if err != nil {
					errors = append(errors, err)
				} else {
					remainingMutex.Lock()
					defer remainingMutex.Unlock()
					remaining[state.Remaining] = true
				}
			}()
		}
		wg.Wait()
		if len(remaining) != n {
			t.Fatalf("Did not observe correct bucket states: %#v, %#v", remaining, errors)
		}
		if len(errors) != 1 && errors[0] != ErrorFull {
			t.Fatalf("Did not observe one full error: %#v", errors)
		}
	}
}
<|endoftext|>


<commit_before>package main

import (
	. "fmt"
	"github.com/google/go-github/github"
	"golang.org/x/oauth2"
	"io/ioutil"
)

func main() {
	fi, err := ioutil.ReadFile("./token")
	if err != nil {
		panic(err)
	}

	//fi := string(fi)

	//resp, _ := http.Get("https://api.github.com/user/ccqpein")
	//Print(resp)

	ts := oauth2.StaticTokenSource(
		&oauth2.Token{AccessToken: string(fi)},
	)

	tc := oauth2.NewClient(oauth2.NoContext, ts)
	client := github.NewClient(tc)

	repos, _, err := client.Repositories.ListContributorsStats("ccqpein", "what_to_eat")

	Println(repos)
	//Println(repp)
}
<commit_msg>change api<commit_after>package main

import (
	. "fmt"
	"github.com/google/go-github/github"
	"golang.org/x/oauth2"
	"io/ioutil"
)

func main() {
	fi, err := ioutil.ReadFile("./token")
	if err != nil {
		panic(err)
	}

	ts := oauth2.StaticTokenSource(
		&oauth2.Token{AccessToken: string(fi)},
	)
	tc := oauth2.NewClient(oauth2.NoContext, ts)
	client := github.NewClient(tc)

	repos, _, err := client.Repositories.List("ccqpein", nil)
	for _, repo := range repos {
		name := string(repo.Name)
		Printf(name)
	}
	//reposs, _, err := client.Repositories.ListCodeFrequency("ccqpein", "Arithmetic-Exercises")

	//Println(reposs)
}
<|endoftext|>


<commit_before>/* text.go contains functions for text annotation
TODO:
getters and setters for
- Stretch (redefine C type)
- Weight (uint)
- Style (redefine C type)
- Resolution (two doubles)
- Antialias (bool)
- Decoration (redefine C type)
- Encoding (string)
*/

package canvas

/*
#cgo CFLAGS: -fopenmp -I./_include
#cgo LDFLAGS: -lMagickWand -lMagickCore

#include <wand/magick_wand.h>
*/
import "C"

import (
	"unsafe"
)

type Alignment uint

const (
 	UndefinedAlign Alignment	= Alignment(C.UndefinedAlign)
	LeftAlign					= Alignment(C.LeftAlign)
	CenterAlign					= Alignment(C.CenterAlign)
	RightAlign					= Alignment(C.RightAlign)
)

// structure containing all text properties for an annotation
// except the colors that are defined by FillColor and StrokeColor
type TextProperties struct {
	Font		string
	Family		string
	Size		float64
	// Stretch		C.StretchType
	// Weight		uint
	// Style		C.StyleType
	// Resolution  [2]C.double
	Alignment	Alignment
	// Antialias	bool
	// Decoration	C.DecorationType
	// Encoding	string
	UnderColor	*C.PixelWand
}

// Returns a TextProperties structure.
// Parameters:
//   read_default: if false, returns an empty structure.
//				   if true, returns a structure set with current canvas settings
func (self *Canvas) NewTextProperties(read_default bool) *TextProperties {
	if read_default == true {
		cfont := C.DrawGetFont(self.drawing)
		defer C.free(unsafe.Pointer(cfont))
		cfamily := C.DrawGetFontFamily(self.drawing)
		defer C.free(unsafe.Pointer(cfamily))
		csize := C.DrawGetFontSize(self.drawing)
		calignment := C.DrawGetTextAlignment(self.drawing)
		underColor :=C.NewPixelWand()
		C.DrawGetTextUnderColor(self.drawing, underColor)
		return &TextProperties{
			Font: C.GoString(cfont),
			Family: C.GoString(cfamily),
			Size: float64(csize),
			Alignment: Alignment(calignment),
			UnderColor: underColor,
		}
	}
	return &TextProperties{
		UnderColor: C.NewPixelWand(),
	}
}

// Sets canvas' default TextProperties
func (self *Canvas) SetTextProperties(def *TextProperties) {
	if def != nil {
		self.text = def
		self.SetFont(def.Font, def.Size)
		self.SetFontFamily(def.Family)
		self.SetTextAlignment(def.Alignment)
	}
}

// Gets a copy of canvas' current TextProperties
func (self *Canvas) TextProperties() *TextProperties {
	if self.text == nil {
		return nil
	}
	cpy := *self.text
	return &cpy
}

// Sets canvas' default font name
func (self *Canvas) SetFontName(font string) {
	self.text.Font = font
	cfont := C.CString(font)
	defer C.free(unsafe.Pointer(cfont))
	C.DrawSetFont(self.drawing, cfont)
}

// Returns canvas' current font name
func (self *Canvas) FontName() string {
	return self.text.Font
}

// Sets canvas' default font family
func (self *Canvas) SetFontFamily(family string) {
	self.text.Family = family
	cfamily := C.CString(family)
	defer C.free(unsafe.Pointer(cfamily))
	C.DrawSetFontFamily(self.drawing, cfamily)
}

// Returns canvas' current font family
func (self *Canvas) FontFamily() string {
	return self.text.Family
}

// Sets canvas' default font size
func (self *Canvas) SetFontSize(size float64) {
	self.text.Size = size
	C.DrawSetFontSize(self.drawing, C.double(size))
}

// Returns canvas' current font size
func (self *Canvas) FontSize() float64 {
	return self.text.Size
}

// Sets canvas' font name and size.
// If font is 0-length, the current font family is not changed
// If size is <= 0, the current font size is not changed
func (self *Canvas) SetFont(font string, size float64) {
	if len(font) > 0 {
		self.SetFontName(font)
	}
	if size > 0 {
		self.SetFontSize(size)
	}
}

// Returns canvas' current font name and size
func (self *Canvas) Font() (string, float64) {
	return self.text.Font, self.text.Size
}

// Sets canvas' default text alignment. Available values are:
// UndefinedAlign (?), LeftAlign, CenterAlign, RightAlign
func (self *Canvas) SetTextAlignment(a Alignment) {
	self.text.Alignment = a
	C.DrawSetTextAlignment(self.drawing, C.AlignType(a))
}

// Returns the canvas' current text aligment
func (self *Canvas) TextAlignment() Alignment {
	return self.text.Alignment
}

// Draws a string at the specified coordinates and using the current canvas
// Alignment.
func (self *Canvas) Annotate(text string, x, y float64) {
	c_text := C.CString(text)
	defer C.free(unsafe.Pointer(c_text))
	C.DrawAnnotation(self.drawing, C.double(x), C.double(y), (*C.uchar)(unsafe.Pointer(c_text)))
}

// Draws a string at the specified coordinates and using the specified Text Properties
// Does not modify the canvas' default TextProperties
func (self *Canvas) AnnotateWithProperties(text string, x, y float64, prop *TextProperties) {
	if prop != nil {
		tmp := self.TextProperties()
		self.SetTextProperties(prop)
		self.Annotate(text, x, y)
		self.SetTextProperties(tmp)
	} else {
		self.Annotate(text, x, y)
	}
}
<commit_msg>Add TextAntialias() and SetTextAntialias() Add calls in NewTextProperties() and SetTextProperties()<commit_after>/* text.go contains functions for text annotation
TODO:
getters and setters for
- Stretch (redefine C type)
- Weight (uint)
- Style (redefine C type)
- Resolution (two doubles)
- Decoration (redefine C type)
- Encoding (string)
*/

package canvas

/*
#cgo CFLAGS: -fopenmp -I./_include
#cgo LDFLAGS: -lMagickWand -lMagickCore

#include <wand/magick_wand.h>
*/
import "C"

import (
	"unsafe"
)

type Alignment uint

const (
 	UndefinedAlign Alignment	= Alignment(C.UndefinedAlign)
	LeftAlign					= Alignment(C.LeftAlign)
	CenterAlign					= Alignment(C.CenterAlign)
	RightAlign					= Alignment(C.RightAlign)
)

// structure containing all text properties for an annotation
// except the colors that are defined by FillColor and StrokeColor
type TextProperties struct {
	Font		string
	Family		string
	Size		float64
	// Stretch		C.StretchType
	// Weight		uint
	// Style		C.StyleType
	// Resolution  [2]C.double
	Alignment	Alignment
	Antialias	bool
	// Decoration	C.DecorationType
	// Encoding	string
	UnderColor	*C.PixelWand
}

// Returns a TextProperties structure.
// Parameters:
//   read_default: if false, returns an empty structure.
//				   if true, returns a structure set with current canvas settings
func (self *Canvas) NewTextProperties(read_default bool) *TextProperties {
	if read_default == true {
		cfont := C.DrawGetFont(self.drawing)
		defer C.free(unsafe.Pointer(cfont))
		cfamily := C.DrawGetFontFamily(self.drawing)
		defer C.free(unsafe.Pointer(cfamily))
		csize := C.DrawGetFontSize(self.drawing)
		calignment := C.DrawGetTextAlignment(self.drawing)
		cantialias := C.DrawGetTextAntialias(self.drawing)
		antialias := false
		if cantialias == C.MagickTrue {
			antialias = true
		}

		underColor :=C.NewPixelWand()
		C.DrawGetTextUnderColor(self.drawing, underColor)
		return &TextProperties{
			Font: C.GoString(cfont),
			Family: C.GoString(cfamily),
			Size: float64(csize),
			Alignment: Alignment(calignment),
			Antialias: antialias,
			UnderColor: underColor,
		}
	}
	return &TextProperties{
		UnderColor: C.NewPixelWand(),
	}
}

// Sets canvas' default TextProperties
func (self *Canvas) SetTextProperties(def *TextProperties) {
	if def != nil {
		self.text = def
		self.SetFont(def.Font, def.Size)
		self.SetFontFamily(def.Family)
		self.SetTextAlignment(def.Alignment)
		self.SetTextAntialias(def.Antialias)
	}
}

// Gets a copy of canvas' current TextProperties
func (self *Canvas) TextProperties() *TextProperties {
	if self.text == nil {
		return nil
	}
	cpy := *self.text
	return &cpy
}

// Sets canvas' default font name
func (self *Canvas) SetFontName(font string) {
	self.text.Font = font
	cfont := C.CString(font)
	defer C.free(unsafe.Pointer(cfont))
	C.DrawSetFont(self.drawing, cfont)
}

// Returns canvas' current font name
func (self *Canvas) FontName() string {
	return self.text.Font
}

// Sets canvas' default font family
func (self *Canvas) SetFontFamily(family string) {
	self.text.Family = family
	cfamily := C.CString(family)
	defer C.free(unsafe.Pointer(cfamily))
	C.DrawSetFontFamily(self.drawing, cfamily)
}

// Returns canvas' current font family
func (self *Canvas) FontFamily() string {
	return self.text.Family
}

// Sets canvas' default font size
func (self *Canvas) SetFontSize(size float64) {
	self.text.Size = size
	C.DrawSetFontSize(self.drawing, C.double(size))
}

// Returns canvas' current font size
func (self *Canvas) FontSize() float64 {
	return self.text.Size
}

// Sets canvas' font name and size.
// If font is 0-length, the current font family is not changed
// If size is <= 0, the current font size is not changed
func (self *Canvas) SetFont(font string, size float64) {
	if len(font) > 0 {
		self.SetFontName(font)
	}
	if size > 0 {
		self.SetFontSize(size)
	}
}

// Returns canvas' current font name and size
func (self *Canvas) Font() (string, float64) {
	return self.text.Font, self.text.Size
}

// Sets canvas' default text alignment. Available values are:
// UndefinedAlign (?), LeftAlign, CenterAlign, RightAlign
func (self *Canvas) SetTextAlignment(a Alignment) {
	self.text.Alignment = a
	C.DrawSetTextAlignment(self.drawing, C.AlignType(a))
}

// Returns the canvas' current text aligment
func (self *Canvas) TextAlignment() Alignment {
	return self.text.Alignment
}

// Sets canvas' default text antialiasing option.
func (self *Canvas) SetTextAntialias(b bool) {
	self.text.Antialias = b
	C.DrawSetTextAntialias(self.drawing, magickBoolean(b))
}

// Returns the canvas' current text aligment
func (self *Canvas) TextAntialias() bool {
	return self.text.Antialias
}

// Draws a string at the specified coordinates and using the current canvas
// Alignment.
func (self *Canvas) Annotate(text string, x, y float64) {
	c_text := C.CString(text)
	defer C.free(unsafe.Pointer(c_text))
	C.DrawAnnotation(self.drawing, C.double(x), C.double(y), (*C.uchar)(unsafe.Pointer(c_text)))
}

// Draws a string at the specified coordinates and using the specified Text Properties
// Does not modify the canvas' default TextProperties
func (self *Canvas) AnnotateWithProperties(text string, x, y float64, prop *TextProperties) {
	if prop != nil {
		tmp := self.TextProperties()
		self.SetTextProperties(prop)
		self.Annotate(text, x, y)
		self.SetTextProperties(tmp)
	} else {
		self.Annotate(text, x, y)
	}
}
<|endoftext|>


<commit_before>package frame

import (
	"image"
	"image/draw"
)

const (
	TickWidth = 3
	tickOff   = 0
	tickOn    = 1
)

func (f *Frame) Untick() {
	if f.p0 == f.p1 {
		f.tickat(f.PointOf(int64(f.p0)), false)
	}
}
func (f *Frame) Tick() {
	if f.p0 == f.p1 {
		f.tickat(f.PointOf(int64(f.p0)), true)
	}
}

func (f *Frame) SetTick(style int) {
	f.tickoff = style == tickOff
}
func (f *Frame) inittick() {
	h := f.Font.Dy()
	r := image.Rect(0, 0, TickWidth, h).Inset(-1)
	f.tickscale = 1 // TODO implement scalesize
	f.tick = image.NewRGBA(r)
	f.tickback = image.NewRGBA(r)
	drawtick := func(x0, y0, x1, y1 int) {
		draw.Draw(f.tick, image.Rect(x0+1, y0+1, x1+1, y1+1), f.Color.Text, image.ZP, draw.Src)
	}
	drawtick(TickWidth/2, 0, TickWidth/2+1, h)
	drawtick(0, 0, TickWidth, h/5)
	drawtick(0, h-h/5, TickWidth, h)
}

// Put
func (f *Frame) tickat(pt image.Point, ticked bool) {
	if f.Ticked == ticked || f.tick == nil || !pt.In(f.Bounds().Inset(-1)) {
		return
	}
	//pt.X--
	r := f.tick.Bounds().Add(pt)
	if r.Max.X > f.r.Max.X {
		r.Max.X = f.r.Max.X
	} //
	adj := image.Pt(1, 1)
	if ticked {
		f.Draw(f.tickback, f.tickback.Bounds(), f.b, pt.Sub(adj), draw.Src)
		f.Draw(f.b, r.Sub(adj), f.tick, image.ZP, draw.Over)
	} else {
		f.Draw(f.b, r, f.tickback, image.ZP.Sub(adj), draw.Src)
	}
	f.Ticked = ticked
}
<commit_msg>Fixes as/a#36<commit_after>package frame

import (
	"image"
	"image/draw"
)

const (
	TickWidth = 3
	tickOff   = 0
	tickOn    = 1
)

func (f *Frame) Untick() {
	if f.p0 == f.p1 {
		f.tickat(f.PointOf(int64(f.p0)), false)
	}
}
func (f *Frame) Tick() {
	if f.p0 == f.p1 {
		f.tickat(f.PointOf(int64(f.p0)), true)
	}
}

func (f *Frame) SetTick(style int) {
	f.tickoff = style == tickOff
}
func (f *Frame) inittick() {
	h := f.Font.Dy()
	r := image.Rect(0, 0, TickWidth, h).Inset(-1)
	f.tickscale = 1 // TODO implement scalesize
	f.tick = image.NewRGBA(r)
	f.tickback = image.NewRGBA(r)
	drawtick := func(x0, y0, x1, y1 int) {
		draw.Draw(f.tick, image.Rect(x0+1, y0+1, x1+1, y1+1), f.Color.Text, image.ZP, draw.Src)
	}
	drawtick(TickWidth/2, 0, TickWidth/2+1, h)
	drawtick(0, 0, TickWidth, h/5)
	drawtick(0, h-h/5, TickWidth, h)
}

// Put
func (f *Frame) tickat(pt image.Point, ticked bool) {
	if f.Ticked == ticked || f.tick == nil || !pt.In(f.Bounds().Inset(-1)) {
		return
	}
	//pt.X--
	r := f.tick.Bounds().Add(pt)
	if r.Max.X > f.r.Max.X {
		r.Max.X = f.r.Max.X
	} //
	adj := image.Pt(1, 1)
	if ticked {
		draw.Draw(f.tickback, f.tickback.Bounds(), f.b, pt.Sub(adj), draw.Src)
		f.Draw(f.b, r.Sub(adj), f.tick, image.ZP, draw.Over)
	} else {
		f.Draw(f.b, r, f.tickback, image.ZP.Sub(adj), draw.Src)
	}
	f.Ticked = ticked
}
<|endoftext|>


<commit_before>package com

import (
	"time"
	"strings"
	"fmt"
	"strconv"
)

// format unix time int to string
func Date(ti int64, format string) string {
	t := time.Unix(int64(ti), 0)
	return DateT(t, format)
}

// format unix time string to string
func DateS(ts string, format string) string {
	i, _ := strconv.ParseInt(ts, 10, 64)
	return DateT(i, format)
}

// format time.Time to string
func DateT(t time.Time, format string) string {
	res := strings.Replace(format, "MM", t.Format("01"), -1)
	res = strings.Replace(res, "M", t.Format("1"), -1)
	res = strings.Replace(res, "DD", t.Format("02"), -1)
	res = strings.Replace(res, "D", t.Format("2"), -1)
	res = strings.Replace(res, "YYYY", t.Format("2006"), -1)
	res = strings.Replace(res, "YY", t.Format("06"), -1)
	res = strings.Replace(res, "HH", fmt.Sprintf("%02d", t.Hour()), -1)
	res = strings.Replace(res, "H", fmt.Sprintf("%d", t.Hour()), -1)
	res = strings.Replace(res, "hh", t.Format("03"), -1)
	res = strings.Replace(res, "h", t.Format("3"), -1)
	res = strings.Replace(res, "mm", t.Format("04"), -1)
	res = strings.Replace(res, "m", t.Format("4"), -1)
	res = strings.Replace(res, "ss", t.Format("05"), -1)
	res = strings.Replace(res, "s", t.Format("5"), -1)
	return res
}

// get now unix timestamp int64
func Now() int64 {
	return time.Now().Unix()
}

<commit_msg>add comments in time.go<commit_after>// Copyright 2013 com authors
//
// 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 com

import (
	"time"
	"strings"
	"fmt"
	"strconv"
)

// Format unix time int64 to string
func Date(ti int64, format string) string {
	t := time.Unix(int64(ti), 0)
	return DateT(t, format)
}

// Format unix time string to string
func DateS(ts string, format string) string {
	i, _ := strconv.ParseInt(ts, 10, 64)
	return Date(i, format)
}

// Format time.Time struct to string
// MM - month - 01
// M - month - 1, single bit
// DD - day - 02
// D - day 2
// YYYY - year - 2006
// YY - year - 06
// HH - 24 hours - 03
// H - 24 hours - 3
// hh - 12 hours - 03
// h - 12 hours - 3
// mm - minute - 04
// m - minute - 4
// ss - second - 05
// s - second = 5
func DateT(t time.Time, format string) string {
	res := strings.Replace(format, "MM", t.Format("01"), -1)
	res = strings.Replace(res, "M", t.Format("1"), -1)
	res = strings.Replace(res, "DD", t.Format("02"), -1)
	res = strings.Replace(res, "D", t.Format("2"), -1)
	res = strings.Replace(res, "YYYY", t.Format("2006"), -1)
	res = strings.Replace(res, "YY", t.Format("06"), -1)
	res = strings.Replace(res, "HH", fmt.Sprintf("%02d", t.Hour()), -1)
	res = strings.Replace(res, "H", fmt.Sprintf("%d", t.Hour()), -1)
	res = strings.Replace(res, "hh", t.Format("03"), -1)
	res = strings.Replace(res, "h", t.Format("3"), -1)
	res = strings.Replace(res, "mm", t.Format("04"), -1)
	res = strings.Replace(res, "m", t.Format("4"), -1)
	res = strings.Replace(res, "ss", t.Format("05"), -1)
	res = strings.Replace(res, "s", t.Format("5"), -1)
	return res
}

// Get unix stamp int64 of now
func Now() int64 {
	return time.Now().Unix()
}

<|endoftext|>


<commit_before>// Copyright 2015 go-swagger maintainers
//
// 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 strfmt

import (
	"database/sql/driver"
	"encoding/binary"
	"encoding/json"
	"fmt"
	"regexp"
	"strings"
	"time"

	"go.mongodb.org/mongo-driver/bson"

	"go.mongodb.org/mongo-driver/bson/bsontype"
)

func init() {
	dt := DateTime{}
	Default.Add("datetime", &dt, IsDateTime)
}

// IsDateTime returns true when the string is a valid date-time
func IsDateTime(str string) bool {
	if len(str) < 4 {
		return false
	}
	s := strings.Split(strings.ToLower(str), "t")
	if len(s) < 2 || !IsDate(s[0]) {
		return false
	}

	matches := rxDateTime.FindAllStringSubmatch(s[1], -1)
	if len(matches) == 0 || len(matches[0]) == 0 {
		return false
	}
	m := matches[0]
	res := m[1] <= "23" && m[2] <= "59" && m[3] <= "59"
	return res
}

const (
	// RFC3339Millis represents a ISO8601 format to millis instead of to nanos
	RFC3339Millis = "2006-01-02T15:04:05.000Z07:00"
	// RFC3339MillisNoColon represents a ISO8601 format to millis instead of to nanos
	RFC3339MillisNoColon = "2006-01-02T15:04:05.000Z0700"
	// RFC3339Micro represents a ISO8601 format to micro instead of to nano
	RFC3339Micro = "2006-01-02T15:04:05.000000Z07:00"
	// RFC3339MicroNoColon represents a ISO8601 format to micro instead of to nano
	RFC3339MicroNoColon = "2006-01-02T15:04:05.000000Z0700"
	// ISO8601LocalTime represents a ISO8601 format to ISO8601 in local time (no timezone)
	ISO8601LocalTime = "2006-01-02T15:04:05"
	// ISO8601TimeWithReducedPrecision represents a ISO8601 format with reduced precision (dropped secs)
	ISO8601TimeWithReducedPrecision = "2006-01-02T15:04Z"
	// ISO8601TimeWithReducedPrecisionLocaltime represents a ISO8601 format with reduced precision and no timezone (dropped seconds + no timezone)
	ISO8601TimeWithReducedPrecisionLocaltime = "2006-01-02T15:04"
	// ISO8601TimeUniversalSortableDateTimePattern represents a ISO8601 universal sortable date time pattern.
	ISO8601TimeUniversalSortableDateTimePattern = "2006-01-02 15:04:05"
	// DateTimePattern pattern to match for the date-time format from http://tools.ietf.org/html/rfc3339#section-5.6
	DateTimePattern = `^([0-9]{2}):([0-9]{2}):([0-9]{2})(.[0-9]+)?(z|([+-][0-9]{2}:[0-9]{2}))$`
)

var (
	rxDateTime = regexp.MustCompile(DateTimePattern)

	// DateTimeFormats is the collection of formats used by ParseDateTime()
	DateTimeFormats = []string{RFC3339Micro, RFC3339MicroNoColon, RFC3339Millis, RFC3339MillisNoColon, time.RFC3339, time.RFC3339Nano, ISO8601LocalTime, ISO8601TimeWithReducedPrecision, ISO8601TimeWithReducedPrecisionLocaltime, ISO8601TimeUniversalSortableDateTimePattern}

	// MarshalFormat sets the time resolution format used for marshaling time (set to milliseconds)
	MarshalFormat = RFC3339Millis

	// NormalizeTimeForMarshal provides a normalization function on time befeore marshalling (e.g. time.UTC).
	// By default, the time value is not changed.
	NormalizeTimeForMarshal = func(t time.Time) time.Time { return t }
)

// ParseDateTime parses a string that represents an ISO8601 time or a unix epoch
func ParseDateTime(data string) (DateTime, error) {
	if data == "" {
		return NewDateTime(), nil
	}
	var lastError error
	for _, layout := range DateTimeFormats {
		dd, err := time.Parse(layout, data)
		if err != nil {
			lastError = err
			continue
		}
		return DateTime(dd), nil
	}
	return DateTime{}, lastError
}

// DateTime is a time but it serializes to ISO8601 format with millis
// It knows how to read 3 different variations of a RFC3339 date time.
// Most APIs we encounter want either millisecond or second precision times.
// This just tries to make it worry-free.
//
// swagger:strfmt date-time
type DateTime time.Time

// NewDateTime is a representation of zero value for DateTime type
func NewDateTime() DateTime {
	return DateTime(time.Unix(0, 0).UTC())
}

// String converts this time to a string
func (t DateTime) String() string {
	return NormalizeTimeForMarshal(time.Time(t)).Format(MarshalFormat)
}

// MarshalText implements the text marshaller interface
func (t DateTime) MarshalText() ([]byte, error) {
	return []byte(t.String()), nil
}

// UnmarshalText implements the text unmarshaller interface
func (t *DateTime) UnmarshalText(text []byte) error {
	tt, err := ParseDateTime(string(text))
	if err != nil {
		return err
	}
	*t = tt
	return nil
}

// Scan scans a DateTime value from database driver type.
func (t *DateTime) Scan(raw interface{}) error {
	// TODO: case int64: and case float64: ?
	switch v := raw.(type) {
	case []byte:
		return t.UnmarshalText(v)
	case string:
		return t.UnmarshalText([]byte(v))
	case time.Time:
		*t = DateTime(v)
	case nil:
		*t = DateTime{}
	default:
		return fmt.Errorf("cannot sql.Scan() strfmt.DateTime from: %#v", v)
	}

	return nil
}

// Value converts DateTime to a primitive value ready to written to a database.
func (t DateTime) Value() (driver.Value, error) {
	return driver.Value(t.String()), nil
}

// MarshalJSON returns the DateTime as JSON
func (t DateTime) MarshalJSON() ([]byte, error) {
	return json.Marshal(NormalizeTimeForMarshal(time.Time(t)).Format(MarshalFormat))
}

// UnmarshalJSON sets the DateTime from JSON
func (t *DateTime) UnmarshalJSON(data []byte) error {
	if string(data) == jsonNull {
		return nil
	}

	var tstr string
	if err := json.Unmarshal(data, &tstr); err != nil {
		return err
	}
	tt, err := ParseDateTime(tstr)
	if err != nil {
		return err
	}
	*t = tt
	return nil
}

// MarshalBSON renders the DateTime as a BSON document
func (t DateTime) MarshalBSON() ([]byte, error) {
	return bson.Marshal(bson.M{"data": t})
}

// UnmarshalBSON reads the DateTime from a BSON document
func (t *DateTime) UnmarshalBSON(data []byte) error {
	var obj struct {
		Data DateTime
	}

	if err := bson.Unmarshal(data, &obj); err != nil {
		return err
	}

	*t = obj.Data

	return nil
}

// MarshalBSONValue is an interface implemented by types that can marshal themselves
// into a BSON document represented as bytes. The bytes returned must be a valid
// BSON document if the error is nil.
// Marshals a DateTime as a bsontype.DateTime, an int64 representing
// milliseconds since epoch.
func (t DateTime) MarshalBSONValue() (bsontype.Type, []byte, error) {
	// UnixNano cannot be used directly, the result of calling UnixNano on the zero
	// Time is undefined. Thats why we use time.Nanosecond() instead.

	tNorm := NormalizeTimeForMarshal(time.Time(t))
	i64 := tNorm.Unix()*1000 + int64(tNorm.Nanosecond())/1e6

	buf := make([]byte, 8)
	binary.LittleEndian.PutUint64(buf, uint64(i64))

	return bsontype.DateTime, buf, nil
}

// UnmarshalBSONValue is an interface implemented by types that can unmarshal a
// BSON value representation of themselves. The BSON bytes and type can be
// assumed to be valid. UnmarshalBSONValue must copy the BSON value bytes if it
// wishes to retain the data after returning.
func (t *DateTime) UnmarshalBSONValue(tpe bsontype.Type, data []byte) error {
	i64 := int64(binary.LittleEndian.Uint64(data))
	// TODO: Use bsonprim.DateTime.Time() method
	*t = DateTime(time.Unix(i64/1000, i64%1000*1000000))

	return nil
}

// DeepCopyInto copies the receiver and writes its value into out.
func (t *DateTime) DeepCopyInto(out *DateTime) {
	*out = *t
}

// DeepCopy copies the receiver into a new DateTime.
func (t *DateTime) DeepCopy() *DateTime {
	if t == nil {
		return nil
	}
	out := new(DateTime)
	t.DeepCopyInto(out)
	return out
}

// GobEncode implements the gob.GobEncoder interface.
func (t DateTime) GobEncode() ([]byte, error) {
	return t.MarshalBinary()
}

// GobDecode implements the gob.GobDecoder interface.
func (t *DateTime) GobDecode(data []byte) error {
	return t.UnmarshalBinary(data)
}

// MarshalBinary implements the encoding.BinaryMarshaler interface.
func (t DateTime) MarshalBinary() ([]byte, error) {
	return NormalizeTimeForMarshal(time.Time(t)).MarshalBinary()
}

// UnmarshalBinary implements the encoding.BinaryUnmarshaler interface.
func (t *DateTime) UnmarshalBinary(data []byte) error {
	var original time.Time

	err := original.UnmarshalBinary(data)
	if err != nil {
		return err
	}

	*t = DateTime(original)

	return nil
}

// Equal checks if two DateTime instances are equal using time.Time's Equal method
func (t DateTime) Equal(t2 DateTime) bool {
	return time.Time(t).Equal(time.Time(t2))
}
<commit_msg>#97: Fixed DateTime UnmarshalBSONValue panics on a null bson value<commit_after>// Copyright 2015 go-swagger maintainers
//
// 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 strfmt

import (
	"database/sql/driver"
	"encoding/binary"
	"encoding/json"
	"errors"
	"fmt"
	"regexp"
	"strings"
	"time"

	"go.mongodb.org/mongo-driver/bson"

	"go.mongodb.org/mongo-driver/bson/bsontype"
)

func init() {
	dt := DateTime{}
	Default.Add("datetime", &dt, IsDateTime)
}

// IsDateTime returns true when the string is a valid date-time
func IsDateTime(str string) bool {
	if len(str) < 4 {
		return false
	}
	s := strings.Split(strings.ToLower(str), "t")
	if len(s) < 2 || !IsDate(s[0]) {
		return false
	}

	matches := rxDateTime.FindAllStringSubmatch(s[1], -1)
	if len(matches) == 0 || len(matches[0]) == 0 {
		return false
	}
	m := matches[0]
	res := m[1] <= "23" && m[2] <= "59" && m[3] <= "59"
	return res
}

const (
	// RFC3339Millis represents a ISO8601 format to millis instead of to nanos
	RFC3339Millis = "2006-01-02T15:04:05.000Z07:00"
	// RFC3339MillisNoColon represents a ISO8601 format to millis instead of to nanos
	RFC3339MillisNoColon = "2006-01-02T15:04:05.000Z0700"
	// RFC3339Micro represents a ISO8601 format to micro instead of to nano
	RFC3339Micro = "2006-01-02T15:04:05.000000Z07:00"
	// RFC3339MicroNoColon represents a ISO8601 format to micro instead of to nano
	RFC3339MicroNoColon = "2006-01-02T15:04:05.000000Z0700"
	// ISO8601LocalTime represents a ISO8601 format to ISO8601 in local time (no timezone)
	ISO8601LocalTime = "2006-01-02T15:04:05"
	// ISO8601TimeWithReducedPrecision represents a ISO8601 format with reduced precision (dropped secs)
	ISO8601TimeWithReducedPrecision = "2006-01-02T15:04Z"
	// ISO8601TimeWithReducedPrecisionLocaltime represents a ISO8601 format with reduced precision and no timezone (dropped seconds + no timezone)
	ISO8601TimeWithReducedPrecisionLocaltime = "2006-01-02T15:04"
	// ISO8601TimeUniversalSortableDateTimePattern represents a ISO8601 universal sortable date time pattern.
	ISO8601TimeUniversalSortableDateTimePattern = "2006-01-02 15:04:05"
	// DateTimePattern pattern to match for the date-time format from http://tools.ietf.org/html/rfc3339#section-5.6
	DateTimePattern = `^([0-9]{2}):([0-9]{2}):([0-9]{2})(.[0-9]+)?(z|([+-][0-9]{2}:[0-9]{2}))$`
)

var (
	rxDateTime = regexp.MustCompile(DateTimePattern)

	// DateTimeFormats is the collection of formats used by ParseDateTime()
	DateTimeFormats = []string{RFC3339Micro, RFC3339MicroNoColon, RFC3339Millis, RFC3339MillisNoColon, time.RFC3339, time.RFC3339Nano, ISO8601LocalTime, ISO8601TimeWithReducedPrecision, ISO8601TimeWithReducedPrecisionLocaltime, ISO8601TimeUniversalSortableDateTimePattern}

	// MarshalFormat sets the time resolution format used for marshaling time (set to milliseconds)
	MarshalFormat = RFC3339Millis

	// NormalizeTimeForMarshal provides a normalization function on time befeore marshalling (e.g. time.UTC).
	// By default, the time value is not changed.
	NormalizeTimeForMarshal = func(t time.Time) time.Time { return t }
)

// ParseDateTime parses a string that represents an ISO8601 time or a unix epoch
func ParseDateTime(data string) (DateTime, error) {
	if data == "" {
		return NewDateTime(), nil
	}
	var lastError error
	for _, layout := range DateTimeFormats {
		dd, err := time.Parse(layout, data)
		if err != nil {
			lastError = err
			continue
		}
		return DateTime(dd), nil
	}
	return DateTime{}, lastError
}

// DateTime is a time but it serializes to ISO8601 format with millis
// It knows how to read 3 different variations of a RFC3339 date time.
// Most APIs we encounter want either millisecond or second precision times.
// This just tries to make it worry-free.
//
// swagger:strfmt date-time
type DateTime time.Time

// NewDateTime is a representation of zero value for DateTime type
func NewDateTime() DateTime {
	return DateTime(time.Unix(0, 0).UTC())
}

// String converts this time to a string
func (t DateTime) String() string {
	return NormalizeTimeForMarshal(time.Time(t)).Format(MarshalFormat)
}

// MarshalText implements the text marshaller interface
func (t DateTime) MarshalText() ([]byte, error) {
	return []byte(t.String()), nil
}

// UnmarshalText implements the text unmarshaller interface
func (t *DateTime) UnmarshalText(text []byte) error {
	tt, err := ParseDateTime(string(text))
	if err != nil {
		return err
	}
	*t = tt
	return nil
}

// Scan scans a DateTime value from database driver type.
func (t *DateTime) Scan(raw interface{}) error {
	// TODO: case int64: and case float64: ?
	switch v := raw.(type) {
	case []byte:
		return t.UnmarshalText(v)
	case string:
		return t.UnmarshalText([]byte(v))
	case time.Time:
		*t = DateTime(v)
	case nil:
		*t = DateTime{}
	default:
		return fmt.Errorf("cannot sql.Scan() strfmt.DateTime from: %#v", v)
	}

	return nil
}

// Value converts DateTime to a primitive value ready to written to a database.
func (t DateTime) Value() (driver.Value, error) {
	return driver.Value(t.String()), nil
}

// MarshalJSON returns the DateTime as JSON
func (t DateTime) MarshalJSON() ([]byte, error) {
	return json.Marshal(NormalizeTimeForMarshal(time.Time(t)).Format(MarshalFormat))
}

// UnmarshalJSON sets the DateTime from JSON
func (t *DateTime) UnmarshalJSON(data []byte) error {
	if string(data) == jsonNull {
		return nil
	}

	var tstr string
	if err := json.Unmarshal(data, &tstr); err != nil {
		return err
	}
	tt, err := ParseDateTime(tstr)
	if err != nil {
		return err
	}
	*t = tt
	return nil
}

// MarshalBSON renders the DateTime as a BSON document
func (t DateTime) MarshalBSON() ([]byte, error) {
	return bson.Marshal(bson.M{"data": t})
}

// UnmarshalBSON reads the DateTime from a BSON document
func (t *DateTime) UnmarshalBSON(data []byte) error {
	var obj struct {
		Data DateTime
	}

	if err := bson.Unmarshal(data, &obj); err != nil {
		return err
	}

	*t = obj.Data

	return nil
}

// MarshalBSONValue is an interface implemented by types that can marshal themselves
// into a BSON document represented as bytes. The bytes returned must be a valid
// BSON document if the error is nil.
// Marshals a DateTime as a bsontype.DateTime, an int64 representing
// milliseconds since epoch.
func (t DateTime) MarshalBSONValue() (bsontype.Type, []byte, error) {
	// UnixNano cannot be used directly, the result of calling UnixNano on the zero
	// Time is undefined. Thats why we use time.Nanosecond() instead.

	tNorm := NormalizeTimeForMarshal(time.Time(t))
	i64 := tNorm.Unix()*1000 + int64(tNorm.Nanosecond())/1e6

	buf := make([]byte, 8)
	binary.LittleEndian.PutUint64(buf, uint64(i64))

	return bsontype.DateTime, buf, nil
}

// UnmarshalBSONValue is an interface implemented by types that can unmarshal a
// BSON value representation of themselves. The BSON bytes and type can be
// assumed to be valid. UnmarshalBSONValue must copy the BSON value bytes if it
// wishes to retain the data after returning.
func (t *DateTime) UnmarshalBSONValue(tpe bsontype.Type, data []byte) error {
	if tpe == bsontype.Null {
		*t = DateTime{}
		return nil
	}

	if len(data) != 8 {
		return errors.New("bson date field length not exactly 8 bytes")
	}

	i64 := int64(binary.LittleEndian.Uint64(data))
	// TODO: Use bsonprim.DateTime.Time() method
	*t = DateTime(time.Unix(i64/1000, i64%1000*1000000))

	return nil
}

// DeepCopyInto copies the receiver and writes its value into out.
func (t *DateTime) DeepCopyInto(out *DateTime) {
	*out = *t
}

// DeepCopy copies the receiver into a new DateTime.
func (t *DateTime) DeepCopy() *DateTime {
	if t == nil {
		return nil
	}
	out := new(DateTime)
	t.DeepCopyInto(out)
	return out
}

// GobEncode implements the gob.GobEncoder interface.
func (t DateTime) GobEncode() ([]byte, error) {
	return t.MarshalBinary()
}

// GobDecode implements the gob.GobDecoder interface.
func (t *DateTime) GobDecode(data []byte) error {
	return t.UnmarshalBinary(data)
}

// MarshalBinary implements the encoding.BinaryMarshaler interface.
func (t DateTime) MarshalBinary() ([]byte, error) {
	return NormalizeTimeForMarshal(time.Time(t)).MarshalBinary()
}

// UnmarshalBinary implements the encoding.BinaryUnmarshaler interface.
func (t *DateTime) UnmarshalBinary(data []byte) error {
	var original time.Time

	err := original.UnmarshalBinary(data)
	if err != nil {
		return err
	}

	*t = DateTime(original)

	return nil
}

// Equal checks if two DateTime instances are equal using time.Time's Equal method
func (t DateTime) Equal(t2 DateTime) bool {
	return time.Time(t).Equal(time.Time(t2))
}
<|endoftext|>


<commit_before>/*
Dependencies:
  go get github.com/dcadenas/pagerank

BUG :
1	if there is no space before \n, throw index out of range error from createNodes function.
	Somehow a word doesn't register on the dict and it cause the error because if not found in dict it returns 0.

FIX :
1	Added some more parameters at createDictionary in the if decision in the strings.Map, possible cleaning could also
	be found there.

TODO :
1	Try Hamming distance instead of Jaccard Coeficient for calculating node weights - Done
2	Try using idf-modified-cosine
*/
package tldr

import (
	"sort"
	"strings"
	"github.com/dcadenas/pagerank"
)

type Bag struct {
	sentences [][]string
	originalSentences []string
	dict map[string]int
	nodes []*Node
	edges []*Edge
	ranks []int
}

func New() *Bag {
	return &Bag{}
}

// the default values of each settings
const (
	VERSION = "0.0.2"
	ALGORITHM = "centrality"
	WEIGHING = "jaccard"
	DAMPING = 0.85
	TOLERANCE = 0.0001
	THRESHOLD = 0.001
)

// Using pagerank algorithm will return many version of summary, unlike static summary result from centrality algorithm
var (
	Algorithm string = "centrality"
	Weighing string = "jaccard"
	Damping float64 = 0.85
	Tolerance float64 = 0.0001
	Threshold float64 = 0.001
)

func Set(d float64, t float64, th float64, alg string, w string) {
	Damping = d
	Tolerance = t
	Threshold = th
	Algorithm = alg
	Weighing = w
}

func (bag *Bag) Summarize(text string, num int) string {
	bag.createDictionary(text)
	bag.createSentences(text)
	bag.createNodes()
	bag.createEdges()
	if Algorithm == "centrality" {
		bag.centrality()
	} else if Algorithm == "pagerank" {
		bag.pageRank()
	} else {
		bag.centrality()
	}
	// get only num top of idx
	idx := bag.ranks[:num]
	// sort it ascending
	sort.Ints(idx)
	var res string
	for _, v := range idx {
		res += bag.originalSentences[v] + " "
	}
	return res
}

func (bag *Bag) centrality() {
	// first remove edges under Threshold weight
	var newEdges []*Edge
	for _, edge := range bag.edges {
		if edge.weight > Threshold {
			newEdges = append(newEdges, edge)
		}
	}
	// sort them by weight descending, using insertion sort
	for i, v := range newEdges {
		j := i - 1
		for j >= 0 && newEdges[j].weight < v.weight {
			newEdges[j+1] = newEdges[j]
			j -= 1
		}
		newEdges[j+1] = v
	}
	var rankBySrc []int
	for _, v := range newEdges {
		rankBySrc = append(rankBySrc, v.src)
	}
	// uniq it without disturbing the order
	// var uniq []int
	// uniq = append(uniq, rankBySrc[0])
	// for _, v := range rankBySrc {
	// 	same := false
	// 	for j := 0; j < len(uniq); j++ {
	// 		if uniq[j] == v {
	// 			same = true
	// 		}
	// 	}
	// 	if !same {
	// 		uniq = append(uniq, v)
	// 	}
	// }
	m := make(map[int]bool)
	var uniq []int
	for _, v := range rankBySrc {
		if m[v] {
			continue
		}
		uniq = append(uniq, v)
		m[v] = true
	}
	bag.ranks = uniq
}

func (bag *Bag) pageRank() {
	// first remove edges under Threshold weight
	var newEdges []*Edge
	for _, edge := range bag.edges {
		if edge.weight > Threshold {
			newEdges = append(newEdges, edge)
		}
	}
	// then page rank them
	graph := pagerank.New()
	defer graph.Clear()
	for _, edge := range newEdges {
		graph.Link(edge.src, edge.dst)
	}
	ranks := make(map[int]float64)
	graph.Rank(Damping, Tolerance, func (sentenceIndex int, rank float64) {
		ranks[sentenceIndex] = rank
	})
	// sort ranks into an array of sentence index, by rank descending
	var idx []int
	for i, v := range ranks {
		highest := i
		for j, x := range ranks {
			if i != j && x > v {
				highest = j
			}
		}
		idx = append(idx, highest)
		delete(ranks, highest)
		if len(ranks) == 2 {
			for l, z := range ranks {
				for m, r := range ranks {
					if r >= z {
						idx = append(idx, m)
						idx = append(idx, l)
						delete(ranks, m)
					}
				}
			}
		}
	}
	bag.ranks = idx
}

type Edge struct {
	src int // index of node
	dst int // index of node
	weight float64 // weight of the similarity between two sentences, use Jaccard Coefficient
}

func (bag *Bag) createEdges() {
	for i, src := range bag.nodes {
		for j, dst := range bag.nodes {
			// don't compare same node
			if i != j {
				var weight float64
				if Weighing == "jaccard" {
					commonElements := intersection(src.vector, dst.vector)
					weight = float64(len(commonElements)) / ((float64(vectorLength) * 2) - float64(len(commonElements)))
				} else if Weighing == "hamming" {
					differentElements := symetricDifference(src.vector, dst.vector)
					weight = float64(len(differentElements))
				} else {
					commonElements := intersection(src.vector, dst.vector)
					weight = float64(len(commonElements)) / ((float64(vectorLength) * 2) - float64(len(commonElements)))
				}
				edge := &Edge{i, j, weight}
				bag.edges = append(bag.edges, edge)
			}
		}
	}
}

func symetricDifference(src []int, dst []int) []int {
	var diff []int
	for i, v := range src {
		if v != dst[i] {
			diff = append(diff, i)
		}
	}
	return diff
}

func intersection(src []int, dst []int) []int {
	intersect := make(map[int]bool)
	for i, v := range src {
		if v > 0 && dst[i] > 0 {
			intersect[i] = true
		}
	}
	var result []int
	for k, _ := range intersect {
		result = append(result, k)
	}
	return result
}

type Node struct {
	sentenceIndex int // index of sentence from the bag
	vector []int // map of word count in respect with dict, should we use map instead of slice?
	// for example :
	/*
	dict = {
		i : 1
		am : 2
		the : 3
		shit : 4
	}
	str = "I am not shit, you effin shit"
	vector = [1, 1, 0, 2]
	*/
}

var vectorLength int

func (bag *Bag) createNodes() {
	vectorLength = len(bag.dict)
	for i, sentence := range bag.sentences {
		// vector length is len(dict)
		vector := make([]int, vectorLength)
		// word for word now
		for _, word := range sentence {
			// check word dict position
			// minus 1, because array started from 0 and lowest dict is 1
			pos := bag.dict[word] - 1
			// increment the position
			vector[pos]++
		}
		// vector is now created, put it into the node
		node := &Node{i, vector}
		// node is now completed, put into the bag
		bag.nodes = append(bag.nodes, node)
	}
}

func (bag *Bag) createSentences(text string) {
	// trim all spaces
	text = strings.TrimSpace(text)
	words := strings.Fields(text)
	var sentence []string
	var sentences [][]string
	for _, word := range words {
		// if there isn't . ? or !, append to sentence. If found, also append but reset the sentence
		if strings.ContainsRune(word, '.') || strings.ContainsRune(word, '!') || strings.ContainsRune(word, '?') {
			sentence = append(sentence, word)
			sentences = append(sentences, sentence)
			sentence = []string{}
		} else {
			sentence = append(sentence, word)
		}
	}
	if len(sentence) > 0 {
		sentences = append(sentences, sentence)
	}
	// remove doubled sentence
	sentences = uniqSentences(sentences)
	// now flatten them
	var bagOfSentence []string
	for _, s := range sentences {
		str := strings.Join(s, " ")
		bagOfSentence = append(bagOfSentence, str)
	}
	bag.originalSentences = bagOfSentence
	// sanitize sentences before putting it into the bag
	bag.sentences = sanitizeSentences(sentences)
}

func uniqSentences(sentences [][]string) [][]string {
	var z []string
	// create a sentence as one string and append it to z
	for _, v := range sentences {
		j := strings.Join(v ," ")
		z = append(z, j)
	}
	// var uniq []string
	// uniq = append(uniq, z[0])
	// for _, v := range z {
	// 	same := false
	// 	for j := 0; j < len(uniq); j++ {
	// 		if uniq[j] == v {
	// 			same = true
	// 		}
	// 	}
	// 	if !same {
	// 		uniq = append(uniq, v)
	// 	}
	// }
	m := make(map[string]bool)
	var uniq []string
	for _, v := range z {
		if m[v] {
			continue
		}
		uniq = append(uniq, v)
		m[v] = true
	}
	var unique [][]string
	for _, v := range uniq {
		unique = append(unique, strings.Fields(v))
	}
	return unique
}

func sanitizeSentences(sentences [][]string) [][]string {
	var sanitizedSentence [][]string
	for _, sentence := range sentences {
		var newSentence []string
		for _, word := range sentence {
			word = strings.ToLower(word)
			word = strings.Map(func (r rune) rune {
				if (r < '0' || r > '9') && (r < 'a' || r > 'z') && r != ' ' {
					return -1
				}
				return r
			}, word)
			newSentence = append(newSentence, word)
		}
		sanitizedSentence = append(sanitizedSentence, newSentence)
	}
	return sanitizedSentence
}

func (bag *Bag) createDictionary(text string) {
	// trim all spaces
	text = strings.TrimSpace(text)
	// lowercase the text
	text = strings.ToLower(text)
	// remove all non alphanumerics
	text = strings.Map(func (r rune) rune {
		// probably would be cleaner if use !unicode.IsDigit, !unicode.IsLetter, and !unicode.IsSpace
		if (r < '0' || r > '9') && (r < 'a' || r > 'z') && r != ' ' && r != '\n' && r != '\t' && r != '\v' && r != '\f' && r!= '\r' {
			return -1
		}
		return r
	}, text)
	// turn it into bag of words
	words := strings.Fields(text)
	// turn it into dictionary
	dict := make(map[string]int)
	i := 1
	for _, word := range words {
		if dict[word] == 0 {
			dict[word] = i
			i++
		}
	}
	bag.dict = dict
}<commit_msg>Fix comments<commit_after>/*
Dependencies:
  go get github.com/dcadenas/pagerank

BUG :
1. if there is no space before \n, throw index out of range error from createNodes function. Somehow a word doesn't register on the dict and it cause the error because if not found in dict it returns 0.

FIX :
1. Added some more parameters at createDictionary in the if decision in the strings.Map.

TODO :
1. Try Hamming distance instead of Jaccard Coeficient for calculating node weights - Done
2. Try using idf-modified-cosine
*/
package tldr

import (
	"sort"
	"strings"
	"github.com/dcadenas/pagerank"
)

type Bag struct {
	sentences [][]string
	originalSentences []string
	dict map[string]int
	nodes []*Node
	edges []*Edge
	ranks []int
}

func New() *Bag {
	return &Bag{}
}

// the default values of each settings
const (
	VERSION = "0.0.2"
	ALGORITHM = "centrality"
	WEIGHING = "jaccard"
	DAMPING = 0.85
	TOLERANCE = 0.0001
	THRESHOLD = 0.001
)

// Using pagerank algorithm will return many version of summary, unlike static summary result from centrality algorithm
var (
	Algorithm string = "centrality"
	Weighing string = "jaccard"
	Damping float64 = 0.85
	Tolerance float64 = 0.0001
	Threshold float64 = 0.001
)

func Set(d float64, t float64, th float64, alg string, w string) {
	Damping = d
	Tolerance = t
	Threshold = th
	Algorithm = alg
	Weighing = w
}

func (bag *Bag) Summarize(text string, num int) string {
	bag.createDictionary(text)
	bag.createSentences(text)
	bag.createNodes()
	bag.createEdges()
	if Algorithm == "centrality" {
		bag.centrality()
	} else if Algorithm == "pagerank" {
		bag.pageRank()
	} else {
		bag.centrality()
	}
	// get only num top of idx
	idx := bag.ranks[:num]
	// sort it ascending
	sort.Ints(idx)
	var res string
	for _, v := range idx {
		res += bag.originalSentences[v] + " "
	}
	return res
}

func (bag *Bag) centrality() {
	// first remove edges under Threshold weight
	var newEdges []*Edge
	for _, edge := range bag.edges {
		if edge.weight > Threshold {
			newEdges = append(newEdges, edge)
		}
	}
	// sort them by weight descending, using insertion sort
	for i, v := range newEdges {
		j := i - 1
		for j >= 0 && newEdges[j].weight < v.weight {
			newEdges[j+1] = newEdges[j]
			j -= 1
		}
		newEdges[j+1] = v
	}
	var rankBySrc []int
	for _, v := range newEdges {
		rankBySrc = append(rankBySrc, v.src)
	}
	// uniq it without disturbing the order
	// var uniq []int
	// uniq = append(uniq, rankBySrc[0])
	// for _, v := range rankBySrc {
	// 	same := false
	// 	for j := 0; j < len(uniq); j++ {
	// 		if uniq[j] == v {
	// 			same = true
	// 		}
	// 	}
	// 	if !same {
	// 		uniq = append(uniq, v)
	// 	}
	// }
	m := make(map[int]bool)
	var uniq []int
	for _, v := range rankBySrc {
		if m[v] {
			continue
		}
		uniq = append(uniq, v)
		m[v] = true
	}
	bag.ranks = uniq
}

func (bag *Bag) pageRank() {
	// first remove edges under Threshold weight
	var newEdges []*Edge
	for _, edge := range bag.edges {
		if edge.weight > Threshold {
			newEdges = append(newEdges, edge)
		}
	}
	// then page rank them
	graph := pagerank.New()
	defer graph.Clear()
	for _, edge := range newEdges {
		graph.Link(edge.src, edge.dst)
	}
	ranks := make(map[int]float64)
	graph.Rank(Damping, Tolerance, func (sentenceIndex int, rank float64) {
		ranks[sentenceIndex] = rank
	})
	// sort ranks into an array of sentence index, by rank descending
	var idx []int
	for i, v := range ranks {
		highest := i
		for j, x := range ranks {
			if i != j && x > v {
				highest = j
			}
		}
		idx = append(idx, highest)
		delete(ranks, highest)
		if len(ranks) == 2 {
			for l, z := range ranks {
				for m, r := range ranks {
					if r >= z {
						idx = append(idx, m)
						idx = append(idx, l)
						delete(ranks, m)
					}
				}
			}
		}
	}
	bag.ranks = idx
}

type Edge struct {
	src int // index of node
	dst int // index of node
	weight float64 // weight of the similarity between two sentences, use Jaccard Coefficient
}

func (bag *Bag) createEdges() {
	for i, src := range bag.nodes {
		for j, dst := range bag.nodes {
			// don't compare same node
			if i != j {
				var weight float64
				if Weighing == "jaccard" {
					commonElements := intersection(src.vector, dst.vector)
					weight = float64(len(commonElements)) / ((float64(vectorLength) * 2) - float64(len(commonElements)))
				} else if Weighing == "hamming" {
					differentElements := symetricDifference(src.vector, dst.vector)
					weight = float64(len(differentElements))
				} else {
					commonElements := intersection(src.vector, dst.vector)
					weight = float64(len(commonElements)) / ((float64(vectorLength) * 2) - float64(len(commonElements)))
				}
				edge := &Edge{i, j, weight}
				bag.edges = append(bag.edges, edge)
			}
		}
	}
}

func symetricDifference(src []int, dst []int) []int {
	var diff []int
	for i, v := range src {
		if v != dst[i] {
			diff = append(diff, i)
		}
	}
	return diff
}

func intersection(src []int, dst []int) []int {
	intersect := make(map[int]bool)
	for i, v := range src {
		if v > 0 && dst[i] > 0 {
			intersect[i] = true
		}
	}
	var result []int
	for k, _ := range intersect {
		result = append(result, k)
	}
	return result
}

type Node struct {
	sentenceIndex int // index of sentence from the bag
	vector []int // map of word count in respect with dict, should we use map instead of slice?
	// for example :
	/*
	dict = {
		i : 1
		am : 2
		the : 3
		shit : 4
	}
	str = "I am not shit, you effin shit"
	vector = [1, 1, 0, 2]
	*/
}

var vectorLength int

func (bag *Bag) createNodes() {
	vectorLength = len(bag.dict)
	for i, sentence := range bag.sentences {
		// vector length is len(dict)
		vector := make([]int, vectorLength)
		// word for word now
		for _, word := range sentence {
			// check word dict position
			// minus 1, because array started from 0 and lowest dict is 1
			pos := bag.dict[word] - 1
			// increment the position
			vector[pos]++
		}
		// vector is now created, put it into the node
		node := &Node{i, vector}
		// node is now completed, put into the bag
		bag.nodes = append(bag.nodes, node)
	}
}

func (bag *Bag) createSentences(text string) {
	// trim all spaces
	text = strings.TrimSpace(text)
	words := strings.Fields(text)
	var sentence []string
	var sentences [][]string
	for _, word := range words {
		// if there isn't . ? or !, append to sentence. If found, also append but reset the sentence
		if strings.ContainsRune(word, '.') || strings.ContainsRune(word, '!') || strings.ContainsRune(word, '?') {
			sentence = append(sentence, word)
			sentences = append(sentences, sentence)
			sentence = []string{}
		} else {
			sentence = append(sentence, word)
		}
	}
	if len(sentence) > 0 {
		sentences = append(sentences, sentence)
	}
	// remove doubled sentence
	sentences = uniqSentences(sentences)
	// now flatten them
	var bagOfSentence []string
	for _, s := range sentences {
		str := strings.Join(s, " ")
		bagOfSentence = append(bagOfSentence, str)
	}
	bag.originalSentences = bagOfSentence
	// sanitize sentences before putting it into the bag
	bag.sentences = sanitizeSentences(sentences)
}

func uniqSentences(sentences [][]string) [][]string {
	var z []string
	// create a sentence as one string and append it to z
	for _, v := range sentences {
		j := strings.Join(v ," ")
		z = append(z, j)
	}
	// var uniq []string
	// uniq = append(uniq, z[0])
	// for _, v := range z {
	// 	same := false
	// 	for j := 0; j < len(uniq); j++ {
	// 		if uniq[j] == v {
	// 			same = true
	// 		}
	// 	}
	// 	if !same {
	// 		uniq = append(uniq, v)
	// 	}
	// }
	m := make(map[string]bool)
	var uniq []string
	for _, v := range z {
		if m[v] {
			continue
		}
		uniq = append(uniq, v)
		m[v] = true
	}
	var unique [][]string
	for _, v := range uniq {
		unique = append(unique, strings.Fields(v))
	}
	return unique
}

func sanitizeSentences(sentences [][]string) [][]string {
	var sanitizedSentence [][]string
	for _, sentence := range sentences {
		var newSentence []string
		for _, word := range sentence {
			word = strings.ToLower(word)
			word = strings.Map(func (r rune) rune {
				if (r < '0' || r > '9') && (r < 'a' || r > 'z') && r != ' ' {
					return -1
				}
				return r
			}, word)
			newSentence = append(newSentence, word)
		}
		sanitizedSentence = append(sanitizedSentence, newSentence)
	}
	return sanitizedSentence
}

func (bag *Bag) createDictionary(text string) {
	// trim all spaces
	text = strings.TrimSpace(text)
	// lowercase the text
	text = strings.ToLower(text)
	// remove all non alphanumerics
	text = strings.Map(func (r rune) rune {
		// probably would be cleaner if use !unicode.IsDigit, !unicode.IsLetter, and !unicode.IsSpace
		if (r < '0' || r > '9') && (r < 'a' || r > 'z') && r != ' ' && r != '\n' && r != '\t' && r != '\v' && r != '\f' && r!= '\r' {
			return -1
		}
		return r
	}, text)
	// turn it into bag of words
	words := strings.Fields(text)
	// turn it into dictionary
	dict := make(map[string]int)
	i := 1
	for _, word := range words {
		if dict[word] == 0 {
			dict[word] = i
			i++
		}
	}
	bag.dict = dict
}<|endoftext|>


<commit_before>package main

import (
	"time"
	. "github.com/BurntSushi/toml"
	"log"
	. "fmt"
)

func main() {

}

<commit_msg>Remove testing file.<commit_after><|endoftext|>


<commit_before>package main

import (
  "flag"
  "fmt"
  "io/ioutil"
  "os"
  "time"
  // "path/filepath"
)

var traqPath string = os.Getenv("TRAQ_DATA_DIR")
var month int
var year int
var day int
var project string = "timestamps"
var date string

func printFile(project string, date time.Time) {
  var traqFile = fmt.Sprintf("%s/%s/%d/%d-%02d-%02d", traqPath, project, date.Year(), date.Year(), date.Month(), date.Day())
  var content, error = ioutil.ReadFile(traqFile)
  if error == nil {
    fmt.Print(string(content))
    fmt.Println("%%")
  } else {
    // fmt.Println(traqFile, " is unknown")
  }
}

func printMonth(project string, year int, month int) {
  var startDate time.Time = time.Date(year, time.Month(month), 1, 0, 0, 0, 0, time.UTC)
  for {
    printFile(project, startDate)
    startDate = startDate.Add(time.Hour * 24)
    if int(startDate.Month()) != month {
      break
    }
  }
}

func writeToFile(project string, date time.Time, command string) {
  var traqFile = fmt.Sprintf("%s/%s/%d/%d-%02d-%02d", traqPath, project, date.Year(), date.Year(), date.Month(), date.Day())
  var file, error = os.OpenFile(traqFile, os.O_RDWR|os.O_APPEND|os.O_CREATE, 0660)
  if error == nil {
    var line = fmt.Sprintf("%s;%s;%s\n", date.Format("Mon Jan 2 15:04:05 -0700 2006"), command, "")
    file.WriteString(line)
    file.Close()
  }
}

func main() {
  flag.IntVar(&year, "y", 0, "print tracked times for a given year")
  flag.IntVar(&month, "m", 0, "print tracked times for a given month")

  flag.StringVar(&date, "d", "", "print tracked times for a given date")
  flag.StringVar(&project, "p", "", "print data for a given project")

  flag.Parse()

  var now = time.Now()
  var t, error = time.Parse("2006-01-02", date)
  if error == nil {
    year = t.Year()
    month = int(t.Month())
    day = t.Day()
  } else {
    if month == 0 && year == 0 {
      day = now.Day()
    } else {
      day = 1
    }
    if year == 0 {
      year = now.Year()
    }
    if month == 0 {
      month = int(now.Month())
    }
  }

  var command string = flag.Arg(0)
  if command != "" && command != "stop" {
    command = "#" + command
  }

  if command == "" {
    printMonth(project, year, month)
  } else {
    writeToFile(project, now, command)
  }
}
<commit_msg>only print single file if date was given<commit_after>package main

import (
  "flag"
  "fmt"
  "io/ioutil"
  "os"
  "time"
  // "path/filepath"
)

var traqPath string = os.Getenv("TRAQ_DATA_DIR")
var month int
var year int
var day int
var project string = "timestamps"
var date string

func printFile(project string, date time.Time) {
  var traqFile = fmt.Sprintf("%s/%s/%d/%d-%02d-%02d", traqPath, project, date.Year(), date.Year(), date.Month(), date.Day())
  var content, error = ioutil.ReadFile(traqFile)
  if error == nil {
    fmt.Print(string(content))
    fmt.Println("%%")
  } else {
    // fmt.Println(traqFile, " is unknown")
  }
}

func printMonth(project string, year int, month int) {
  var startDate time.Time = time.Date(year, time.Month(month), 1, 0, 0, 0, 0, time.UTC)
  for {
    printFile(project, startDate)
    startDate = startDate.Add(time.Hour * 24)
    if int(startDate.Month()) != month {
      break
    }
  }
}

func writeToFile(project string, date time.Time, command string) {
  var traqFile = fmt.Sprintf("%s/%s/%d/%d-%02d-%02d", traqPath, project, date.Year(), date.Year(), date.Month(), date.Day())
  var file, error = os.OpenFile(traqFile, os.O_RDWR|os.O_APPEND|os.O_CREATE, 0660)
  if error == nil {
    var line = fmt.Sprintf("%s;%s;%s\n", date.Format("Mon Jan 2 15:04:05 -0700 2006"), command, "")
    file.WriteString(line)
    file.Close()
  }
}

func main() {
  flag.IntVar(&year, "y", 0, "print tracked times for a given year")
  flag.IntVar(&month, "m", 0, "print tracked times for a given month")

  flag.StringVar(&date, "d", "", "print tracked times for a given date")
  flag.StringVar(&project, "p", "", "print data for a given project")

  flag.Parse()

  var now = time.Now()
  var t, error = time.Parse("2006-01-02", date)
  if error == nil {
    year = t.Year()
    month = int(t.Month())
    day = t.Day()
  } else {
    if month == 0 && year == 0 {
      day = now.Day()
    } else {
      day = 1
    }
    if year == 0 {
      year = now.Year()
    }
    if month == 0 {
      month = int(now.Month())
    }
  }

  var command string = flag.Arg(0)
  if command != "" && command != "stop" {
    command = "#" + command
  }

  if command == "" {
    if date == "" {
      printMonth(project, year, month)
    } else {
      printFile(project, t)
    }
  } else {
    writeToFile(project, now, command)
  }
}
<|endoftext|>


<commit_before>package flash2

import (
	"net/http"
	"strings"
)

// type routes map[string]routes

// route contains part of route
type route struct {
	paramName string
	routes    routes
	f         handFunc
}

type match struct {
	handler http.Handler
	// params  map[string]string
}

type routes map[string]*route

// match returns route if found and route params
func (l routes) match(meth, s string) http.Handler {
	keys := strings.Split(s, "/")
	// fmt.Println("2:", meth, s, keys)
	params := make(map[string]string)

	root, ok := l[meth]
	if !ok {
		return nil
	}

	r := root
	for idx, key := range keys {
		if key != "" {
			r1, ok := r.routes[key]
			if !ok {
				r1, ok = r.routes["*"]
				if !ok {
					r1, ok = r.routes["**"]
					if ok {
						params[r1.paramName] = strings.Join(keys[idx:], "/")
						r = r1
						break
					}
				}
				if r1 != nil {
					params[r1.paramName] = key
				}
			}
			r = r1
			if r == nil {
				break
			}
		}
	}
	if r != nil && r.f != nil {
		return r.f(params)
	}

	return nil
}

// assign adds route structure to routes
func (l routes) assign(meth, path string, f handFunc) {
	parts := strings.Split(path, "/")

	if _, ok := l[meth]; !ok {
		l[meth] = &route{routes: routes{}}
	}

	r := l[meth]
	for _, key := range parts {
		if key != "" {
			name, param := keyParams(key)
			if _, ok := r.routes[name]; !ok {
				r.routes[name] = &route{paramName: param, routes: routes{}}
			}
			r = r.routes[name]
			if name == "**" {
				break
			}
		}
	}
	r.f = f
}

func keyParams(key string) (name, param string) {
	switch key[0] {
	case ':':
		param = key[1:]
		name = "*"
	case '@':
		param = key[1:]
		name = "**"
	default:
		name = key
	}
	return
}
<commit_msg>cleanup code<commit_after>package flash2

import (
	"net/http"
	"strings"
)

// type routes map[string]routes

// route contains part of route
type route struct {
	paramName string
	routes    routes
	f         handFunc
}

type match struct {
	handler http.Handler
	// params  map[string]string
}

type routes map[string]*route

// match returns route if found and route params
func (l routes) match(meth, s string) http.Handler {
	keys := strings.Split(s, "/")
	// fmt.Println("2:", meth, s, keys)
	params := make(map[string]string)

	root, ok := l[meth]
	if !ok {
		return nil
	}

	for idx, key := range keys {
		if key != "" {
			r, ok := root.routes[key]
			if !ok {
				r, ok = root.routes["*"]
				if !ok {
					r, ok = root.routes["**"]
					if ok {
						params[r.paramName] = strings.Join(keys[idx:], "/")
						root = r
						break
					}
				}
				if r != nil {
					params[r.paramName] = key
				}
			}
			root = r
			if root == nil {
				break
			}
		}
	}
	if root != nil && root.f != nil {
		return root.f(params)
	}

	return nil
}

// assign adds route structure to routes
func (l routes) assign(meth, path string, f handFunc) {
	parts := strings.Split(path, "/")

	if _, ok := l[meth]; !ok {
		l[meth] = &route{routes: routes{}}
	}

	r := l[meth]
	for _, key := range parts {
		if key != "" {
			name, param := keyParams(key)
			if _, ok := r.routes[name]; !ok {
				r.routes[name] = &route{paramName: param, routes: routes{}}
			}
			r = r.routes[name]
			if name == "**" {
				break
			}
		}
	}
	r.f = f
}

func keyParams(key string) (name, param string) {
	switch key[0] {
	case ':':
		param = key[1:]
		name = "*"
	case '@':
		param = key[1:]
		name = "**"
	default:
		name = key
	}
	return
}
<|endoftext|>


<commit_before>package asyncpi

// Type system.
// A mini type system to represent types and perform type inference.

import (
	"bytes"
	"fmt"
	"log"
)

// Type is a representation of types.
type Type interface {
	Underlying() Type
	String() string
}

// unTyped is an undefined type.
type unTyped struct{}

// NewUnTyped creates a new unTyped.
func NewUnTyped() Type {
	return &unTyped{}
}

// Underlying of unTyped is itself.
func (t *unTyped) Underlying() Type {
	return t
}

func (t *unTyped) String() string {
	return "interface{}"
}

// baseType is a concrete type.
type baseType struct {
	name string
}

// NewBaseType creates a new concrete type from string type name.
func NewBaseType(t string) Type {
	return &baseType{name: t}
}

// Underlying of baseType is itself.
func (t *baseType) Underlying() Type {
	return t
}

// String of baseType returns the type name.
func (t *baseType) String() string {
	return t.name
}

// refType is a reference to the type of a given name.
// Since names don't change but types do, we use the enclosing name as a handle.
type refType struct {
	n Name
}

// NewRefType creates a new reference type from a name.
func NewRefType(n Name) Type {
	return &refType{n: n}
}

// Underlying of a refType returns the referenced type.
func (t *refType) Underlying() Type {
	return t.n.Type()
}

// String of refType returns the type name of underlying type.
func (t *refType) String() string {
	return fmt.Sprintf("%s", t.n.Type().String())
}

// compType is a composite type.
type compType struct {
	types []Type
}

// NewCompType creates a new composite type from a list of types.
func NewCompType(t ...Type) Type {
	comp := &compType{types: []Type{}}
	comp.types = append(comp.types, t...)
	return comp
}

// Underlying of a compType returns itself.
func (t *compType) Underlying() Type {
	return t
}

// String of compType is a struct of composed types.
func (t *compType) String() string {
	var buf bytes.Buffer
	buf.WriteString("struct{")
	for i, t := range t.types {
		if i != 0 {
			buf.WriteRune(';')
		}
		buf.WriteString(fmt.Sprintf("e%d %s", i, t.String()))
	}
	buf.WriteString("}")
	return buf.String()
}

func (t *compType) Elems() []Type {
	return t.types
}

// chanType is reference type wrapped with a channel.
type chanType struct {
	T Type
}

// NewChanType creates a new channel type from an existing type.
func NewChanType(t Type) Type {
	return &chanType{T: t}
}

// Underlying of a chanType is itself.
func (t *chanType) Underlying() Type {
	return t
}

// String of refType is proxy to underlying type.
func (t *chanType) String() string {
	return fmt.Sprintf("chan %s", t.T.String())
}

// BUG(nickng) Inference may fail if type of a name is recursively defined (e.g.
// a<a> → typed chan of type(a)), printing the type will cause a stack
// overflow.

// Infer performs inline type inference for channels.
//
// Infer should be called after Bind, so the types of names inferred from
// channels can be propagated to other references bound to the same name.
func Infer(p Process) {
	switch proc := p.(type) {
	case *NilProcess:
	case *Par:
		for _, proc := range proc.Procs {
			Infer(proc)
		}
	case *Recv:
		Infer(proc.Cont)
		// But that's all we know right now.
		if _, ok := proc.Chan.Type().(*unTyped); ok {
			switch arity := len(proc.Vars); arity {
			case 1:
				if t, ok := proc.Vars[0].Type().(*refType); ok { // Already a ref
					proc.Chan.SetType(NewChanType(t))
				} else {
					proc.Chan.SetType(NewChanType(NewRefType(proc.Vars[0])))
				}
			default:
				ts := []Type{}
				for i := range proc.Vars {
					if t, ok := proc.Vars[i].Type().(*refType); ok {
						ts = append(ts, t)
					} else {
						ts = append(ts, NewRefType(proc.Vars[i]))
					}
				}
				proc.Chan.SetType(NewChanType(NewCompType(ts...)))
			}
		}
	case *Send: // Send is the only place we can infer channel type.
		switch arity := len(proc.Vals); arity {
		case 1:
			if t, ok := proc.Vals[0].Type().(*refType); ok { // Already a ref
				proc.Chan.SetType(NewChanType(t))
			} else {
				proc.Chan.SetType(NewChanType(NewRefType(proc.Vals[0])))
			}
		default:
			ts := []Type{}
			for i := range proc.Vals {
				if t, ok := proc.Vals[i].Type().(*refType); ok {
					ts = append(ts, t)
				} else {
					ts = append(ts, NewRefType(proc.Vals[i]))
				}
			}
			proc.Chan.SetType(NewChanType(NewCompType(ts...)))
		}
	case *Repeat:
		Infer(proc.Proc)
	case *Restrict:
		Infer(proc.Proc)
	default:
		log.Fatalln("Infer: Unknown process type", proc)
	}
}

// Unify takes sending channel and receiving channels and try to 'unify' the
// types with best effort.
//
// One of the assumption is send and receive names are already typed as channels.
// A well typed Process should have no conflict of types during unification.
func Unify(p Process) error {
	switch proc := p.(type) {
	case *NilProcess, *Send: // No continuation.
	case *Par:
		for _, proc := range proc.Procs {
			if err := Unify(proc); err != nil {
				return err
			}
		}
	case *Recv:
		// chType is either
		// - a compType with refType fields (including struct{})
		// - a refType (non-tuple)
		chType := proc.Chan.Type().(*chanType).T
		switch arity := len(proc.Vars); arity {
		case 1:
			if _, ok := chType.(*refType); !ok {
				return &ErrTypeArity{
					Got:      len(chType.(*compType).types),
					Expected: 1,
					Msg:      fmt.Sprintf("Types from channel %s and vars have different arity", proc.Chan.Name()),
				}
			}
			if _, ok := proc.Vars[0].Type().(*unTyped); ok {
				proc.Vars[0].SetType(chType) // Chan type --> Val type.
			} else if _, ok := chType.(*refType).n.Type().(*unTyped); ok {
				chType.(*refType).n.SetType(proc.Vars[0].Type()) // Val --> Chan type
			} else if chType.String() == proc.Vars[0].Type().String() {
				// No conflict.
				// TODO(nickng) deref type and check properly.
			} else {
				return &ErrType{
					T:   chType,
					U:   proc.Vars[0].Type(),
					Msg: fmt.Sprintf("Types inferred from channel %s are in conflict", proc.Chan.Name()),
				}
			}
		default:
			if _, ok := chType.(*compType); !ok {
				return &ErrTypeArity{
					Got:      1,
					Expected: len(proc.Vars),
					Msg:      fmt.Sprintf("Types from channel %s and vars have different arity", proc.Chan.Name()),
				}
			}
			for i := range proc.Vars {
				if _, ok := proc.Vars[i].Type().(*unTyped); ok {
					proc.Vars[i].SetType(chType.(*compType).types[i].(*refType).n.Type())
				} else if _, ok := chType.(*compType).types[i].(*refType).n.Type().(*unTyped); ok {
					chType.(*compType).types[i].(*refType).n.SetType(proc.Vars[i].Type())
				} else {
					return &ErrType{
						T:   chType,
						U:   proc.Vars[0].Type(),
						Msg: fmt.Sprintf("Types inferred from channel %s are in conflict", proc.Chan.Name()),
					}
				}
			}
		}
		return Unify(proc.Cont)
	case *Repeat:
		return Unify(proc.Proc)
	case *Restrict:
		return Unify(proc.Proc)
	}
	return nil
}

// ProcTypes returns the Type of the Process p.
func ProcTypes(p Process) string {
	switch proc := p.(type) {
	case *NilProcess:
		return "0"
	case *Send:
		return fmt.Sprintf("%s!%#v", proc.Chan.Name(), proc.Chan.Type())
	case *Recv:
		return fmt.Sprintf("%s?%#v; %s", proc.Chan.Name(), proc.Chan.Type(), ProcTypes(proc.Cont))
	case *Par:
		var buf bytes.Buffer
		for i, ps := range proc.Procs {
			if i != 0 {
				buf.WriteRune('|')
			}
			buf.WriteString(ProcTypes(ps))
		}
		return buf.String()
	case *Repeat:
		return "*" + ProcTypes(proc.Proc)
	case *Restrict:
		return fmt.Sprintf("(ν%s:%s) %s", proc.Name.Name(), proc.Name.Type(), ProcTypes(proc.Proc))
	default:
		log.Fatalln("ProcTypes: Unknown process type", proc)
	}
	return ""
}
<commit_msg>Deep type equality check<commit_after>package asyncpi

// Type system.
// A mini type system to represent types and perform type inference.

import (
	"bytes"
	"fmt"
	"log"
)

// Type is a representation of types.
type Type interface {
	Underlying() Type
	String() string
}

// unTyped is an undefined type.
type unTyped struct{}

// NewUnTyped creates a new unTyped.
func NewUnTyped() Type {
	return &unTyped{}
}

// Underlying of unTyped is itself.
func (t *unTyped) Underlying() Type {
	return t
}

func (t *unTyped) String() string {
	return "interface{}"
}

// baseType is a concrete type.
type baseType struct {
	name string
}

// NewBaseType creates a new concrete type from string type name.
func NewBaseType(t string) Type {
	return &baseType{name: t}
}

// Underlying of baseType is itself.
func (t *baseType) Underlying() Type {
	return t
}

// String of baseType returns the type name.
func (t *baseType) String() string {
	return t.name
}

// refType is a reference to the type of a given name.
// Since names don't change but types do, we use the enclosing name as a handle.
type refType struct {
	n Name
}

// NewRefType creates a new reference type from a name.
func NewRefType(n Name) Type {
	return &refType{n: n}
}

// Underlying of a refType returns the referenced type.
func (t *refType) Underlying() Type {
	return t.n.Type()
}

// String of refType returns the type name of underlying type.
func (t *refType) String() string {
	return fmt.Sprintf("%s", t.n.Type().String())
}

// compType is a composite type.
type compType struct {
	types []Type
}

// NewCompType creates a new composite type from a list of types.
func NewCompType(t ...Type) Type {
	comp := &compType{types: []Type{}}
	comp.types = append(comp.types, t...)
	return comp
}

// Underlying of a compType returns itself.
func (t *compType) Underlying() Type {
	return t
}

// String of compType is a struct of composed types.
func (t *compType) String() string {
	var buf bytes.Buffer
	buf.WriteString("struct{")
	for i, t := range t.types {
		if i != 0 {
			buf.WriteRune(';')
		}
		buf.WriteString(fmt.Sprintf("e%d %s", i, t.String()))
	}
	buf.WriteString("}")
	return buf.String()
}

func (t *compType) Elems() []Type {
	return t.types
}

// chanType is reference type wrapped with a channel.
type chanType struct {
	T Type
}

// NewChanType creates a new channel type from an existing type.
func NewChanType(t Type) Type {
	return &chanType{T: t}
}

// Underlying of a chanType is itself.
func (t *chanType) Underlying() Type {
	return t
}

// String of refType is proxy to underlying type.
func (t *chanType) String() string {
	return fmt.Sprintf("chan %s", t.T.String())
}

// BUG(nickng) Inference may fail if type of a name is recursively defined (e.g.
// a<a> → typed chan of type(a)), printing the type will cause a stack
// overflow.

// Infer performs inline type inference for channels.
//
// Infer should be called after Bind, so the types of names inferred from
// channels can be propagated to other references bound to the same name.
func Infer(p Process) {
	switch proc := p.(type) {
	case *NilProcess:
	case *Par:
		for _, proc := range proc.Procs {
			Infer(proc)
		}
	case *Recv:
		Infer(proc.Cont)
		// But that's all we know right now.
		if _, ok := proc.Chan.Type().(*unTyped); ok {
			switch arity := len(proc.Vars); arity {
			case 1:
				if t, ok := proc.Vars[0].Type().(*refType); ok { // Already a ref
					proc.Chan.SetType(NewChanType(t))
				} else {
					proc.Chan.SetType(NewChanType(NewRefType(proc.Vars[0])))
				}
			default:
				ts := []Type{}
				for i := range proc.Vars {
					if t, ok := proc.Vars[i].Type().(*refType); ok {
						ts = append(ts, t)
					} else {
						ts = append(ts, NewRefType(proc.Vars[i]))
					}
				}
				proc.Chan.SetType(NewChanType(NewCompType(ts...)))
			}
		}
	case *Send: // Send is the only place we can infer channel type.
		switch arity := len(proc.Vals); arity {
		case 1:
			if t, ok := proc.Vals[0].Type().(*refType); ok { // Already a ref
				proc.Chan.SetType(NewChanType(t))
			} else {
				proc.Chan.SetType(NewChanType(NewRefType(proc.Vals[0])))
			}
		default:
			ts := []Type{}
			for i := range proc.Vals {
				if t, ok := proc.Vals[i].Type().(*refType); ok {
					ts = append(ts, t)
				} else {
					ts = append(ts, NewRefType(proc.Vals[i]))
				}
			}
			proc.Chan.SetType(NewChanType(NewCompType(ts...)))
		}
	case *Repeat:
		Infer(proc.Proc)
	case *Restrict:
		Infer(proc.Proc)
	default:
		log.Fatalln("Infer: Unknown process type", proc)
	}
}

// Unify takes sending channel and receiving channels and try to 'unify' the
// types with best effort.
//
// One of the assumption is send and receive names are already typed as channels.
// A well typed Process should have no conflict of types during unification.
func Unify(p Process) error {
	switch proc := p.(type) {
	case *NilProcess, *Send: // No continuation.
	case *Par:
		for _, proc := range proc.Procs {
			if err := Unify(proc); err != nil {
				return err
			}
		}
	case *Recv:
		// chType is either
		// - a compType with refType fields (including struct{})
		// - a refType (non-tuple)
		chType := proc.Chan.Type().(*chanType).T
		switch arity := len(proc.Vars); arity {
		case 1:
			if _, ok := chType.(*refType); !ok {
				return &ErrTypeArity{
					Got:      len(chType.(*compType).types),
					Expected: 1,
					Msg:      fmt.Sprintf("Types from channel %s and vars have different arity", proc.Chan.Name()),
				}
			}
			if _, ok := proc.Vars[0].Type().(*unTyped); ok {
				proc.Vars[0].SetType(chType) // Chan type --> Val type.
			} else if _, ok := chType.(*refType).n.Type().(*unTyped); ok {
				chType.(*refType).n.SetType(proc.Vars[0].Type()) // Val --> Chan type
			} else if equalType(chType, proc.Vars[0].Type()) {
				// Type is both set but equal.
			} else {
				return &ErrType{
					T:   chType,
					U:   proc.Vars[0].Type(),
					Msg: fmt.Sprintf("Types inferred from channel %s are in conflict", proc.Chan.Name()),
				}
			}
		default:
			if _, ok := chType.(*compType); !ok {
				return &ErrTypeArity{
					Got:      1,
					Expected: len(proc.Vars),
					Msg:      fmt.Sprintf("Types from channel %s and vars have different arity", proc.Chan.Name()),
				}
			}
			for i := range proc.Vars {
				if _, ok := proc.Vars[i].Type().(*unTyped); ok {
					proc.Vars[i].SetType(chType.(*compType).types[i].(*refType).n.Type())
				} else if _, ok := chType.(*compType).types[i].(*refType).n.Type().(*unTyped); ok {
					chType.(*compType).types[i].(*refType).n.SetType(proc.Vars[i].Type())
				} else if equalType(chType.(*compType).types[i], proc.Vars[i].Type()) {
					// Type is both set but equal.
				} else {
					return &ErrType{
						T:   chType,
						U:   proc.Vars[0].Type(),
						Msg: fmt.Sprintf("Types inferred from channel %s are in conflict", proc.Chan.Name()),
					}
				}
			}
		}
		return Unify(proc.Cont)
	case *Repeat:
		return Unify(proc.Proc)
	case *Restrict:
		return Unify(proc.Proc)
	}
	return nil
}

// ProcTypes returns the Type of the Process p.
func ProcTypes(p Process) string {
	switch proc := p.(type) {
	case *NilProcess:
		return "0"
	case *Send:
		return fmt.Sprintf("%s!%#v", proc.Chan.Name(), proc.Chan.Type())
	case *Recv:
		return fmt.Sprintf("%s?%#v; %s", proc.Chan.Name(), proc.Chan.Type(), ProcTypes(proc.Cont))
	case *Par:
		var buf bytes.Buffer
		for i, ps := range proc.Procs {
			if i != 0 {
				buf.WriteRune('|')
			}
			buf.WriteString(ProcTypes(ps))
		}
		return buf.String()
	case *Repeat:
		return "*" + ProcTypes(proc.Proc)
	case *Restrict:
		return fmt.Sprintf("(ν%s:%s) %s", proc.Name.Name(), proc.Name.Type(), ProcTypes(proc.Proc))
	default:
		log.Fatalln("ProcTypes: Unknown process type", proc)
	}
	return ""
}

// deref peels off layers of refType from a given type and returns the underlying
// type.
func deref(t Type) Type {
	if rt, ok := t.(*refType); ok {
		return deref(rt.n.Type())
	}
	return t
}

// equalType compare types.
func equalType(t, u Type) bool {
	if baseT, tok := deref(t).(*baseType); tok {
		if baseU, uok := deref(u).(*baseType); uok {
			return baseT.name == baseU.name
		}
	}
	if compT, tok := deref(t).(*compType); tok {
		if compU, uok := deref(u).(*compType); uok {
			if len(compT.types) == 0 && len(compU.types) == 0 {
				return true
			}
			compEqual := len(compT.types) == len(compU.types)
			for i := range compT.types {
				compEqual = compEqual && equalType(compT.types[i], compU.types[i])
			}
			return compEqual
		}
	}
	if chanT, tok := deref(t).(*chanType); tok {
		if chanU, uok := deref(u).(*chanType); uok {
			return equalType(chanT.T, chanU.T)
		}
	}
	return false
}
<|endoftext|>