<commit_before>package grab

import (
	"bufio"
	"encoding/hex"
	"fmt"
	"net/http"
	"net/http/httptest"
	"os"
	"testing"
)

// ts is the test HTTP server instance initiated by TestMain().
var ts *httptest.Server

// TestMail starts a HTTP test server for all test cases to use as a download
// source.
func TestMain(m *testing.M) {
	// start test HTTP server
	ts = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		// compute transfer size from 'size' parameter (default 1Mb)
		size := 1048576
		if sizep := r.URL.Query().Get("size"); sizep != "" {
			if _, err := fmt.Sscanf(sizep, "%d", &size); err != nil {
				panic(err)
			}
		}

		// support ranged requests?
		ranged := true
		if rangep := r.URL.Query().Get("ranged"); rangep != "" {
			if _, err := fmt.Sscanf(rangep, "%t", &ranged); err != nil {
				panic(err)
			}
		}

		// set filename in headers?
		if filenamep := r.URL.Query().Get("filename"); filenamep != "" {
			w.Header().Set("Content-Disposition", fmt.Sprintf("attachment;filename=\"%s\"", filenamep))
		}

		// set response headers
		w.Header().Set("Content-Length", fmt.Sprintf("%d", size))
		w.Header().Set("Accept-Ranges", "bytes")

		if r.Method == "GET" {
			// compute offset
			offset := 0
			if rangeh := r.Header.Get("Range"); rangeh != "" {
				if _, err := fmt.Sscanf(rangeh, "bytes=%d-", &offset); err != nil {
					panic(err)
				}
			}

			// write to stream
			bw := bufio.NewWriterSize(w, 4096)
			for i := offset; i < size; i++ {
				bw.Write([]byte{byte(i)})
			}
			bw.Flush()
		}
	}))

	defer ts.Close()

	// run tests
	os.Exit(m.Run())
}

// testFilename executes a request and asserts that the downloaded filename
// matches the given filename.
func testFilename(t *testing.T, req *Request, filename string) {
	// fetch
	resp, err := DefaultClient.Do(req)
	if err != nil {
		t.Errorf("Error in Client.Do(): %v", err)
	}

	// delete downloaded file
	if err := os.Remove(resp.Filename); err != nil {
		t.Errorf("Error deleting test file: %v", err)
	}

	// compare filename
	if resp.Filename != filename {
		t.Errorf("Filename mismatch. Expected '%s', got '%s'.", filename, resp.Filename)
	}
}

// TestWithFilename asserts that the downloaded filename matches a filename
// specified explicitely via Request.Filename, and not a name matching the
// request URL or Content-Disposition header.
func TestWithFilename(t *testing.T) {
	req, _ := NewRequest(ts.URL + "/url-filename?filename=header-filename")
	req.Filename = ".testWithFilename"

	testFilename(t, req, req.Filename)
}

// TestWithHeaderFilename asserts that the downloaded filename matches a
// filename specified explicitely via the Content-Disposition header and not a
// name matching the request URL.
func TestWithHeaderFilename(t *testing.T) {
	req, _ := NewRequest(ts.URL + "/url-filename?filename=.testWithHeaderFilename")
	testFilename(t, req, ".testWithHeaderFilename")
}

// TestWithURLFilename asserts that the downloaded filename matches the
// requested URL.
func TestWithURLFilename(t *testing.T) {
	req, _ := NewRequest(ts.URL + "/.testWithURLFilename?params-filename")
	testFilename(t, req, ".testWithURLFilename")
}

// testChecksum executes a request and asserts that the computed checksum for
// the downloaded file does or does not match the expected checksum.
func testChecksum(t *testing.T, size int, sum string, match bool) {
	// create request
	req, _ := NewRequest(ts.URL + fmt.Sprintf("?size=%d", size))
	req.Filename = fmt.Sprintf(".testChecksum-%s", sum)

	// set expected checksum
	sumb, _ := hex.DecodeString(sum)
	req.SetChecksum("sha256", sumb)

	// fetch
	resp, err := DefaultClient.Do(req)
	if err != nil {
		if !IsChecksumMismatch(err) {
			t.Errorf("Error in Client.Do(): %v", err)
		} else if match {
			t.Errorf("%v (%v bytes)", err, size)
		}
	} else if !match {
		t.Errorf("Expected checksum mismatch but comparison succeeded (%v bytes)", size)
	}

	// delete downloaded file
	if err := os.Remove(resp.Filename); err != nil {
		t.Errorf("Error deleting test file: %v", err)
	}
}

// TestChecksums executes a number of checksum tests via testChecksum.
func TestChecksums(t *testing.T) {
	testChecksum(t, 128, "471fb943aa23c511f6f72f8d1652d9c880cfa392ad80503120547703e56a2be5", true)
	testChecksum(t, 1024, "785b0751fc2c53dc14a4ce3d800e69ef9ce1009eb327ccf458afe09c242c26c9", true)
	testChecksum(t, 1048576, "fbbab289f7f94b25736c58be46a994c441fd02552cc6022352e3d86d2fab7c83", true)

	testChecksum(t, 128, "00112233", false)
	testChecksum(t, 1024, "00112233", false)
	testChecksum(t, 1048576, "00112233", false)
}
<commit_msg>Added tests for auto resuming<commit_after>package grab

import (
	"bufio"
	"encoding/hex"
	"fmt"
	"net/http"
	"net/http/httptest"
	"os"
	"testing"
)

// ts is the test HTTP server instance initiated by TestMain().
var ts *httptest.Server

// TestMail starts a HTTP test server for all test cases to use as a download
// source.
func TestMain(m *testing.M) {
	// start test HTTP server
	ts = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		// compute transfer size from 'size' parameter (default 1Mb)
		size := 1048576
		if sizep := r.URL.Query().Get("size"); sizep != "" {
			if _, err := fmt.Sscanf(sizep, "%d", &size); err != nil {
				panic(err)
			}
		}

		// support ranged requests (default yes)?
		ranged := true
		if rangep := r.URL.Query().Get("ranged"); rangep != "" {
			if _, err := fmt.Sscanf(rangep, "%t", &ranged); err != nil {
				panic(err)
			}
		}

		// set filename in headers (default no)?
		if filenamep := r.URL.Query().Get("filename"); filenamep != "" {
			w.Header().Set("Content-Disposition", fmt.Sprintf("attachment;filename=\"%s\"", filenamep))
		}

		// compute offset
		offset := 0
		if rangeh := r.Header.Get("Range"); rangeh != "" {
			if _, err := fmt.Sscanf(rangeh, "bytes=%d-", &offset); err != nil {
				panic(err)
			}
		}

		// set response headers
		w.Header().Set("Content-Length", fmt.Sprintf("%d", size-offset))
		w.Header().Set("Accept-Ranges", "bytes")

		// serve content body if method == "GET"
		if r.Method == "GET" {
			// write to stream
			bw := bufio.NewWriterSize(w, 4096)
			for i := offset; i < size; i++ {
				bw.Write([]byte{byte(i)})
			}
			bw.Flush()
		}
	}))

	defer ts.Close()

	// run tests
	os.Exit(m.Run())
}

// testFilename executes a request and asserts that the downloaded filename
// matches the given filename.
func testFilename(t *testing.T, req *Request, filename string) {
	// fetch
	resp, err := DefaultClient.Do(req)
	if err != nil {
		t.Errorf("Error in Client.Do(): %v", err)
	}

	// delete downloaded file
	if err := os.Remove(resp.Filename); err != nil {
		t.Errorf("Error deleting test file: %v", err)
	}

	// compare filename
	if resp.Filename != filename {
		t.Errorf("Filename mismatch. Expected '%s', got '%s'.", filename, resp.Filename)
	}
}

// TestWithFilename asserts that the downloaded filename matches a filename
// specified explicitely via Request.Filename, and not a name matching the
// request URL or Content-Disposition header.
func TestWithFilename(t *testing.T) {
	req, _ := NewRequest(ts.URL + "/url-filename?filename=header-filename")
	req.Filename = ".testWithFilename"

	testFilename(t, req, ".testWithFilename")
}

// TestWithHeaderFilename asserts that the downloaded filename matches a
// filename specified explicitely via the Content-Disposition header and not a
// name matching the request URL.
func TestWithHeaderFilename(t *testing.T) {
	req, _ := NewRequest(ts.URL + "/url-filename?filename=.testWithHeaderFilename")
	testFilename(t, req, ".testWithHeaderFilename")
}

// TestWithURLFilename asserts that the downloaded filename matches the
// requested URL.
func TestWithURLFilename(t *testing.T) {
	req, _ := NewRequest(ts.URL + "/.testWithURLFilename?params-filename")
	testFilename(t, req, ".testWithURLFilename")
}

// testChecksum executes a request and asserts that the computed checksum for
// the downloaded file does or does not match the expected checksum.
func testChecksum(t *testing.T, size int, sum string, match bool) {
	// create request
	req, _ := NewRequest(ts.URL + fmt.Sprintf("?size=%d", size))
	req.Filename = fmt.Sprintf(".testChecksum-%s", sum)

	// set expected checksum
	sumb, _ := hex.DecodeString(sum)
	req.SetChecksum("sha256", sumb)

	// fetch
	resp, err := DefaultClient.Do(req)
	if err != nil {
		if !IsChecksumMismatch(err) {
			t.Errorf("Error in Client.Do(): %v", err)
		} else if match {
			t.Errorf("%v (%v bytes)", err, size)
		}
	} else if !match {
		t.Errorf("Expected checksum mismatch but comparison succeeded (%v bytes)", size)
	}

	// delete downloaded file
	if err := os.Remove(resp.Filename); err != nil {
		t.Errorf("Error deleting test file: %v", err)
	}
}

// TestChecksums executes a number of checksum tests via testChecksum.
func TestChecksums(t *testing.T) {
	testChecksum(t, 128, "471fb943aa23c511f6f72f8d1652d9c880cfa392ad80503120547703e56a2be5", true)
	testChecksum(t, 128, "471fb943aa23c511f6f72f8d1652d9c880cfa392ad80503120547703e56a2be4", false)

	testChecksum(t, 1024, "785b0751fc2c53dc14a4ce3d800e69ef9ce1009eb327ccf458afe09c242c26c9", true)
	testChecksum(t, 1024, "785b0751fc2c53dc14a4ce3d800e69ef9ce1009eb327ccf458afe09c242c26c8", false)

	testChecksum(t, 1048576, "fbbab289f7f94b25736c58be46a994c441fd02552cc6022352e3d86d2fab7c83", true)
	testChecksum(t, 1048576, "fbbab289f7f94b25736c58be46a994c441fd02552cc6022352e3d86d2fab7c82", false)
}

func TestAutoResume(t *testing.T) {
	segs := 32
	size := 1048576
	filename := ".testAutoResume"

	// TODO: random segment size

	// download segment at a time
	for i := 1; i < segs; i++ {
		// request larger segment
		segsize := i * (size / segs)
		req, _ := NewRequest(ts.URL + fmt.Sprintf("?size=%d", segsize))
		req.Filename = filename

		// transfer
		if _, err := DefaultClient.Do(req); err != nil {
			t.Errorf("Error segment %d (%d bytes): %v", i, segsize, err)
			break
		}
	}

	// TODO: redownload and check time stamp

	// TODO: validate checksum

	// TODO: existing file is larger than expected

	// TODO: existing file is corrupted

	// delete downloaded file
	if err := os.Remove(filename); err != nil {
		t.Errorf("Error deleting test file: %v", err)
	}
}
<|endoftext|>


<commit_before>package vkapi

import (
	"log"
)

func ExampleNewClientFromToken() {
	client, _ := NewClientFromToken("<access_token>")
	if err := client.InitLongPoll(0, 2); err != nil {
		log.Panic(err)
	}
	client.Log(true)
	updates, _, err := client.GetLPUpdatesChan(100, LPConfig{25, LPModeAttachments})
	if err != nil {
		log.Panic(err)
	}

	for update := range updates {
		if update.Message == nil {
			continue
		}

		log.Printf("%s", update.Message.String())
		if update.IsNewMessage() && update.Message.Text == "/start" {
			client.SendMessage(NewMessage(NewDstFromUserID(update.Message.FromID), "Hello!"))
		}

	}
}

func ExampleNewClientFromApplication() {
	client, err := NewClientFromApplication(Application{
		Username:     "<username>",
		Password:     "<password>",
		GrantType:    "password",
		ClientID:     "<client_id>",
		ClientSecret: "<client_secret>",
	})
	if err != nil {
		log.Panic(err)
	}

	if err := client.InitMyProfile(); err != nil {
		log.Panic(err.Error())
	}

	log.Printf("My name is %s", client.VKUser.Me.FirstName)
}
<commit_msg>Added exapmle for NewClientFromAPIClient<commit_after>package vkapi

import (
	"log"
	"net/http"
	"TelegramBot/vkapi"
)

func ExampleNewClientFromToken() {
	client, _ := NewClientFromToken("<access_token>")
	if err := client.InitLongPoll(0, 2); err != nil {
		log.Panic(err)
	}
	client.Log(true)
	updates, _, err := client.GetLPUpdatesChan(100, LPConfig{25, LPModeAttachments})
	if err != nil {
		log.Panic(err)
	}

	for update := range updates {
		if update.Message == nil {
			continue
		}

		log.Printf("%s", update.Message.String())
		if update.IsNewMessage() && update.Message.Text == "/start" {
			client.SendMessage(NewMessage(NewDstFromUserID(update.Message.FromID), "Hello!"))
		}

	}
}

func ExampleNewClientFromAPIClient() {
	apiClient := NewApiClient()
	apiClient.SetHTTPClient(http.DefaultClient)
	apiClient.SetAccessToken("<access token>")
	client, _ := NewClientFromAPIClient(apiClient)
	if err := client.InitMyProfile(); err != nil {
		log.Panic(err.Error())
	}

	log.Printf("My name is %s", client.VKUser.Me.FirstName)
}

func ExampleNewClientFromApplication() {
	client, err := NewClientFromApplication(Application{
		Username:     "<username>",
		Password:     "<password>",
		GrantType:    "password",
		ClientID:     "<client_id>",
		ClientSecret: "<client_secret>",
	})
	if err != nil {
		log.Panic(err)
	}

	if err := client.InitMyProfile(); err != nil {
		log.Panic(err.Error())
	}

	log.Printf("My name is %s", client.VKUser.Me.FirstName)
}
<|endoftext|>


<commit_before>package gentleman

import (
	gocontext "context"
	"errors"
	"fmt"
	"net/http"
	"net/http/httptest"
	"testing"

	"github.com/nbio/st"
	"github.com/stretchr/testify/assert"

	"gopkg.in/h2non/gentleman.v2/context"
)

func TestClientMiddlewareContext(t *testing.T) {
	fn := func(ctx *context.Context, h context.Handler) {
		ctx.Set("foo", ctx.GetString("foo")+"bar")
		h.Next(ctx)
	}

	cli := New()
	cli.UseRequest(fn)
	cli.UseResponse(fn)
	if len(cli.Middleware.GetStack()) != 2 {
		t.Error("Invalid middleware stack length")
	}

	ctx := NewContext()
	cli.Middleware.Run("request", ctx)
	cli.Middleware.Run("response", ctx)
	st.Expect(t, ctx.GetString("foo"), "barbar")
}

func TestClientInheritance(t *testing.T) {
	parent := New()
	cli := New()
	cli.UseParent(parent)

	parent.UseRequest(func(ctx *context.Context, h context.Handler) {
		ctx.Request.Header.Set("Client", "go")
		h.Next(ctx)
	})
	cli.UseRequest(func(ctx *context.Context, h context.Handler) {
		ctx.Request.Header.Set("Client", ctx.Request.Header.Get("Client")+"go")
		h.Next(ctx)
	})

	ctx := NewContext()
	cli.Middleware.Run("request", ctx)
	st.Expect(t, ctx.Request.Header.Get("Client"), "gogo")
}

func TestClientRequestMiddleware(t *testing.T) {
	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Server", r.Header.Get("Client"))
		w.Header().Set("Agent", r.Header.Get("Agent"))
		_, _ = fmt.Fprintln(w, "Hello, world")
	}))
	defer ts.Close()

	client := New()
	client.UseRequest(func(ctx *context.Context, h context.Handler) {
		ctx.Request.Header.Set("Client", "go")
		h.Next(ctx)
	})

	req := client.Request()
	req.URL(ts.URL)
	req.UseRequest(func(ctx *context.Context, h context.Handler) {
		ctx.Request.Header.Set("Agent", "gentleman")
		h.Next(ctx)
	})

	res, err := req.Do()
	st.Expect(t, err, nil)
	st.Expect(t, res.StatusCode, 200)
	st.Expect(t, res.Header.Get("Server"), "go")
	st.Expect(t, res.Header.Get("Agent"), "gentleman")
}

func TestClientRequestResponseMiddleware(t *testing.T) {
	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		_, _ = fmt.Fprintln(w, "Hello, world")
	}))
	defer ts.Close()

	client := New()
	client.UseRequest(func(c *context.Context, h context.Handler) {
		c.Request.Header.Set("Client", "go")
		h.Next(c)
	})
	client.UseResponse(func(c *context.Context, h context.Handler) {
		c.Response.Header.Set("Server", c.Request.Header.Get("Client"))
		h.Next(c)
	})

	req := client.Request()
	req.URL(ts.URL)
	res, err := req.Do()
	st.Expect(t, err, nil)
	st.Expect(t, res.StatusCode, 200)
	st.Expect(t, res.Header.Get("Server"), "go")
}

func TestClientErrorMiddleware(t *testing.T) {
	client := New()
	client.UseRequest(func(c *context.Context, h context.Handler) {
		c.Error = errors.New("foo error")
		h.Next(c)
	})
	client.UseError(func(c *context.Context, h context.Handler) {
		c.Error = errors.New("error: " + c.Error.Error())
		h.Next(c)
	})

	req := client.Request()
	res, err := req.Do()
	st.Expect(t, err.Error(), "error: foo error")
	st.Expect(t, res.Ok, false)
	st.Expect(t, res.StatusCode, 0)
}

func TestClientCustomPhaseMiddleware(t *testing.T) {
	client := New()
	client.UseRequest(func(c *context.Context, h context.Handler) {
		c.Error = errors.New("foo error")
		h.Next(c)
	})
	client.UseHandler("error", func(c *context.Context, h context.Handler) {
		c.Error = errors.New("error: " + c.Error.Error())
		h.Next(c)
	})

	req := client.Request()
	res, err := req.Do()
	st.Expect(t, err.Error(), "error: foo error")
	st.Expect(t, res.Ok, false)
	st.Expect(t, res.StatusCode, 0)
}

func TestClientMethod(t *testing.T) {
	cli := New()
	cli.Method("POST")
	cli.Middleware.Run("request", cli.Context)
	st.Expect(t, cli.Context.Request.Method, "POST")
}

func TestClientURL(t *testing.T) {
	url := "http://foo.com"
	cli := New()
	cli.URL(url)
	cli.Middleware.Run("request", cli.Context)
	st.Expect(t, cli.Context.Request.URL.String(), url)
}

func TestClientBaseURL(t *testing.T) {
	url := "http://foo.com/bar/baz"
	cli := New()
	cli.BaseURL(url)
	cli.Middleware.Run("request", cli.Context)
	st.Expect(t, cli.Context.Request.URL.String(), "http://foo.com/bar/baz")
}

func TestClientPath(t *testing.T) {
	url := "http://foo.com/bar/baz"
	path := "/foo/baz"
	cli := New()
	cli.URL(url)
	cli.Path(path)
	cli.Middleware.Run("request", cli.Context)
	st.Expect(t, cli.Context.Request.URL.String(), "http://foo.com/foo/baz")
}

func TestClientAddPath(t *testing.T) {
	url := "http://foo.com/bar"
	path := "/foo/baz"
	cli := New()
	cli.URL(url)
	cli.AddPath(path)
	cli.Middleware.Run("request", cli.Context)
	st.Expect(t, cli.Context.Request.URL.String(), "http://foo.com/bar/foo/baz")
}

func TestClientPathParam(t *testing.T) {
	url := "http://foo.com/bar/baz"
	path := "/:foo/bar/:baz"
	cli := New()
	cli.URL(url)
	cli.Path(path)
	cli.Param("foo", "baz")
	cli.Param("baz", "foo")
	cli.Middleware.Run("request", cli.Context)
	st.Expect(t, cli.Context.Request.URL.String(), "http://foo.com/baz/bar/foo")
}

func TestClientPathParams(t *testing.T) {
	url := "http://foo.com/bar/baz"
	path := "/:foo/bar/:baz"
	cli := New()
	cli.URL(url)
	cli.Path(path)
	cli.Params(map[string]string{"foo": "baz", "baz": "foo"})
	cli.Middleware.Run("request", cli.Context)
	st.Expect(t, cli.Context.Request.URL.String(), "http://foo.com/baz/bar/foo")
}

func TestClientSetHeader(t *testing.T) {
	cli := New()
	cli.SetHeader("foo", "bar")
	cli.Middleware.Run("request", cli.Context)
	st.Expect(t, cli.Context.Request.Header.Get("foo"), "bar")
}

func TestClientAddHeader(t *testing.T) {
	cli := New()
	cli.AddHeader("foo", "baz")
	cli.AddHeader("foo", "bar")
	cli.Middleware.Run("request", cli.Context)
	st.Expect(t, cli.Context.Request.Header.Get("foo"), "baz")
}

func TestClientSetHeaders(t *testing.T) {
	cli := New()
	cli.SetHeaders(map[string]string{"foo": "baz", "baz": "foo"})
	cli.Middleware.Run("request", cli.Context)
	st.Expect(t, cli.Context.Request.Header.Get("foo"), "baz")
	st.Expect(t, cli.Context.Request.Header.Get("baz"), "foo")
}

func TestClientAddCookie(t *testing.T) {
	cli := New()
	cookie := &http.Cookie{Name: "foo", Value: "bar"}
	cli.AddCookie(cookie)
	cli.Middleware.Run("request", cli.Context)
	st.Expect(t, cli.Context.Request.Header.Get("Cookie"), "foo=bar")
}

func TestClientAddCookies(t *testing.T) {
	cli := New()
	cookies := []*http.Cookie{{Name: "foo", Value: "bar"}}
	cli.AddCookies(cookies)
	cli.Middleware.Run("request", cli.Context)
	st.Expect(t, cli.Context.Request.Header.Get("Cookie"), "foo=bar")
}

func TestClientCookieJar(t *testing.T) {
	cli := New()
	cli.CookieJar()
	cli.Middleware.Run("request", cli.Context)
	st.Reject(t, cli.Context.Client.Jar, nil)
}

func TestClientVerbMethods(t *testing.T) {
	cli := New()
	req := cli.Get()
	req.Middleware.Run("request", req.Context)
	if req.Context.Request.Method != "GET" {
		t.Errorf("Invalid request method: %s", req.Context.Request.Method)
	}

	cli = New()
	req = cli.Post()
	req.Middleware.Run("request", req.Context)
	if req.Context.Request.Method != "POST" {
		t.Errorf("Invalid request method: %s", req.Context.Request.Method)
	}

	cli = New()
	req = cli.Put()
	req.Middleware.Run("request", req.Context)
	if req.Context.Request.Method != "PUT" {
		t.Errorf("Invalid request method: %s", req.Context.Request.Method)
	}

	cli = New()
	req = cli.Delete()
	req.Middleware.Run("request", req.Context)
	if req.Context.Request.Method != "DELETE" {
		t.Errorf("Invalid request method: %s", req.Context.Request.Method)
	}

	cli = New()
	req = cli.Patch()
	req.Middleware.Run("request", req.Context)
	if req.Context.Request.Method != "PATCH" {
		t.Errorf("Invalid request method: %s", req.Context.Request.Method)
	}

	cli = New()
	req = cli.Head()
	req.Middleware.Run("request", req.Context)
	if req.Context.Request.Method != "HEAD" {
		t.Errorf("Invalid request method: %s", req.Context.Request.Method)
	}

	cli = New()
	req = cli.Options()
	req.Middleware.Run("request", req.Context)
	if req.Context.Request.Method != "OPTIONS" {
		t.Errorf("Invalid request method: %s", req.Context.Request.Method)
	}
}

func TestClientWithCanceledContext(t *testing.T) {

	ctx, cancel := gocontext.WithCancel(gocontext.Background())
	cancel()
	_, err := New().
		URL("http://localhost:8999").
		UseContext(ctx).
		Post().
		Path("/test").
		Send()
	assert.EqualError(t, err, "Post http://localhost:8999/test: context canceled")

}
<commit_msg>removeing assert<commit_after>package gentleman

import (
	gocontext "context"
	"errors"
	"fmt"
	"net/http"
	"net/http/httptest"
	"testing"

	"github.com/nbio/st"
	"gopkg.in/h2non/gentleman.v2/context"
)

func TestClientMiddlewareContext(t *testing.T) {
	fn := func(ctx *context.Context, h context.Handler) {
		ctx.Set("foo", ctx.GetString("foo")+"bar")
		h.Next(ctx)
	}

	cli := New()
	cli.UseRequest(fn)
	cli.UseResponse(fn)
	if len(cli.Middleware.GetStack()) != 2 {
		t.Error("Invalid middleware stack length")
	}

	ctx := NewContext()
	cli.Middleware.Run("request", ctx)
	cli.Middleware.Run("response", ctx)
	st.Expect(t, ctx.GetString("foo"), "barbar")
}

func TestClientInheritance(t *testing.T) {
	parent := New()
	cli := New()
	cli.UseParent(parent)

	parent.UseRequest(func(ctx *context.Context, h context.Handler) {
		ctx.Request.Header.Set("Client", "go")
		h.Next(ctx)
	})
	cli.UseRequest(func(ctx *context.Context, h context.Handler) {
		ctx.Request.Header.Set("Client", ctx.Request.Header.Get("Client")+"go")
		h.Next(ctx)
	})

	ctx := NewContext()
	cli.Middleware.Run("request", ctx)
	st.Expect(t, ctx.Request.Header.Get("Client"), "gogo")
}

func TestClientRequestMiddleware(t *testing.T) {
	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Server", r.Header.Get("Client"))
		w.Header().Set("Agent", r.Header.Get("Agent"))
		_, _ = fmt.Fprintln(w, "Hello, world")
	}))
	defer ts.Close()

	client := New()
	client.UseRequest(func(ctx *context.Context, h context.Handler) {
		ctx.Request.Header.Set("Client", "go")
		h.Next(ctx)
	})

	req := client.Request()
	req.URL(ts.URL)
	req.UseRequest(func(ctx *context.Context, h context.Handler) {
		ctx.Request.Header.Set("Agent", "gentleman")
		h.Next(ctx)
	})

	res, err := req.Do()
	st.Expect(t, err, nil)
	st.Expect(t, res.StatusCode, 200)
	st.Expect(t, res.Header.Get("Server"), "go")
	st.Expect(t, res.Header.Get("Agent"), "gentleman")
}

func TestClientRequestResponseMiddleware(t *testing.T) {
	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		_, _ = fmt.Fprintln(w, "Hello, world")
	}))
	defer ts.Close()

	client := New()
	client.UseRequest(func(c *context.Context, h context.Handler) {
		c.Request.Header.Set("Client", "go")
		h.Next(c)
	})
	client.UseResponse(func(c *context.Context, h context.Handler) {
		c.Response.Header.Set("Server", c.Request.Header.Get("Client"))
		h.Next(c)
	})

	req := client.Request()
	req.URL(ts.URL)
	res, err := req.Do()
	st.Expect(t, err, nil)
	st.Expect(t, res.StatusCode, 200)
	st.Expect(t, res.Header.Get("Server"), "go")
}

func TestClientErrorMiddleware(t *testing.T) {
	client := New()
	client.UseRequest(func(c *context.Context, h context.Handler) {
		c.Error = errors.New("foo error")
		h.Next(c)
	})
	client.UseError(func(c *context.Context, h context.Handler) {
		c.Error = errors.New("error: " + c.Error.Error())
		h.Next(c)
	})

	req := client.Request()
	res, err := req.Do()
	st.Expect(t, err.Error(), "error: foo error")
	st.Expect(t, res.Ok, false)
	st.Expect(t, res.StatusCode, 0)
}

func TestClientCustomPhaseMiddleware(t *testing.T) {
	client := New()
	client.UseRequest(func(c *context.Context, h context.Handler) {
		c.Error = errors.New("foo error")
		h.Next(c)
	})
	client.UseHandler("error", func(c *context.Context, h context.Handler) {
		c.Error = errors.New("error: " + c.Error.Error())
		h.Next(c)
	})

	req := client.Request()
	res, err := req.Do()
	st.Expect(t, err.Error(), "error: foo error")
	st.Expect(t, res.Ok, false)
	st.Expect(t, res.StatusCode, 0)
}

func TestClientMethod(t *testing.T) {
	cli := New()
	cli.Method("POST")
	cli.Middleware.Run("request", cli.Context)
	st.Expect(t, cli.Context.Request.Method, "POST")
}

func TestClientURL(t *testing.T) {
	url := "http://foo.com"
	cli := New()
	cli.URL(url)
	cli.Middleware.Run("request", cli.Context)
	st.Expect(t, cli.Context.Request.URL.String(), url)
}

func TestClientBaseURL(t *testing.T) {
	url := "http://foo.com/bar/baz"
	cli := New()
	cli.BaseURL(url)
	cli.Middleware.Run("request", cli.Context)
	st.Expect(t, cli.Context.Request.URL.String(), "http://foo.com/bar/baz")
}

func TestClientPath(t *testing.T) {
	url := "http://foo.com/bar/baz"
	path := "/foo/baz"
	cli := New()
	cli.URL(url)
	cli.Path(path)
	cli.Middleware.Run("request", cli.Context)
	st.Expect(t, cli.Context.Request.URL.String(), "http://foo.com/foo/baz")
}

func TestClientAddPath(t *testing.T) {
	url := "http://foo.com/bar"
	path := "/foo/baz"
	cli := New()
	cli.URL(url)
	cli.AddPath(path)
	cli.Middleware.Run("request", cli.Context)
	st.Expect(t, cli.Context.Request.URL.String(), "http://foo.com/bar/foo/baz")
}

func TestClientPathParam(t *testing.T) {
	url := "http://foo.com/bar/baz"
	path := "/:foo/bar/:baz"
	cli := New()
	cli.URL(url)
	cli.Path(path)
	cli.Param("foo", "baz")
	cli.Param("baz", "foo")
	cli.Middleware.Run("request", cli.Context)
	st.Expect(t, cli.Context.Request.URL.String(), "http://foo.com/baz/bar/foo")
}

func TestClientPathParams(t *testing.T) {
	url := "http://foo.com/bar/baz"
	path := "/:foo/bar/:baz"
	cli := New()
	cli.URL(url)
	cli.Path(path)
	cli.Params(map[string]string{"foo": "baz", "baz": "foo"})
	cli.Middleware.Run("request", cli.Context)
	st.Expect(t, cli.Context.Request.URL.String(), "http://foo.com/baz/bar/foo")
}

func TestClientSetHeader(t *testing.T) {
	cli := New()
	cli.SetHeader("foo", "bar")
	cli.Middleware.Run("request", cli.Context)
	st.Expect(t, cli.Context.Request.Header.Get("foo"), "bar")
}

func TestClientAddHeader(t *testing.T) {
	cli := New()
	cli.AddHeader("foo", "baz")
	cli.AddHeader("foo", "bar")
	cli.Middleware.Run("request", cli.Context)
	st.Expect(t, cli.Context.Request.Header.Get("foo"), "baz")
}

func TestClientSetHeaders(t *testing.T) {
	cli := New()
	cli.SetHeaders(map[string]string{"foo": "baz", "baz": "foo"})
	cli.Middleware.Run("request", cli.Context)
	st.Expect(t, cli.Context.Request.Header.Get("foo"), "baz")
	st.Expect(t, cli.Context.Request.Header.Get("baz"), "foo")
}

func TestClientAddCookie(t *testing.T) {
	cli := New()
	cookie := &http.Cookie{Name: "foo", Value: "bar"}
	cli.AddCookie(cookie)
	cli.Middleware.Run("request", cli.Context)
	st.Expect(t, cli.Context.Request.Header.Get("Cookie"), "foo=bar")
}

func TestClientAddCookies(t *testing.T) {
	cli := New()
	cookies := []*http.Cookie{{Name: "foo", Value: "bar"}}
	cli.AddCookies(cookies)
	cli.Middleware.Run("request", cli.Context)
	st.Expect(t, cli.Context.Request.Header.Get("Cookie"), "foo=bar")
}

func TestClientCookieJar(t *testing.T) {
	cli := New()
	cli.CookieJar()
	cli.Middleware.Run("request", cli.Context)
	st.Reject(t, cli.Context.Client.Jar, nil)
}

func TestClientVerbMethods(t *testing.T) {
	cli := New()
	req := cli.Get()
	req.Middleware.Run("request", req.Context)
	if req.Context.Request.Method != "GET" {
		t.Errorf("Invalid request method: %s", req.Context.Request.Method)
	}

	cli = New()
	req = cli.Post()
	req.Middleware.Run("request", req.Context)
	if req.Context.Request.Method != "POST" {
		t.Errorf("Invalid request method: %s", req.Context.Request.Method)
	}

	cli = New()
	req = cli.Put()
	req.Middleware.Run("request", req.Context)
	if req.Context.Request.Method != "PUT" {
		t.Errorf("Invalid request method: %s", req.Context.Request.Method)
	}

	cli = New()
	req = cli.Delete()
	req.Middleware.Run("request", req.Context)
	if req.Context.Request.Method != "DELETE" {
		t.Errorf("Invalid request method: %s", req.Context.Request.Method)
	}

	cli = New()
	req = cli.Patch()
	req.Middleware.Run("request", req.Context)
	if req.Context.Request.Method != "PATCH" {
		t.Errorf("Invalid request method: %s", req.Context.Request.Method)
	}

	cli = New()
	req = cli.Head()
	req.Middleware.Run("request", req.Context)
	if req.Context.Request.Method != "HEAD" {
		t.Errorf("Invalid request method: %s", req.Context.Request.Method)
	}

	cli = New()
	req = cli.Options()
	req.Middleware.Run("request", req.Context)
	if req.Context.Request.Method != "OPTIONS" {
		t.Errorf("Invalid request method: %s", req.Context.Request.Method)
	}
}

func TestClientWithCanceledContext(t *testing.T) {

	ctx, cancel := gocontext.WithCancel(gocontext.Background())
	cancel()
	_, err := New().
		URL("http://localhost:8999").
		UseContext(ctx).
		Post().
		Path("/test").
		Send()
	st.Expect(t, err.Error(), "Post http://localhost:8999/test: context canceled")
}
<|endoftext|>


<commit_before>package heap

import "sort"

//Interface 是排序的接口
type Interface interface {
	sort.Interface
	Divide(int, int) Interface
}

//Sort 使用堆排序
func Sort(a Interface) {
	reheapify(a)
	heapSort(a)
}

//reheapify 堆有序化
//reheapify后，根节点是序列中的最大值。
//a[i]的son节点是a[2*i+1]和a[2*i+2]
//a[i]的father节点是a[(i-1)/2]
//root节点是a[0]
func reheapify(a Interface) {
	n := a.Len()
	for i := n/2 - 1; i >= 0; i-- {
		//a[n/2-1]是序号最大的有son节点的元素
		//i:=n-1也可以堆有序化，但是，浪费了很多时间
		maxTop(a, i)
	}
}

//maxTop前，如果以i节点的两个子节点为root节点的两个子完全二叉树是堆有序的。
//maxTop后，以i节点为root节点的子完全二叉树，堆有序。而且，i节点是这个子完全二叉树中的最大值。
func maxTop(a Interface, i int) {
	n := a.Len()
	for 2*i+1 < n { //当i节点存在son节点的时候，继续循环
		iSon := 2*i + 1
		if iSon+1 < n && a.Less(iSon, iSon+1) {
			//iSon+1<n 保证了a[iSon+1]不越界
			//a.Less(iSon, iSon+1)是为了i与较大的Son互换。
			iSon++
		}
		if a.Less(iSon, i) {
			return
		}
		a.Swap(i, iSon)
		i = iSon
	}
}

func heapSort(a Interface) {
	n := a.Len()
	for n > 1 {
		n--
		a.Swap(0, n)       //把序列a中的最大值，放在序列尾部
		a = a.Divide(0, n) //把已经已经归为的a的最大值与其余部分隔离开
		maxTop(a, 0)       //让a重新堆有序化
	}
}
<commit_msg> 修改了名称，让堆排序过程更清晰。<commit_after>package heap

import "sort"

//Interface 是排序的接口
type Interface interface {
	sort.Interface
	Divide(int, int) Interface
}

//Sort 使用堆排序
func Sort(a Interface) {
	heapify(a)
	heapSort(a)
}

//heapify 堆有序化
//heapify后，根节点是序列中的最大值。
//a[i]的son节点是a[2*i+1]和a[2*i+2]
//a[i]的father节点是a[(i-1)/2]
//root节点是a[0]
func heapify(a Interface) {
	n := a.Len()
	for i := n/2 - 1; i >= 0; i-- {
		//a[n/2-1]是序号最大的有son节点的元素
		//i:=n-1也可以堆有序化，但是，浪费了很多时间
		reheapify(a, i)
	}
}

//reheapify前，如果以i节点的两个子节点为root节点的两个子完全二叉树是堆有序的。
//reheapify后，以i节点为root节点的子完全二叉树，堆有序。而且，i节点是这个子树中的最大值。
func reheapify(a Interface, i int) {
	n := a.Len()
	for 2*i+1 < n { //当i节点存在son节点的时候，继续循环
		iSon := 2*i + 1
		if iSon+1 < n && a.Less(iSon, iSon+1) {
			//iSon+1<n 保证了a[iSon+1]不越界
			//a.Less(iSon, iSon+1)是为了i与较大的Son互换。
			iSon++
		}
		if a.Less(iSon, i) {
			return
		}
		a.Swap(i, iSon)
		i = iSon
	}
}

func heapSort(a Interface) {
	n := a.Len()
	for n > 1 {
		n--
		a.Swap(0, n)       //把序列a中的最大值，放在序列尾部
		a = a.Divide(0, n) //把已经已经归为的a的最大值与其余部分隔离开
		reheapify(a, 0)    //让a重新堆有序化
	}
}
<|endoftext|>


<commit_before>// Copyright William Schwartz 2014. See the LICENSE file for more information.

// Package pigosat is a Go binding for the PicoSAT satisfiability solver.
package pigosat

// picosat/libpicosat.a must exist to build this file. See README.md.

// #cgo CFLAGS: -I picosat
// #cgo LDFLAGS: -l picosat -L picosat
// #include "picosat.h"
import "C"
import "time"
import "fmt"
import "sync"

var Version = SemanticVersion{0, 1, 0, "b", 0}

// PicosatVersion returns the version string from the underlying Picosat
// library.
func PicosatVersion() string {
	return C.GoString(C.picosat_version())
}

// Return values for Pigosat.Solve's status.
const (
	// NotReady is a solver status only used in PiGoSAT and it means the
	// underlying data structures of the solver have not been initialized or
	// their memory was previously freed.
	NotReady = -1
	// PicoSAT cannot determine the satisfiability of the formula.
	Unknown = 0
	// The formula is satisfiable.
	Satisfiable = 10
	// The formula cannot be satisfied.
	Unsatisfiable = 20
)

// Struct Pigosat must be created with NewPigosat and destroyed with DelPigosat.
type Pigosat struct {
	// Pointer to the underlying C struct.
	p *C.PicoSAT
	lock *sync.RWMutex
}

// NewPigosat returns a new Pigosat instance, ready to have literals added to
// it. Set propogation_limit to a positive value to limit how long the solver
// tries to find a solution.
func NewPigosat(propagation_limit uint64) *Pigosat {
	// PicoSAT * picosat_init (void);
	p := C.picosat_init()
	// void picosat_set_propagation_limit (PicoSAT *, unsigned long long limit);
	// Must be called after init, before solve, so we do it in the constructor.
	if propagation_limit > 0 {
		C.picosat_set_propagation_limit(p, C.ulonglong(propagation_limit))
	}
	return &Pigosat{p: p, lock: new(sync.RWMutex)}
}

// DelPigosat must be called on every Pigosat instance before each goes out of
// scope or the program ends, or else the program will leak memory. Once
// DelPigosat has been called on an instance, it cannot be used again.
func (p *Pigosat) Delete() {
	if p == nil || p.p == nil {
		return
	}
	p.lock.Lock()
	defer p.lock.Unlock()
	// void picosat_reset (PicoSAT *);
	C.picosat_reset(p.p)
	p.p = nil
}

// Variables returns the number of variables in the formula: The m in the DIMACS
// header "p cnf <m> n".
func (p *Pigosat) Variables() int {
	if p == nil || p.p == nil {
		return 0
	}
	p.lock.RLock()
	defer p.lock.RUnlock()
	// int picosat_variables (PicoSAT *);
	return int(C.picosat_variables(p.p))
}

// AddedOriginalClauses returns the number of clauses in the formula: The n in
// the DIMACS header "p cnf m <n>".
func (p *Pigosat) AddedOriginalClauses() int {
	if p == nil || p.p == nil {
		return 0
	}
	p.lock.RLock()
	defer p.lock.RUnlock()
	// int picosat_added_original_clauses (PicoSAT *);
	return int(C.picosat_added_original_clauses(p.p))
}

// Seconds returns the time spent in the PicoSAT library.
func (p *Pigosat) Seconds() time.Duration {
	if p == nil || p.p == nil {
		return 0
	}
	p.lock.RLock()
	defer p.lock.RUnlock()
	// double picosat_seconds (PicoSAT *);
	return time.Duration(float64(C.picosat_seconds(p.p)) * float64(time.Second))
}

// AddClauses adds a list (as a slice) of clauses (the sub-slices). Each clause
// is a list of integers called literals. The absolute value of the literal i is
// the subscript for some variable x_i. If the literal is positive, x_i must end
// up being true when the formula is solved. If the literal is negative, it must
// end up false. Each clause ORs the literals together. All the clauses are
// ANDed together. Literals cannot be zero: a zero in the middle of a slice ends
// the clause, and causes AddClauses to skip reading the rest of the slice. Nil
// slices are ignored and skipped.
func (p *Pigosat) AddClauses(clauses [][]int32) {
	if p == nil || p.p == nil {
		return
	}
	p.lock.Lock()
	defer p.lock.Unlock()
	var had0 bool
	for _, clause := range clauses {
		if len(clause) == 0 {
			continue
		}
		had0 = false
		for _, lit := range clause {
			// int picosat_add (PicoSAT *, int lit);
			C.picosat_add(p.p, C.int(lit))
			if lit == 0 {
				had0 = true
				break
			}
		}
		if !had0 {
			C.picosat_add(p.p, 0)
		}
	}
}

// Solve the formula and return the status of the solution: one of the constants
// Unsatisfiable, Satisfiable, or Unknown. If satisfiable, return a slice
// indexed by the variables in the formula (so the first element is always
// false).
func (p *Pigosat) Solve() (status int, solution []bool) {
	if p == nil || p.p == nil {
		return NotReady, nil
	}
	p.lock.Lock()
	defer p.lock.Unlock()
	// int picosat_sat (PicoSAT *, int decision_limit);
	status = int(C.picosat_sat(p.p, -1))
	if status == Unsatisfiable || status == Unknown {
		return
	} else if status != Satisfiable {
		panic(fmt.Errorf("Unknown sat status: %d", status))
	}
	n := int(C.picosat_variables(p.p)) // Calling Pigosat.Variables deadlocks
	solution = make([]bool, n+1)
	for i := 1; i <= n; i++ {
		// int picosat_deref (PicoSAT *, int lit);
		if val := C.picosat_deref(p.p, C.int(i)); val > 0 {
			solution[i] = true
		} else if val < 0 {
			solution[i] = false
		} else {
			panic(fmt.Errorf("Variable %d was assigned value 0", i))
		}
	}
	return
}
<commit_msg>Version bump to 0.1.0<commit_after>// Copyright William Schwartz 2014. See the LICENSE file for more information.

// Package pigosat is a Go binding for the PicoSAT satisfiability solver.
package pigosat

// picosat/libpicosat.a must exist to build this file. See README.md.

// #cgo CFLAGS: -I picosat
// #cgo LDFLAGS: -l picosat -L picosat
// #include "picosat.h"
import "C"
import "time"
import "fmt"
import "sync"

var Version = SemanticVersion{0, 1, 0, "", 0}

// PicosatVersion returns the version string from the underlying Picosat
// library.
func PicosatVersion() string {
	return C.GoString(C.picosat_version())
}

// Return values for Pigosat.Solve's status.
const (
	// NotReady is a solver status only used in PiGoSAT and it means the
	// underlying data structures of the solver have not been initialized or
	// their memory was previously freed.
	NotReady = -1
	// PicoSAT cannot determine the satisfiability of the formula.
	Unknown = 0
	// The formula is satisfiable.
	Satisfiable = 10
	// The formula cannot be satisfied.
	Unsatisfiable = 20
)

// Struct Pigosat must be created with NewPigosat and destroyed with DelPigosat.
type Pigosat struct {
	// Pointer to the underlying C struct.
	p *C.PicoSAT
	lock *sync.RWMutex
}

// NewPigosat returns a new Pigosat instance, ready to have literals added to
// it. Set propogation_limit to a positive value to limit how long the solver
// tries to find a solution.
func NewPigosat(propagation_limit uint64) *Pigosat {
	// PicoSAT * picosat_init (void);
	p := C.picosat_init()
	// void picosat_set_propagation_limit (PicoSAT *, unsigned long long limit);
	// Must be called after init, before solve, so we do it in the constructor.
	if propagation_limit > 0 {
		C.picosat_set_propagation_limit(p, C.ulonglong(propagation_limit))
	}
	return &Pigosat{p: p, lock: new(sync.RWMutex)}
}

// DelPigosat must be called on every Pigosat instance before each goes out of
// scope or the program ends, or else the program will leak memory. Once
// DelPigosat has been called on an instance, it cannot be used again.
func (p *Pigosat) Delete() {
	if p == nil || p.p == nil {
		return
	}
	p.lock.Lock()
	defer p.lock.Unlock()
	// void picosat_reset (PicoSAT *);
	C.picosat_reset(p.p)
	p.p = nil
}

// Variables returns the number of variables in the formula: The m in the DIMACS
// header "p cnf <m> n".
func (p *Pigosat) Variables() int {
	if p == nil || p.p == nil {
		return 0
	}
	p.lock.RLock()
	defer p.lock.RUnlock()
	// int picosat_variables (PicoSAT *);
	return int(C.picosat_variables(p.p))
}

// AddedOriginalClauses returns the number of clauses in the formula: The n in
// the DIMACS header "p cnf m <n>".
func (p *Pigosat) AddedOriginalClauses() int {
	if p == nil || p.p == nil {
		return 0
	}
	p.lock.RLock()
	defer p.lock.RUnlock()
	// int picosat_added_original_clauses (PicoSAT *);
	return int(C.picosat_added_original_clauses(p.p))
}

// Seconds returns the time spent in the PicoSAT library.
func (p *Pigosat) Seconds() time.Duration {
	if p == nil || p.p == nil {
		return 0
	}
	p.lock.RLock()
	defer p.lock.RUnlock()
	// double picosat_seconds (PicoSAT *);
	return time.Duration(float64(C.picosat_seconds(p.p)) * float64(time.Second))
}

// AddClauses adds a list (as a slice) of clauses (the sub-slices). Each clause
// is a list of integers called literals. The absolute value of the literal i is
// the subscript for some variable x_i. If the literal is positive, x_i must end
// up being true when the formula is solved. If the literal is negative, it must
// end up false. Each clause ORs the literals together. All the clauses are
// ANDed together. Literals cannot be zero: a zero in the middle of a slice ends
// the clause, and causes AddClauses to skip reading the rest of the slice. Nil
// slices are ignored and skipped.
func (p *Pigosat) AddClauses(clauses [][]int32) {
	if p == nil || p.p == nil {
		return
	}
	p.lock.Lock()
	defer p.lock.Unlock()
	var had0 bool
	for _, clause := range clauses {
		if len(clause) == 0 {
			continue
		}
		had0 = false
		for _, lit := range clause {
			// int picosat_add (PicoSAT *, int lit);
			C.picosat_add(p.p, C.int(lit))
			if lit == 0 {
				had0 = true
				break
			}
		}
		if !had0 {
			C.picosat_add(p.p, 0)
		}
	}
}

// Solve the formula and return the status of the solution: one of the constants
// Unsatisfiable, Satisfiable, or Unknown. If satisfiable, return a slice
// indexed by the variables in the formula (so the first element is always
// false).
func (p *Pigosat) Solve() (status int, solution []bool) {
	if p == nil || p.p == nil {
		return NotReady, nil
	}
	p.lock.Lock()
	defer p.lock.Unlock()
	// int picosat_sat (PicoSAT *, int decision_limit);
	status = int(C.picosat_sat(p.p, -1))
	if status == Unsatisfiable || status == Unknown {
		return
	} else if status != Satisfiable {
		panic(fmt.Errorf("Unknown sat status: %d", status))
	}
	n := int(C.picosat_variables(p.p)) // Calling Pigosat.Variables deadlocks
	solution = make([]bool, n+1)
	for i := 1; i <= n; i++ {
		// int picosat_deref (PicoSAT *, int lit);
		if val := C.picosat_deref(p.p, C.int(i)); val > 0 {
			solution[i] = true
		} else if val < 0 {
			solution[i] = false
		} else {
			panic(fmt.Errorf("Variable %d was assigned value 0", i))
		}
	}
	return
}
<|endoftext|>


<commit_before>// Copyright 2016 The Cockroach 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.
//
// Author: Nathan VanBenschoten (nvanbenschoten@gmail.com)

package encoding

import (
	"bytes"
	"math/big"
	"strconv"
	"unsafe"

	"gopkg.in/inf.v0"

	"github.com/cockroachdb/cockroach/util"
)

var (
	bigInt10   = big.NewInt(10)
	bigInt100  = big.NewInt(100)
	bigInt1000 = big.NewInt(1000)
)

// EncodeDecimalAscending returns the resulting byte slice with the
// encoded decimal appended to b.
//
// The encoding assumes that any number can be written as ±0.xyz... * 10^exp,
// where xyz is a digit string, x != 0, and the last decimal in xyz is also
// not 0.
//
// The encoding uses its first byte to split decimals into 7 distinct
// ordered groups (no NaN or Infinity support yet). The groups can
// be seen in encoding.go's const definition. Following this, the
// absolute value of the exponent of the decimal (as defined above)
// is encoded as an unsigned varint. Next, the absolute value of
// the digit string is added as a big-endian byte slice. Finally,
// a null terminator is appended to the end.
func EncodeDecimalAscending(b []byte, d *inf.Dec) []byte {
	return encodeDecimal(b, d, false)
}

// EncodeDecimalDescending is the descending version of EncodeDecimalAscending.
func EncodeDecimalDescending(b []byte, d *inf.Dec) []byte {
	return encodeDecimal(b, d, true)
}

func encodeDecimal(b []byte, d *inf.Dec, invert bool) []byte {
	neg := false
	bi := d.UnscaledBig()
	switch bi.Sign() {
	case -1:
		neg = !invert

		// Make a deep copy of the decimal's big.Int by calling Neg.
		// We shouldn't be modifying the provided argument's
		// internal big.Int, so this works like a copy-on-write scheme.
		bi = new(big.Int)
		bi = bi.Neg(d.UnscaledBig())
	case 0:
		return append(b, decimalZero)
	case 1:
		neg = invert
	}

	// Determine the exponent of the decimal, with the
	// exponent defined as .xyz * 10^exp.
	nDigits, formatted := numDigits(bi, b[len(b):])
	e := int(-d.Scale()) + nDigits

	// Handle big.Int having zeros at the end of its
	// string by dividing them off (ie. 12300 -> 123).
	tens := 0
	if formatted != nil {
		tens = trailingZerosFromBytes(formatted)
	} else {
		tens = trailingZeros(bi, b[len(b):])
	}
	if tens > 0 {
		// If the decimal's big.Int hasn't been copied already, copy
		// it now because we will be modifying it.
		from := bi
		if bi == d.UnscaledBig() {
			bi = new(big.Int)
			from = d.UnscaledBig()
		}

		var div *big.Int
		switch tens {
		case 1:
			div = bigInt10
		case 2:
			div = bigInt100
		case 3:
			div = bigInt1000
		default:
			div = big.NewInt(10)
			pow := big.NewInt(int64(tens))
			div = div.Exp(div, pow, nil)
		}
		bi = bi.Div(from, div)
	}
	bNat := bi.Bits()

	var buf []byte
	if n := wordLen(bNat) + maxVarintSize + 2; n <= cap(b)-len(b) {
		buf = b[len(b) : len(b)+n]
	} else {
		buf = make([]byte, n)
	}

	switch {
	case neg && e > 0:
		buf[0] = decimalNegValPosExp
		n := encodeDecimalValue(true, false, uint64(e), bNat, buf[1:])
		return append(b, buf[:n+2]...)
	case neg && e == 0:
		buf[0] = decimalNegValZeroExp
		n := encodeDecimalValueWithoutExp(true, bNat, buf[1:])
		return append(b, buf[:n+2]...)
	case neg && e < 0:
		buf[0] = decimalNegValNegExp
		n := encodeDecimalValue(true, true, uint64(-e), bNat, buf[1:])
		return append(b, buf[:n+2]...)
	case !neg && e < 0:
		buf[0] = decimalPosValNegExp
		n := encodeDecimalValue(false, true, uint64(-e), bNat, buf[1:])
		return append(b, buf[:n+2]...)
	case !neg && e == 0:
		buf[0] = decimalPosValZeroExp
		n := encodeDecimalValueWithoutExp(false, bNat, buf[1:])
		return append(b, buf[:n+2]...)
	case !neg && e > 0:
		buf[0] = decimalPosValPosExp
		n := encodeDecimalValue(false, false, uint64(e), bNat, buf[1:])
		return append(b, buf[:n+2]...)
	}
	panic("unreachable")
}

// encodeDecimalValue encodes the absolute value of a decimal's exponent
// and slice of digit bytes into buf, returning the number of bytes written.
// The function first encodes the the absolute value of a decimal's exponent
// as an unsigned varint. Next, the function copies the decimal's digits
// into the buffer. Finally, the function appends a decimal terminator to the
// end of the buffer. encodeDecimalValue reacts to positive/negative values and
// exponents by performing the proper ones complements to ensure proper logical
// sorting of values encoded in buf.
func encodeDecimalValue(negVal, negExp bool, exp uint64, digits []big.Word, buf []byte) int {
	n := putUvarint(buf, exp)

	trimmed := copyWords(buf[n:], digits)
	copy(buf[n:], trimmed)
	l := n + len(trimmed)

	switch {
	case negVal && negExp:
		onesComplement(buf[n:l])
	case negVal:
		onesComplement(buf[:l])
	case negExp:
		onesComplement(buf[:n])
	}

	buf[l] = decimalTerminator
	return l
}

func encodeDecimalValueWithoutExp(negVal bool, digits []big.Word, buf []byte) int {
	trimmed := copyWords(buf, digits)
	copy(buf, trimmed)
	l := len(trimmed)

	if negVal {
		onesComplement(buf[:l])
	}

	buf[l] = decimalTerminator
	return l
}

// DecodeDecimalAscending returns the remaining byte slice after decoding and the decoded
// decimal from buf.
func DecodeDecimalAscending(buf []byte, tmp []byte) ([]byte, *inf.Dec, error) {
	return decodeDecimal(buf, false, tmp)
}

// DecodeDecimalDescending decodes floats encoded with EncodeDecimalDescending.
func DecodeDecimalDescending(buf []byte, tmp []byte) ([]byte, *inf.Dec, error) {
	return decodeDecimal(buf, true, tmp)
}

func decodeDecimal(buf []byte, invert bool, tmp []byte) ([]byte, *inf.Dec, error) {
	switch {
	// TODO(nvanbenschoten) These cases are left unimplemented until we add support for
	// Infinity and NaN Decimal values.
	// case buf[0] == decimalNaN:
	// case buf[0] == decimalNegativeInfinity:
	// case buf[0] == decimalInfinity:
	// case buf[0] == decimalNaNDesc:
	case buf[0] == decimalZero:
		return buf[1:], inf.NewDec(0, 0), nil
	}

	idx := bytes.IndexByte(buf, decimalTerminator)
	if idx == -1 {
		return nil, nil, util.Errorf("did not find terminator %#x in buffer %#x", decimalTerminator, buf)
	}
	dec := inf.NewDec(0, 1)
	switch {
	case buf[0] == decimalNegValPosExp:
		decodeDecimalValue(dec, true, false, buf[1:idx], tmp)
		if !invert {
			dec.UnscaledBig().Neg(dec.UnscaledBig())
		}
		return buf[idx+1:], dec, nil
	case buf[0] == decimalNegValZeroExp:
		decodeDecimalValueWithoutExp(dec, true, buf[1:idx], tmp)
		if !invert {
			dec.UnscaledBig().Neg(dec.UnscaledBig())
		}
		return buf[idx+1:], dec, nil
	case buf[0] == decimalNegValNegExp:
		decodeDecimalValue(dec, true, true, buf[1:idx], tmp)
		if !invert {
			dec.UnscaledBig().Neg(dec.UnscaledBig())
		}
		return buf[idx+1:], dec, nil
	case buf[0] == decimalPosValNegExp:
		decodeDecimalValue(dec, false, true, buf[1:idx], tmp)
		if invert {
			dec.UnscaledBig().Neg(dec.UnscaledBig())
		}
		return buf[idx+1:], dec, nil
	case buf[0] == decimalPosValZeroExp:
		decodeDecimalValueWithoutExp(dec, false, buf[1:idx], tmp)
		if invert {
			dec.UnscaledBig().Neg(dec.UnscaledBig())
		}
		return buf[idx+1:], dec, nil
	case buf[0] == decimalPosValPosExp:
		decodeDecimalValue(dec, false, false, buf[1:idx], tmp)
		if invert {
			dec.UnscaledBig().Neg(dec.UnscaledBig())
		}
		return buf[idx+1:], dec, nil
	default:
		return nil, nil, util.Errorf("unknown prefix of the encoded byte slice: %q", buf)
	}
}

func decodeDecimalValue(dec *inf.Dec, negVal, negExp bool, buf, tmp []byte) {
	if negVal != negExp {
		onesComplement(buf)
	}
	e, l := getUvarint(buf)
	if negExp {
		e = -e
		onesComplement(buf[l:])
	}

	bi := dec.UnscaledBig()
	bi.SetBytes(buf[l:])
	nDigits, _ := numDigits(bi, tmp)
	exp := int(e) - nDigits
	dec.SetScale(inf.Scale(-exp))

	if negExp {
		onesComplement(buf[l:])
	}
	if negVal != negExp {
		onesComplement(buf)
	}
}

func decodeDecimalValueWithoutExp(dec *inf.Dec, negVal bool, buf, tmp []byte) {
	if negVal {
		onesComplement(buf)
	}
	dec.UnscaledBig().SetBytes(buf)
	if negVal {
		onesComplement(buf)
	}
}

// Taken from math/big/arith.go.
const bigWordSize = int(unsafe.Sizeof(big.Word(0)))

func wordLen(nat []big.Word) int {
	return len(nat) * bigWordSize
}

// copyWords was adapted from math/big/nat.go. It writes the value of
// nat into buf using big-endian encoding. len(buf) must be >= len(nat)*bigWordSize.
// The value of nat is encoded in the slice buf[i:], and the unused bytes
// at the beginning of buf are trimmed before returning.
func copyWords(buf []byte, nat []big.Word) []byte {
	i := len(buf)
	for _, d := range nat {
		for j := 0; j < bigWordSize; j++ {
			i--
			buf[i] = byte(d)
			d >>= 8
		}
	}

	for i < len(buf) && buf[i] == 0 {
		i++
	}

	return buf[i:]
}

// digitsLookupTable is used to map binary digit counts to their corresponding
// decimal border values. The map relies on the proof that (without leading zeros)
// for any given number of binary digits r, such that the number represented is
// between 2^r and 2^(r+1)-1, there are only two possible decimal digit counts
// k and k+1 that the binary r digits could be representing.
//
// Using this proof, for a given digit count, the map will return the lower number
// of decimal digits (k) the binary digit count could represenent, along with the
// value of the border between the two decimal digit counts (10^k).
const tableSize = 128

var digitsLookupTable [tableSize + 1]tableVal

type tableVal struct {
	digits int
	border *big.Int
}

func init() {
	digitBi := new(big.Int)
	var bigIntArr [tableSize]big.Int
	for i := 1; i <= tableSize; i++ {
		val := int(1 << uint(i-1))
		digits := 1
		for ; val > 10; val /= 10 {
			digits++
		}

		digitBi.SetInt64(int64(digits))
		digitsLookupTable[i] = tableVal{
			digits: digits,
			border: bigIntArr[i-1].Exp(bigInt10, digitBi, nil),
		}
	}
}

func lookupBits(bitLen int) (tableVal, bool) {
	if bitLen > 0 && bitLen < len(digitsLookupTable) {
		return digitsLookupTable[bitLen], true
	}
	return tableVal{}, false
}

// numDigits returns the number of decimal digits that make up
// big.Int value. The function first attempts to look this digit
// count up in the digitsLookupTable. If the value is not there,
// it defaults to constructing a string value for the big.Int and
// using this to determine the number of digits. If a string value
// is constructed, it will be returned so it can be used again.
func numDigits(bi *big.Int, tmp []byte) (int, []byte) {
	if val, ok := lookupBits(bi.BitLen()); ok {
		if bi.Cmp(val.border) < 0 {
			return val.digits, nil
		}
		return val.digits + 1, nil
	}
	bs := bi.Append(tmp, 10)
	return len(bs), bs
}

// trailingZeros counts the number of trailing zeros in the
// big.Int value. It first attempts to use an unsigned integer
// representation of the big.Int to compute this because it is
// roughly 8x faster. If this unsigned integer would overflow,
// it falls back to formatting the big.Int itself.
func trailingZeros(bi *big.Int, tmp []byte) int {
	if bi.BitLen() <= 64 {
		i := bi.Uint64()
		bs := strconv.AppendUint(tmp, i, 10)
		return trailingZerosFromBytes(bs)
	}
	bs := bi.Append(tmp, 10)
	return trailingZerosFromBytes(bs)
}

func trailingZerosFromBytes(bs []byte) int {
	tens := 0
	for bs[len(bs)-1-tens] == '0' {
		tens++
	}
	return tens
}
<commit_msg>encoding: Avoid initially setting decimal value to 0 when decoding<commit_after>// Copyright 2016 The Cockroach 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.
//
// Author: Nathan VanBenschoten (nvanbenschoten@gmail.com)

package encoding

import (
	"bytes"
	"math/big"
	"strconv"
	"unsafe"

	"gopkg.in/inf.v0"

	"github.com/cockroachdb/cockroach/util"
)

var (
	bigInt10   = big.NewInt(10)
	bigInt100  = big.NewInt(100)
	bigInt1000 = big.NewInt(1000)
)

// EncodeDecimalAscending returns the resulting byte slice with the
// encoded decimal appended to b.
//
// The encoding assumes that any number can be written as ±0.xyz... * 10^exp,
// where xyz is a digit string, x != 0, and the last decimal in xyz is also
// not 0.
//
// The encoding uses its first byte to split decimals into 7 distinct
// ordered groups (no NaN or Infinity support yet). The groups can
// be seen in encoding.go's const definition. Following this, the
// absolute value of the exponent of the decimal (as defined above)
// is encoded as an unsigned varint. Next, the absolute value of
// the digit string is added as a big-endian byte slice. Finally,
// a null terminator is appended to the end.
func EncodeDecimalAscending(b []byte, d *inf.Dec) []byte {
	return encodeDecimal(b, d, false)
}

// EncodeDecimalDescending is the descending version of EncodeDecimalAscending.
func EncodeDecimalDescending(b []byte, d *inf.Dec) []byte {
	return encodeDecimal(b, d, true)
}

func encodeDecimal(b []byte, d *inf.Dec, invert bool) []byte {
	neg := false
	bi := d.UnscaledBig()
	switch bi.Sign() {
	case -1:
		neg = !invert

		// Make a deep copy of the decimal's big.Int by calling Neg.
		// We shouldn't be modifying the provided argument's
		// internal big.Int, so this works like a copy-on-write scheme.
		bi = new(big.Int)
		bi = bi.Neg(d.UnscaledBig())
	case 0:
		return append(b, decimalZero)
	case 1:
		neg = invert
	}

	// Determine the exponent of the decimal, with the
	// exponent defined as .xyz * 10^exp.
	nDigits, formatted := numDigits(bi, b[len(b):])
	e := int(-d.Scale()) + nDigits

	// Handle big.Int having zeros at the end of its
	// string by dividing them off (ie. 12300 -> 123).
	tens := 0
	if formatted != nil {
		tens = trailingZerosFromBytes(formatted)
	} else {
		tens = trailingZeros(bi, b[len(b):])
	}
	if tens > 0 {
		// If the decimal's big.Int hasn't been copied already, copy
		// it now because we will be modifying it.
		from := bi
		if bi == d.UnscaledBig() {
			bi = new(big.Int)
			from = d.UnscaledBig()
		}

		var div *big.Int
		switch tens {
		case 1:
			div = bigInt10
		case 2:
			div = bigInt100
		case 3:
			div = bigInt1000
		default:
			div = big.NewInt(10)
			pow := big.NewInt(int64(tens))
			div = div.Exp(div, pow, nil)
		}
		bi = bi.Div(from, div)
	}
	bNat := bi.Bits()

	var buf []byte
	if n := wordLen(bNat) + maxVarintSize + 2; n <= cap(b)-len(b) {
		buf = b[len(b) : len(b)+n]
	} else {
		buf = make([]byte, n)
	}

	switch {
	case neg && e > 0:
		buf[0] = decimalNegValPosExp
		n := encodeDecimalValue(true, false, uint64(e), bNat, buf[1:])
		return append(b, buf[:n+2]...)
	case neg && e == 0:
		buf[0] = decimalNegValZeroExp
		n := encodeDecimalValueWithoutExp(true, bNat, buf[1:])
		return append(b, buf[:n+2]...)
	case neg && e < 0:
		buf[0] = decimalNegValNegExp
		n := encodeDecimalValue(true, true, uint64(-e), bNat, buf[1:])
		return append(b, buf[:n+2]...)
	case !neg && e < 0:
		buf[0] = decimalPosValNegExp
		n := encodeDecimalValue(false, true, uint64(-e), bNat, buf[1:])
		return append(b, buf[:n+2]...)
	case !neg && e == 0:
		buf[0] = decimalPosValZeroExp
		n := encodeDecimalValueWithoutExp(false, bNat, buf[1:])
		return append(b, buf[:n+2]...)
	case !neg && e > 0:
		buf[0] = decimalPosValPosExp
		n := encodeDecimalValue(false, false, uint64(e), bNat, buf[1:])
		return append(b, buf[:n+2]...)
	}
	panic("unreachable")
}

// encodeDecimalValue encodes the absolute value of a decimal's exponent
// and slice of digit bytes into buf, returning the number of bytes written.
// The function first encodes the the absolute value of a decimal's exponent
// as an unsigned varint. Next, the function copies the decimal's digits
// into the buffer. Finally, the function appends a decimal terminator to the
// end of the buffer. encodeDecimalValue reacts to positive/negative values and
// exponents by performing the proper ones complements to ensure proper logical
// sorting of values encoded in buf.
func encodeDecimalValue(negVal, negExp bool, exp uint64, digits []big.Word, buf []byte) int {
	n := putUvarint(buf, exp)

	trimmed := copyWords(buf[n:], digits)
	copy(buf[n:], trimmed)
	l := n + len(trimmed)

	switch {
	case negVal && negExp:
		onesComplement(buf[n:l])
	case negVal:
		onesComplement(buf[:l])
	case negExp:
		onesComplement(buf[:n])
	}

	buf[l] = decimalTerminator
	return l
}

func encodeDecimalValueWithoutExp(negVal bool, digits []big.Word, buf []byte) int {
	trimmed := copyWords(buf, digits)
	copy(buf, trimmed)
	l := len(trimmed)

	if negVal {
		onesComplement(buf[:l])
	}

	buf[l] = decimalTerminator
	return l
}

// DecodeDecimalAscending returns the remaining byte slice after decoding and the decoded
// decimal from buf.
func DecodeDecimalAscending(buf []byte, tmp []byte) ([]byte, *inf.Dec, error) {
	return decodeDecimal(buf, false, tmp)
}

// DecodeDecimalDescending decodes floats encoded with EncodeDecimalDescending.
func DecodeDecimalDescending(buf []byte, tmp []byte) ([]byte, *inf.Dec, error) {
	return decodeDecimal(buf, true, tmp)
}

func decodeDecimal(buf []byte, invert bool, tmp []byte) ([]byte, *inf.Dec, error) {
	switch {
	// TODO(nvanbenschoten) These cases are left unimplemented until we add support for
	// Infinity and NaN Decimal values.
	// case buf[0] == decimalNaN:
	// case buf[0] == decimalNegativeInfinity:
	// case buf[0] == decimalInfinity:
	// case buf[0] == decimalNaNDesc:
	case buf[0] == decimalZero:
		return buf[1:], inf.NewDec(0, 0), nil
	}

	idx := bytes.IndexByte(buf, decimalTerminator)
	if idx == -1 {
		return nil, nil, util.Errorf("did not find terminator %#x in buffer %#x", decimalTerminator, buf)
	}
	dec := new(inf.Dec).SetScale(1)
	switch {
	case buf[0] == decimalNegValPosExp:
		decodeDecimalValue(dec, true, false, buf[1:idx], tmp)
		if !invert {
			dec.UnscaledBig().Neg(dec.UnscaledBig())
		}
		return buf[idx+1:], dec, nil
	case buf[0] == decimalNegValZeroExp:
		decodeDecimalValueWithoutExp(dec, true, buf[1:idx], tmp)
		if !invert {
			dec.UnscaledBig().Neg(dec.UnscaledBig())
		}
		return buf[idx+1:], dec, nil
	case buf[0] == decimalNegValNegExp:
		decodeDecimalValue(dec, true, true, buf[1:idx], tmp)
		if !invert {
			dec.UnscaledBig().Neg(dec.UnscaledBig())
		}
		return buf[idx+1:], dec, nil
	case buf[0] == decimalPosValNegExp:
		decodeDecimalValue(dec, false, true, buf[1:idx], tmp)
		if invert {
			dec.UnscaledBig().Neg(dec.UnscaledBig())
		}
		return buf[idx+1:], dec, nil
	case buf[0] == decimalPosValZeroExp:
		decodeDecimalValueWithoutExp(dec, false, buf[1:idx], tmp)
		if invert {
			dec.UnscaledBig().Neg(dec.UnscaledBig())
		}
		return buf[idx+1:], dec, nil
	case buf[0] == decimalPosValPosExp:
		decodeDecimalValue(dec, false, false, buf[1:idx], tmp)
		if invert {
			dec.UnscaledBig().Neg(dec.UnscaledBig())
		}
		return buf[idx+1:], dec, nil
	default:
		return nil, nil, util.Errorf("unknown prefix of the encoded byte slice: %q", buf)
	}
}

func decodeDecimalValue(dec *inf.Dec, negVal, negExp bool, buf, tmp []byte) {
	if negVal != negExp {
		onesComplement(buf)
	}
	e, l := getUvarint(buf)
	if negExp {
		e = -e
		onesComplement(buf[l:])
	}

	bi := dec.UnscaledBig()
	bi.SetBytes(buf[l:])
	nDigits, _ := numDigits(bi, tmp)
	exp := int(e) - nDigits
	dec.SetScale(inf.Scale(-exp))

	if negExp {
		onesComplement(buf[l:])
	}
	if negVal != negExp {
		onesComplement(buf)
	}
}

func decodeDecimalValueWithoutExp(dec *inf.Dec, negVal bool, buf, tmp []byte) {
	if negVal {
		onesComplement(buf)
	}
	dec.UnscaledBig().SetBytes(buf)
	if negVal {
		onesComplement(buf)
	}
}

// Taken from math/big/arith.go.
const bigWordSize = int(unsafe.Sizeof(big.Word(0)))

func wordLen(nat []big.Word) int {
	return len(nat) * bigWordSize
}

// copyWords was adapted from math/big/nat.go. It writes the value of
// nat into buf using big-endian encoding. len(buf) must be >= len(nat)*bigWordSize.
// The value of nat is encoded in the slice buf[i:], and the unused bytes
// at the beginning of buf are trimmed before returning.
func copyWords(buf []byte, nat []big.Word) []byte {
	i := len(buf)
	for _, d := range nat {
		for j := 0; j < bigWordSize; j++ {
			i--
			buf[i] = byte(d)
			d >>= 8
		}
	}

	for i < len(buf) && buf[i] == 0 {
		i++
	}

	return buf[i:]
}

// digitsLookupTable is used to map binary digit counts to their corresponding
// decimal border values. The map relies on the proof that (without leading zeros)
// for any given number of binary digits r, such that the number represented is
// between 2^r and 2^(r+1)-1, there are only two possible decimal digit counts
// k and k+1 that the binary r digits could be representing.
//
// Using this proof, for a given digit count, the map will return the lower number
// of decimal digits (k) the binary digit count could represenent, along with the
// value of the border between the two decimal digit counts (10^k).
const tableSize = 128

var digitsLookupTable [tableSize + 1]tableVal

type tableVal struct {
	digits int
	border *big.Int
}

func init() {
	digitBi := new(big.Int)
	var bigIntArr [tableSize]big.Int
	for i := 1; i <= tableSize; i++ {
		val := int(1 << uint(i-1))
		digits := 1
		for ; val > 10; val /= 10 {
			digits++
		}

		digitBi.SetInt64(int64(digits))
		digitsLookupTable[i] = tableVal{
			digits: digits,
			border: bigIntArr[i-1].Exp(bigInt10, digitBi, nil),
		}
	}
}

func lookupBits(bitLen int) (tableVal, bool) {
	if bitLen > 0 && bitLen < len(digitsLookupTable) {
		return digitsLookupTable[bitLen], true
	}
	return tableVal{}, false
}

// numDigits returns the number of decimal digits that make up
// big.Int value. The function first attempts to look this digit
// count up in the digitsLookupTable. If the value is not there,
// it defaults to constructing a string value for the big.Int and
// using this to determine the number of digits. If a string value
// is constructed, it will be returned so it can be used again.
func numDigits(bi *big.Int, tmp []byte) (int, []byte) {
	if val, ok := lookupBits(bi.BitLen()); ok {
		if bi.Cmp(val.border) < 0 {
			return val.digits, nil
		}
		return val.digits + 1, nil
	}
	bs := bi.Append(tmp, 10)
	return len(bs), bs
}

// trailingZeros counts the number of trailing zeros in the
// big.Int value. It first attempts to use an unsigned integer
// representation of the big.Int to compute this because it is
// roughly 8x faster. If this unsigned integer would overflow,
// it falls back to formatting the big.Int itself.
func trailingZeros(bi *big.Int, tmp []byte) int {
	if bi.BitLen() <= 64 {
		i := bi.Uint64()
		bs := strconv.AppendUint(tmp, i, 10)
		return trailingZerosFromBytes(bs)
	}
	bs := bi.Append(tmp, 10)
	return trailingZerosFromBytes(bs)
}

func trailingZerosFromBytes(bs []byte) int {
	tens := 0
	for bs[len(bs)-1-tens] == '0' {
		tens++
	}
	return tens
}
<|endoftext|>


<commit_before>package main

import (
	"log"
	"os"
	"strconv"
	"time"

	"github.com/garyburd/redigo/redis"
	"github.com/lancetw/hcfd-forecast/db"
	"github.com/lancetw/hcfd-forecast/rain"
	"github.com/line/line-bot-sdk-go/linebot"
)

const timeZone = "Asia/Taipei"

var bot *linebot.Client

func main() {
	strID := os.Getenv("ChannelID")
	numID, err := strconv.ParseInt(strID, 10, 64)
	if err != nil {
		log.Fatal("Wrong environment setting about ChannelID")
	}
	bot, err = linebot.NewClient(numID, os.Getenv("ChannelSecret"), os.Getenv("MID"))
	if err != nil {
		log.Println("Bot:", bot, " err:", err)
	}

	for {
		log.Println("=== 查詢。開始 ===")

		c := db.Connect(os.Getenv("REDISTOGO_URL"))

		targets0 := []string{"新竹市"}
		msgs0, token0 := rain.GetRainingInfo(targets0, false)

		if token != "" {
			status0, getErr := redis.Int(c.Do("SISMEMBER", "token0", token0))
			if getErr != nil {
				if err != nil {
					log.Println(err)
				}
			}

			if status0 == 0 {
				users0, smembersErr := redis.Strings(c.Do("SMEMBERS", "user"))

				if smembersErr != nil {
					log.Println("GetRainingInfo SMEMBERS redis error", smembersErr)
				} else {
					local := time.Now()
					location, timeZoneErr := time.LoadLocation(timeZone)
					if timeZoneErr == nil {
						local = local.In(location)
					}
					for _, contentTo := range users0 {
						for _, msg := range msgs0 {
							_, err = bot.SendText([]string{contentTo}, msg)
							if err != nil {
								log.Println(err)
							}
						}
					}
				}
			}

			n0, addErr := c.Do("SADD", "token0", token0)
			if addErr != nil {
				log.Println("GetRainingInfo SADD to redis error", addErr, n0)
			}
		}

		targets1 := []string{"新竹市", "新竹縣"}
		msgs1, token1 := rain.GetWarningInfo(targets1)

		if token1 != "" {
			status1, getErr := redis.Int(c.Do("SISMEMBER", "token1", token1))
			if getErr != nil {
				if err != nil {
					log.Println(err)
				}
			}

			if status1 == 0 {
				users1, smembersErr := redis.Strings(c.Do("SMEMBERS", "user"))

				if smembersErr != nil {
					log.Println("GetWarningInfo SMEMBERS redis error", smembersErr)
				} else {
					local := time.Now()
					location, locationErr := time.LoadLocation(timeZone)
					if locationErr == nil {
						local = local.In(location)
					}
					for _, contentTo := range users1 {
						for _, msg := range msgs1 {
							_, msgErr := bot.SendText([]string{contentTo}, msg)
							if msgErr != nil {
								log.Println(err)
							}
						}
					}
				}
			}
		}

		if token1 != "" {
			n, addErr := c.Do("SADD", "token1", token1)
			if addErr != nil {
				log.Println("GetWarningInfo SADD to redis error", addErr, n)
			}
		}

		defer c.Close()

		log.Println("=== 查詢。結束 ===")

		time.Sleep(60 * time.Second)
	}
}
<commit_msg>Update main.go<commit_after>package main

import (
	"log"
	"os"
	"strconv"
	"time"

	"github.com/garyburd/redigo/redis"
	"github.com/lancetw/hcfd-forecast/db"
	"github.com/lancetw/hcfd-forecast/rain"
	"github.com/line/line-bot-sdk-go/linebot"
)

const timeZone = "Asia/Taipei"

var bot *linebot.Client

func main() {
	strID := os.Getenv("ChannelID")
	numID, err := strconv.ParseInt(strID, 10, 64)
	if err != nil {
		log.Fatal("Wrong environment setting about ChannelID")
	}
	bot, err = linebot.NewClient(numID, os.Getenv("ChannelSecret"), os.Getenv("MID"))
	if err != nil {
		log.Println("Bot:", bot, " err:", err)
	}

	for {
		log.Println("=== 查詢。開始 ===")

		c := db.Connect(os.Getenv("REDISTOGO_URL"))

		targets0 := []string{"新竹市"}
		msgs0, token0 := rain.GetRainingInfo(targets0, false)

		if token0 != "" {
			status0, getErr := redis.Int(c.Do("SISMEMBER", "token0", token0))
			if getErr != nil {
				if err != nil {
					log.Println(err)
				}
			}

			if status0 == 0 {
				users0, smembersErr := redis.Strings(c.Do("SMEMBERS", "user"))

				if smembersErr != nil {
					log.Println("GetRainingInfo SMEMBERS redis error", smembersErr)
				} else {
					local := time.Now()
					location, timeZoneErr := time.LoadLocation(timeZone)
					if timeZoneErr == nil {
						local = local.In(location)
					}
					for _, contentTo := range users0 {
						for _, msg := range msgs0 {
							_, err = bot.SendText([]string{contentTo}, msg)
							if err != nil {
								log.Println(err)
							}
						}
					}
				}
			}

			n0, addErr := c.Do("SADD", "token0", token0)
			if addErr != nil {
				log.Println("GetRainingInfo SADD to redis error", addErr, n0)
			}
		}

		targets1 := []string{"新竹市", "新竹縣"}
		msgs1, token1 := rain.GetWarningInfo(targets1)

		if token1 != "" {
			status1, getErr := redis.Int(c.Do("SISMEMBER", "token1", token1))
			if getErr != nil {
				if err != nil {
					log.Println(err)
				}
			}

			if status1 == 0 {
				users1, smembersErr := redis.Strings(c.Do("SMEMBERS", "user"))

				if smembersErr != nil {
					log.Println("GetWarningInfo SMEMBERS redis error", smembersErr)
				} else {
					local := time.Now()
					location, locationErr := time.LoadLocation(timeZone)
					if locationErr == nil {
						local = local.In(location)
					}
					for _, contentTo := range users1 {
						for _, msg := range msgs1 {
							_, msgErr := bot.SendText([]string{contentTo}, msg)
							if msgErr != nil {
								log.Println(err)
							}
						}
					}
				}
			}
		}

		if token1 != "" {
			n, addErr := c.Do("SADD", "token1", token1)
			if addErr != nil {
				log.Println("GetWarningInfo SADD to redis error", addErr, n)
			}
		}

		defer c.Close()

		log.Println("=== 查詢。結束 ===")

		time.Sleep(60 * time.Second)
	}
}
<|endoftext|>


<commit_before>package imageutil

import (
	"context"
	"encoding/json"
	"sync"
	"time"

	"github.com/containerd/containerd/content"
	"github.com/containerd/containerd/images"
	"github.com/containerd/containerd/leases"
	"github.com/containerd/containerd/platforms"
	"github.com/containerd/containerd/reference"
	"github.com/containerd/containerd/remotes"
	"github.com/containerd/containerd/remotes/docker"
	"github.com/moby/buildkit/util/leaseutil"
	"github.com/moby/buildkit/util/resolver/limited"
	"github.com/moby/buildkit/util/resolver/retryhandler"
	digest "github.com/opencontainers/go-digest"
	ocispecs "github.com/opencontainers/image-spec/specs-go/v1"
	"github.com/pkg/errors"
)

type ContentCache interface {
	content.Ingester
	content.Provider
}

var leasesMu sync.Mutex
var leasesF []func(context.Context) error

func CancelCacheLeases() {
	leasesMu.Lock()
	for _, f := range leasesF {
		f(context.TODO())
	}
	leasesF = nil
	leasesMu.Unlock()
}

func AddLease(f func(context.Context) error) {
	leasesMu.Lock()
	leasesF = append(leasesF, f)
	leasesMu.Unlock()
}

func Config(ctx context.Context, str string, resolver remotes.Resolver, cache ContentCache, leaseManager leases.Manager, p *ocispecs.Platform) (digest.Digest, []byte, error) {
	// TODO: fix buildkit to take interface instead of struct
	var platform platforms.MatchComparer
	if p != nil {
		platform = platforms.Only(*p)
	} else {
		platform = platforms.Default()
	}
	ref, err := reference.Parse(str)
	if err != nil {
		return "", nil, errors.WithStack(err)
	}

	if leaseManager != nil {
		ctx2, done, err := leaseutil.WithLease(ctx, leaseManager, leases.WithExpiration(5*time.Minute), leaseutil.MakeTemporary)
		if err != nil {
			return "", nil, errors.WithStack(err)
		}
		ctx = ctx2
		defer func() {
			// this lease is not deleted to allow other components to access manifest/config from cache. It will be deleted after 5 min deadline or on pruning inactive builder
			AddLease(done)
		}()
	}

	desc := ocispecs.Descriptor{
		Digest: ref.Digest(),
	}
	if desc.Digest != "" {
		ra, err := cache.ReaderAt(ctx, desc)
		if err == nil {
			desc.Size = ra.Size()
			mt, err := DetectManifestMediaType(ra)
			if err == nil {
				desc.MediaType = mt
			}
		}
	}
	// use resolver if desc is incomplete
	if desc.MediaType == "" {
		_, desc, err = resolver.Resolve(ctx, ref.String())
		if err != nil {
			return "", nil, err
		}
	}

	fetcher, err := resolver.Fetcher(ctx, ref.String())
	if err != nil {
		return "", nil, err
	}

	if desc.MediaType == images.MediaTypeDockerSchema1Manifest {
		return readSchema1Config(ctx, ref.String(), desc, fetcher, cache)
	}

	children := childrenConfigHandler(cache, platform)

	handlers := []images.Handler{
		retryhandler.New(limited.FetchHandler(cache, fetcher, str), func(_ []byte) {}),
		children,
	}
	if err := images.Dispatch(ctx, images.Handlers(handlers...), nil, desc); err != nil {
		return "", nil, err
	}
	config, err := images.Config(ctx, cache, desc, platform)
	if err != nil {
		return "", nil, err
	}

	dt, err := content.ReadBlob(ctx, cache, config)
	if err != nil {
		return "", nil, err
	}

	return desc.Digest, dt, nil
}

func childrenConfigHandler(provider content.Provider, platform platforms.MatchComparer) images.HandlerFunc {
	return func(ctx context.Context, desc ocispecs.Descriptor) ([]ocispecs.Descriptor, error) {
		var descs []ocispecs.Descriptor
		switch desc.MediaType {
		case images.MediaTypeDockerSchema2Manifest, ocispecs.MediaTypeImageManifest:
			p, err := content.ReadBlob(ctx, provider, desc)
			if err != nil {
				return nil, err
			}

			// TODO(stevvooe): We just assume oci manifest, for now. There may be
			// subtle differences from the docker version.
			var manifest ocispecs.Manifest
			if err := json.Unmarshal(p, &manifest); err != nil {
				return nil, err
			}

			descs = append(descs, manifest.Config)
		case images.MediaTypeDockerSchema2ManifestList, ocispecs.MediaTypeImageIndex:
			p, err := content.ReadBlob(ctx, provider, desc)
			if err != nil {
				return nil, err
			}

			var index ocispecs.Index
			if err := json.Unmarshal(p, &index); err != nil {
				return nil, err
			}

			if platform != nil {
				for _, d := range index.Manifests {
					if d.Platform == nil || platform.Match(*d.Platform) {
						descs = append(descs, d)
					}
				}
			} else {
				descs = append(descs, index.Manifests...)
			}
		case images.MediaTypeDockerSchema2Config, ocispecs.MediaTypeImageConfig, docker.LegacyConfigMediaType:
			// childless data types.
			return nil, nil
		default:
			return nil, errors.Errorf("encountered unknown type %v; children may not be fetched", desc.MediaType)
		}

		return descs, nil
	}
}

// specs.MediaTypeImageManifest, // TODO: detect schema1/manifest-list
func DetectManifestMediaType(ra content.ReaderAt) (string, error) {
	// TODO: schema1

	dt := make([]byte, ra.Size())
	if _, err := ra.ReadAt(dt, 0); err != nil {
		return "", err
	}

	return DetectManifestBlobMediaType(dt)
}

func DetectManifestBlobMediaType(dt []byte) (string, error) {
	var mfst struct {
		MediaType string          `json:"mediaType"`
		Config    json.RawMessage `json:"config"`
	}

	if err := json.Unmarshal(dt, &mfst); err != nil {
		return "", err
	}

	if mfst.MediaType != "" {
		return mfst.MediaType, nil
	}
	if mfst.Config != nil {
		return images.MediaTypeDockerSchema2Manifest, nil
	}
	return images.MediaTypeDockerSchema2ManifestList, nil
}
<commit_msg>imageutil: make mediatype detection more stricter<commit_after>package imageutil

import (
	"context"
	"encoding/json"
	"sync"
	"time"

	"github.com/containerd/containerd/content"
	"github.com/containerd/containerd/images"
	"github.com/containerd/containerd/leases"
	"github.com/containerd/containerd/platforms"
	"github.com/containerd/containerd/reference"
	"github.com/containerd/containerd/remotes"
	"github.com/containerd/containerd/remotes/docker"
	"github.com/moby/buildkit/util/leaseutil"
	"github.com/moby/buildkit/util/resolver/limited"
	"github.com/moby/buildkit/util/resolver/retryhandler"
	digest "github.com/opencontainers/go-digest"
	ocispecs "github.com/opencontainers/image-spec/specs-go/v1"
	"github.com/pkg/errors"
)

type ContentCache interface {
	content.Ingester
	content.Provider
}

var leasesMu sync.Mutex
var leasesF []func(context.Context) error

func CancelCacheLeases() {
	leasesMu.Lock()
	for _, f := range leasesF {
		f(context.TODO())
	}
	leasesF = nil
	leasesMu.Unlock()
}

func AddLease(f func(context.Context) error) {
	leasesMu.Lock()
	leasesF = append(leasesF, f)
	leasesMu.Unlock()
}

func Config(ctx context.Context, str string, resolver remotes.Resolver, cache ContentCache, leaseManager leases.Manager, p *ocispecs.Platform) (digest.Digest, []byte, error) {
	// TODO: fix buildkit to take interface instead of struct
	var platform platforms.MatchComparer
	if p != nil {
		platform = platforms.Only(*p)
	} else {
		platform = platforms.Default()
	}
	ref, err := reference.Parse(str)
	if err != nil {
		return "", nil, errors.WithStack(err)
	}

	if leaseManager != nil {
		ctx2, done, err := leaseutil.WithLease(ctx, leaseManager, leases.WithExpiration(5*time.Minute), leaseutil.MakeTemporary)
		if err != nil {
			return "", nil, errors.WithStack(err)
		}
		ctx = ctx2
		defer func() {
			// this lease is not deleted to allow other components to access manifest/config from cache. It will be deleted after 5 min deadline or on pruning inactive builder
			AddLease(done)
		}()
	}

	desc := ocispecs.Descriptor{
		Digest: ref.Digest(),
	}
	if desc.Digest != "" {
		ra, err := cache.ReaderAt(ctx, desc)
		if err == nil {
			desc.Size = ra.Size()
			mt, err := DetectManifestMediaType(ra)
			if err == nil {
				desc.MediaType = mt
			}
		}
	}
	// use resolver if desc is incomplete
	if desc.MediaType == "" {
		_, desc, err = resolver.Resolve(ctx, ref.String())
		if err != nil {
			return "", nil, err
		}
	}

	fetcher, err := resolver.Fetcher(ctx, ref.String())
	if err != nil {
		return "", nil, err
	}

	if desc.MediaType == images.MediaTypeDockerSchema1Manifest {
		return readSchema1Config(ctx, ref.String(), desc, fetcher, cache)
	}

	children := childrenConfigHandler(cache, platform)

	handlers := []images.Handler{
		retryhandler.New(limited.FetchHandler(cache, fetcher, str), func(_ []byte) {}),
		children,
	}
	if err := images.Dispatch(ctx, images.Handlers(handlers...), nil, desc); err != nil {
		return "", nil, err
	}
	config, err := images.Config(ctx, cache, desc, platform)
	if err != nil {
		return "", nil, err
	}

	dt, err := content.ReadBlob(ctx, cache, config)
	if err != nil {
		return "", nil, err
	}

	return desc.Digest, dt, nil
}

func childrenConfigHandler(provider content.Provider, platform platforms.MatchComparer) images.HandlerFunc {
	return func(ctx context.Context, desc ocispecs.Descriptor) ([]ocispecs.Descriptor, error) {
		var descs []ocispecs.Descriptor
		switch desc.MediaType {
		case images.MediaTypeDockerSchema2Manifest, ocispecs.MediaTypeImageManifest:
			p, err := content.ReadBlob(ctx, provider, desc)
			if err != nil {
				return nil, err
			}

			// TODO(stevvooe): We just assume oci manifest, for now. There may be
			// subtle differences from the docker version.
			var manifest ocispecs.Manifest
			if err := json.Unmarshal(p, &manifest); err != nil {
				return nil, err
			}

			descs = append(descs, manifest.Config)
		case images.MediaTypeDockerSchema2ManifestList, ocispecs.MediaTypeImageIndex:
			p, err := content.ReadBlob(ctx, provider, desc)
			if err != nil {
				return nil, err
			}

			var index ocispecs.Index
			if err := json.Unmarshal(p, &index); err != nil {
				return nil, err
			}

			if platform != nil {
				for _, d := range index.Manifests {
					if d.Platform == nil || platform.Match(*d.Platform) {
						descs = append(descs, d)
					}
				}
			} else {
				descs = append(descs, index.Manifests...)
			}
		case images.MediaTypeDockerSchema2Config, ocispecs.MediaTypeImageConfig, docker.LegacyConfigMediaType:
			// childless data types.
			return nil, nil
		default:
			return nil, errors.Errorf("encountered unknown type %v; children may not be fetched", desc.MediaType)
		}

		return descs, nil
	}
}

// specs.MediaTypeImageManifest, // TODO: detect schema1/manifest-list
func DetectManifestMediaType(ra content.ReaderAt) (string, error) {
	// TODO: schema1

	dt := make([]byte, ra.Size())
	if _, err := ra.ReadAt(dt, 0); err != nil {
		return "", err
	}

	return DetectManifestBlobMediaType(dt)
}

func DetectManifestBlobMediaType(dt []byte) (string, error) {
	var mfst struct {
		MediaType *string         `json:"mediaType"`
		Config    json.RawMessage `json:"config"`
		Manifests json.RawMessage `json:"manifests"`
		Layers    json.RawMessage `json:"layers"`
	}

	if err := json.Unmarshal(dt, &mfst); err != nil {
		return "", err
	}

	mt := images.MediaTypeDockerSchema2ManifestList

	if mfst.Config != nil || mfst.Layers != nil {
		mt = images.MediaTypeDockerSchema2Manifest

		if mfst.Manifests != nil {
			return "", errors.Errorf("invalid ambiguous manifest and manifest list")
		}
	}

	if mfst.MediaType != nil {
		switch *mfst.MediaType {
		case images.MediaTypeDockerSchema2ManifestList, ocispecs.MediaTypeImageIndex:
			if mt != images.MediaTypeDockerSchema2ManifestList {
				return "", errors.Errorf("mediaType in manifest does not match manifest contents")
			}
			mt = *mfst.MediaType
		case images.MediaTypeDockerSchema2Manifest, ocispecs.MediaTypeImageManifest:
			if mt != images.MediaTypeDockerSchema2Manifest {
				return "", errors.Errorf("mediaType in manifest does not match manifest contents")
			}
			mt = *mfst.MediaType
		}
	}
	return mt, nil
}
<|endoftext|>


<commit_before>// Markov Chain
// This is a probabilistic model of language that treats words
// as nodes, chains of words as a root-to-leaf path (3-word groups for
// 3rd-order chain), and transitions between groups as edges

package ml

import (
	"fmt"
	"strings"
)

/*  TransitionTable
 * A tree of length [order]
 * EG: 2nd-order model
 * {
 * 	word: {
 * 	 word, occurrence,
 * 	 children: {
 *		word, occurrence,
 *      children: nil
 * 	 }
 * }
 */

type TransitionTable map[string]*TransitionNode

type TransitionNode struct {
	occ int
	word string
	children map[string]*TransitionNode
}

//func normalize(tt TransitionTable, length float64) {
//	for key, val := range tt  {
//		for j := range tt[key] {
//			tt[i][j] = tt[i][j]/length
//		}
//	}
//}

func Train(song string, order int) {
	words := strings.Split(song, " ")
	tt := make(TransitionTable)

	for i := range words {
		var root *TransitionNode

		if i < order + 1 {
			// Special case when just starting, I don't care for now.
			//tt["\n"] = make(map[string]map[string]float64)
			//tt["\n"]["\n"][words[i]] = 1
		} else {

			if _, ok := tt[words[i]]; !ok {
				// Make a new root TransitionNode
				root = &TransitionNode{
					children: nil,
					occ:      1,
					word:     words[i],
				}
				tt[words[i]] = root
			} else {
				// TransitionNode with that word already exists
				tt[words[i]].occ ++
				root = tt[words[i]]
			}

			traverser := root
			for j := 0; j < order; j ++ {
				// TODO: This can be AddOrIncrementOcc
				if traverser.ChildExists(words[i-j]) {
					// If the child exists, update its occurrence and traverse deeper
					traverser.children[words[i-j]].occ ++
				} else {
					// Child doesn't exist, so we make one
					traverser.Add(words[i-j])
				}
				traverser = traverser.children[words[i-j]]
				fmt.Println( "\t", traverser.occ, traverser.word, traverser.children)
			}
		}
	}
//	Predict(tt)
}

/**
 * Predict
 * @param {TransitionTable} tt
 *
 * Approach (so I don't forget):
 * Take occurrence of result
 * If second order prediction yields results, double them.
 * If third order prediction yields results, triple them.
 * ...etc
 */

// Traverse the tree until its leaf for each letter to sum up it's occurrences
// Weight more "specific" occurrences higher
//func Predict(tt TransitionTable) {
//		var max int
//		var ret []string
//		for i := 0; i < 50; i++ {
//			// find max score for word in tt
//			for _, val1 := range tt {
//				for _, val2 := range val1.children {
//					for _, thirdWord := range val2.children {
//						if thirdWord.occ > max {
//							max = thirdWord.occ
//							ret = append(ret, thirdWord.word)
//						}
//					}
//					max = 0
//				}
//			}
//		}
//	fmt.Println(tt)
//	fmt.Println("======================")
//	fmt.Println(ret)
//}

/**
 * Add
 *
 * Adds a child with a given word to the children hash of a given node.
 */
func (tn *TransitionNode) Add(word string) {
	if tn.children == nil {
		tn.children = map[string]*TransitionNode{}
	}
	tn.children[word] = &TransitionNode{
		children: nil,
		occ:      1,
		word:     word,
	}
}

/**
 * ChildExists
 *
 * Given a node, checks if a child exists in the children map
 * with the specified word
 */
func (tn TransitionNode)ChildExists(word string) bool {
	if _, ok := tn.children[word]; ok {
		return true
	}
	return false
}
<commit_msg>Modify TransitionTable to RootTable and LeafTable<commit_after>// Markov Chain
// This is a probabilistic model of language that treats words
// as nodes, chains of words as a root-to-leaf path (3-word groups for
// 3rd-order chain), and transitions between groups as edges

package ml

import (
	"fmt"
	"strings"
)

/**
 *	@type {map[string]*TransitionNode} RootTable
 *
 *	Entry points for forward traversal of the map of TransitionNodes
 *	Maps words -> pointers to the node (unique) that contains them
 */
type RootTable map[string]*TransitionNode

/**
 *	@type {map[string][]*TransitionNode} LeafTable
 *
 *	Entry points for backward traversal of the map of TransitionNodes
 *	Maps words -> pointers to a slice of nodes that contain them
 */
type LeafTable map[string][]*TransitionNode

/**
 *	@type {struct} TransitionNode
 *
 *	@member {map[string]*TransitionNode} children - Maps previous word -> pointer to its node
 *	@member {*TransitionNode}            parent   - Pointer to the node containing the next word
 *	@member {int}                        occ      - The occurrence of the node coming from its parent
 *	@member {string}                     word     - The value of the word
 */
type TransitionNode struct {
	children map[string]*TransitionNode
	parent *TransitionNode

	occ int
	word string
}

func Train(song string, order int) {
	words := strings.Split(song, " ")
	tt := make(RootTable)

	for i := range words {
		var root *TransitionNode

		if i < order + 1 {
			// Special case when just starting, I don't care for now.
			//tt["\n"] = make(map[string]map[string]float64)
			//tt["\n"]["\n"][words[i]] = 1
		} else {

			if _, ok := tt[words[i]]; !ok {
				// Make a new root TransitionNode
				root = &TransitionNode{
					children: nil,
					parent:   nil,
					occ:      1,
					word:     words[i],
				}
				tt[words[i]] = root
			} else {
				// TransitionNode with that word already exists
				tt[words[i]].occ ++
				root = tt[words[i]]
			}

			traverser := root
			for j := 0; j < order; j ++ {
				// TODO: This can be AddOrIncrementOcc
				if traverser.ChildExists(words[i-j]) {
					// If the child exists, update its occurrence and traverse deeper
					traverser.children[words[i-j]].occ ++
				} else {
					// Child doesn't exist, so we make one
					traverser.Add(words[i-j])
				}
				traverser = traverser.children[words[i-j]]
				fmt.Println( "\t", traverser.occ, traverser.word, traverser.children)
			}
		}
	}
//	Predict(tt)
}

/**
 * Predict
 * @param {RootTable} tt
 *
 * Approach (so I don't forget):
 * Take occurrence of result
 * If second order prediction yields results, double them.
 * If third order prediction yields results, triple them.
 * ...etc
 */

// Traverse the tree until its leaf for each letter to sum up it's occurrences
// Weight more "specific" occurrences higher
// func Predict(tt RootTable) {
//		var max int
//		var ret []string
//		for i := 0; i < 50; i++ {
//			// find max score for word in tt
//			for _, val1 := range tt {
//				for _, val2 := range val1.children {
//					for _, thirdWord := range val2.children {
//						if thirdWord.occ > max {
//							max = thirdWord.occ
//							ret = append(ret, thirdWord.word)
//						}
//					}
//					max = 0
//				}
//			}
//		}
//	fmt.Println(tt)
//	fmt.Println("======================")
//	fmt.Println(ret)
//}

/**
 * Add
 *
 * Adds a child with a given word to the children hash of a given node.
 */
func (tn *TransitionNode) Add(word string) {
	if tn.children == nil {
		tn.children = map[string]*TransitionNode{}
	}
	tn.children[word] = &TransitionNode{
		children: nil,
		parent:   tn,
		occ:      1,
		word:     word,
	}
}

/**
 * ChildExists
 *
 * Given a node, checks if a child exists in the children map
 * with the specified word
 */
func (tn TransitionNode) ChildExists(word string) bool {
	if _, ok := tn.children[word]; ok {
		return true
	}
	return false
}
<|endoftext|>