<commit_before>package cloudwatch

import (
	"context"
	"encoding/json"
	"errors"
	"io"
	"io/ioutil"
	"net/http"
	"net/http/httptest"
	"testing"
	"time"

	"github.com/sirupsen/logrus"
	"github.com/stretchr/testify/assert"
	"github.com/stripe/veneur/v14/samplers"
)

// TestServer wraps an internal httptest.Server and provides a convenience
// method for retrieving the most recently written series
type TestServer struct {
	URL    string
	server *httptest.Server
}

// Close closes the internal test server
func (t *TestServer) Close() {
	t.server.Close()
}

// NewTestServer starts a test server instance. Ensure calls are followed by
// defer server.Close() to avoid hanging connections
func NewTestServer(t *testing.T, handlerDelay time.Duration, reqBodyCh chan []byte) *TestServer {
	result := TestServer{}

	router := http.NewServeMux()
	router.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		time.Sleep(handlerDelay)

		b, err := io.ReadAll(r.Body)
		if err != nil {
			t.Error("empty request body")
		}
		reqBodyCh <- b
	})

	server := httptest.NewServer(router)
	result.URL = server.URL + "/"
	result.server = server
	t.Log("test server listening on", server.URL)

	return &result
}

// latest returns the most recent write request, or errors if there was none
func latest(reqBodyCh chan []byte, timeoutSecs int) ([]byte, error) {
	timeout := time.After(time.Duration(timeoutSecs) * time.Second)
	select {
	case data := <-reqBodyCh:
		return data, nil
	case <-timeout:
		return nil, errors.New("no data received")
	}
}

func TestName(t *testing.T) {
	sink := NewCloudwatchMetricSink(
		"cloudwatch", "http://localhost/", "test", "us-east-1000", "cloudwatch_standard_unit",
		time.Second*30, true, []string{}, logrus.NewEntry(logrus.New()),
	)
	assert.Equal(t, "cloudwatch", sink.Name())
}

func TestFlush(t *testing.T) {
	// Listen for PutMetricData
	reqBodyCh := make(chan []byte)
	server := NewTestServer(t, 0, reqBodyCh)
	defer server.Close()

	// input.1.json contains three timeseries samples in InterMetrics format
	jsInput, err := ioutil.ReadFile("testdata/input.1.json")
	assert.NoError(t, err)
	var metrics []samplers.InterMetric
	assert.NoError(t, json.Unmarshal(jsInput, &metrics))

	// Initialize sink
	sink := NewCloudwatchMetricSink(
		"cloudwatch", server.URL, "test", "us-east-1000", "cloudwatch_standard_unit",
		time.Second*30, true, []string{}, logrus.NewEntry(logrus.New()),
	)
	sink.Start(nil)

	// Assert data is as we expect
	done := make(chan bool)
	go func(reqBodyCh chan []byte, done chan bool) {
		expectedOutput, err := ioutil.ReadFile("testdata/output.1.txt")
		assert.NoError(t, err)
		data, err := latest(reqBodyCh, 3)
		assert.NoError(t, err)
		assert.Equal(t, string(expectedOutput), string(data))
		done <- true
	}(reqBodyCh, done)

	// Flush the sink
	_, err = sink.Flush(context.Background(), metrics)
	assert.NoError(t, err)

	<-done
}

func TestFlushWithStandardUnitTagName(t *testing.T) {
	// Listen for PutMetricData
	reqBodyCh := make(chan []byte)
	server := NewTestServer(t, 0, reqBodyCh)
	defer server.Close()

	// input.2.json contains one timeseries sample in InterMetrics format, with a unit specified
	jsInput, err := ioutil.ReadFile("testdata/input.2.json")
	assert.NoError(t, err)
	var metrics []samplers.InterMetric
	assert.NoError(t, json.Unmarshal(jsInput, &metrics))

	// Initialize sink
	sink := NewCloudwatchMetricSink(
		"cloudwatch", server.URL, "test", "us-east-1000", "cloudwatch_standard_unit",
		time.Second*30, true, []string{}, logrus.NewEntry(logrus.New()),
	)
	sink.Start(nil)

	// Inspect data that was flushed, which should have a standard unit and no dimensions
	done := make(chan bool)
	go func(reqBodyCh chan []byte, done chan bool) {
		expectedOutput, err := ioutil.ReadFile("testdata/output.2.txt")
		assert.NoError(t, err)
		data, err := latest(reqBodyCh, 3)
		assert.NoError(t, err)
		assert.Equal(t, string(expectedOutput), string(data))
		done <- true
	}(reqBodyCh, done)

	// Flush the sink
	_, err = sink.Flush(context.Background(), metrics)
	assert.NoError(t, err)

	<-done
}

func TestFlushWithStripTags(t *testing.T) {
	// Listen for PutMetricData
	reqBodyCh := make(chan []byte)
	server := NewTestServer(t, 0, reqBodyCh)
	defer server.Close()

	// input.2.json contains timeseries with tags to strip, and tags to keep
	jsInput, err := ioutil.ReadFile("testdata/input.3.json")
	assert.NoError(t, err)
	var metrics []samplers.InterMetric
	assert.NoError(t, json.Unmarshal(jsInput, &metrics))

	// Initialize sink
	stripTags := []string{"baz"}
	sink := NewCloudwatchMetricSink(
		"cloudwatch", server.URL, "test", "us-east-1000", "cloudwatch_standard_unit",
		time.Second*30, true, stripTags, logrus.NewEntry(logrus.New()),
	)
	sink.Start(nil)

	// Inspect data that was flushed
	// - Datapoint (1, 3) should not have tags
	// - Datapoint (2) should have one tag
	done := make(chan bool)
	go func(reqBodyCh chan []byte, done chan bool) {
		expectedOutput, err := ioutil.ReadFile("testdata/output.3.txt")
		assert.NoError(t, err)
		data, err := latest(reqBodyCh, 3)
		assert.NoError(t, err)
		assert.Equal(t, string(expectedOutput), string(data))
		done <- true
	}(reqBodyCh, done)

	// Flush the sink
	_, err = sink.Flush(context.Background(), metrics)
	assert.NoError(t, err)

	<-done
}

func TestFlushNoop(t *testing.T) {
	// Listen for PutMetricData
	reqBodyCh := make(chan []byte)
	server := NewTestServer(t, 0, reqBodyCh)
	defer server.Close()

	// Pass empty metrics slice
	var metrics []samplers.InterMetric

	// Initialize the sink
	sink := NewCloudwatchMetricSink(
		"cloudwatch", server.URL, "test", "us-east-1000", "cloudwatch_standard_unit",
		time.Second*30, true, []string{}, logrus.NewEntry(logrus.New()),
	)
	sink.Start(nil)

	// Assert the server was never hit
	done := make(chan bool)
	go func(reqBodyCh chan []byte, done chan bool) {
		_, err := latest(reqBodyCh, 3)
		assert.Error(t, err)
		done <- true
	}(reqBodyCh, done)

	// Flush the sink
	_, err := sink.Flush(context.Background(), metrics)
	assert.NoError(t, err)

	<-done
}

func TestFlushRemoteTimeout(t *testing.T) {
	// Server handler should return response after the flush timeout expires
	customTimeout := time.Second * 1
	serverDelay := customTimeout + time.Second

	// Listen for PutMetricData
	reqBodyCh := make(chan []byte)
	server := NewTestServer(t, serverDelay, reqBodyCh)
	defer server.Close()

	// Pass non-empty metrics slice
	metrics := []samplers.InterMetric{{}}

	// Initialize the sink
	sink := NewCloudwatchMetricSink(
		"cloudwatch", server.URL, "test", "us-east-1000", "cloudwatch_standard_unit",
		customTimeout, true, []string{}, logrus.NewEntry(logrus.New()),
	)
	sink.Start(nil)

	// Make sure that the server can Close, eventually
	done := make(chan bool)
	go func(reqBodyCh chan []byte, done chan bool) {
		<-reqBodyCh
		done <- true
	}(reqBodyCh, done)

	// Assert the flush failed
	_, err := sink.Flush(context.Background(), metrics)
	assert.Error(t, err)

	<-done
}
<commit_msg>Fix typo in comment on cloudwatch sink tests (#965)<commit_after>package cloudwatch

import (
	"context"
	"encoding/json"
	"errors"
	"io"
	"io/ioutil"
	"net/http"
	"net/http/httptest"
	"testing"
	"time"

	"github.com/sirupsen/logrus"
	"github.com/stretchr/testify/assert"
	"github.com/stripe/veneur/v14/samplers"
)

// TestServer wraps an internal httptest.Server and provides a convenience
// method for retrieving the most recently written series
type TestServer struct {
	URL    string
	server *httptest.Server
}

// Close closes the internal test server
func (t *TestServer) Close() {
	t.server.Close()
}

// NewTestServer starts a test server instance. Ensure calls are followed by
// defer server.Close() to avoid hanging connections
func NewTestServer(t *testing.T, handlerDelay time.Duration, reqBodyCh chan []byte) *TestServer {
	result := TestServer{}

	router := http.NewServeMux()
	router.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		time.Sleep(handlerDelay)

		b, err := io.ReadAll(r.Body)
		if err != nil {
			t.Error("empty request body")
		}
		reqBodyCh <- b
	})

	server := httptest.NewServer(router)
	result.URL = server.URL + "/"
	result.server = server
	t.Log("test server listening on", server.URL)

	return &result
}

// latest returns the most recent write request, or errors if there was none
func latest(reqBodyCh chan []byte, timeoutSecs int) ([]byte, error) {
	timeout := time.After(time.Duration(timeoutSecs) * time.Second)
	select {
	case data := <-reqBodyCh:
		return data, nil
	case <-timeout:
		return nil, errors.New("no data received")
	}
}

func TestName(t *testing.T) {
	sink := NewCloudwatchMetricSink(
		"cloudwatch", "http://localhost/", "test", "us-east-1000", "cloudwatch_standard_unit",
		time.Second*30, true, []string{}, logrus.NewEntry(logrus.New()),
	)
	assert.Equal(t, "cloudwatch", sink.Name())
}

func TestFlush(t *testing.T) {
	// Listen for PutMetricData
	reqBodyCh := make(chan []byte)
	server := NewTestServer(t, 0, reqBodyCh)
	defer server.Close()

	// input.1.json contains three timeseries samples in InterMetrics format
	jsInput, err := ioutil.ReadFile("testdata/input.1.json")
	assert.NoError(t, err)
	var metrics []samplers.InterMetric
	assert.NoError(t, json.Unmarshal(jsInput, &metrics))

	// Initialize sink
	sink := NewCloudwatchMetricSink(
		"cloudwatch", server.URL, "test", "us-east-1000", "cloudwatch_standard_unit",
		time.Second*30, true, []string{}, logrus.NewEntry(logrus.New()),
	)
	sink.Start(nil)

	// Assert data is as we expect
	done := make(chan bool)
	go func(reqBodyCh chan []byte, done chan bool) {
		expectedOutput, err := ioutil.ReadFile("testdata/output.1.txt")
		assert.NoError(t, err)
		data, err := latest(reqBodyCh, 3)
		assert.NoError(t, err)
		assert.Equal(t, string(expectedOutput), string(data))
		done <- true
	}(reqBodyCh, done)

	// Flush the sink
	_, err = sink.Flush(context.Background(), metrics)
	assert.NoError(t, err)

	<-done
}

func TestFlushWithStandardUnitTagName(t *testing.T) {
	// Listen for PutMetricData
	reqBodyCh := make(chan []byte)
	server := NewTestServer(t, 0, reqBodyCh)
	defer server.Close()

	// input.2.json contains one timeseries sample in InterMetrics format, with a unit specified
	jsInput, err := ioutil.ReadFile("testdata/input.2.json")
	assert.NoError(t, err)
	var metrics []samplers.InterMetric
	assert.NoError(t, json.Unmarshal(jsInput, &metrics))

	// Initialize sink
	sink := NewCloudwatchMetricSink(
		"cloudwatch", server.URL, "test", "us-east-1000", "cloudwatch_standard_unit",
		time.Second*30, true, []string{}, logrus.NewEntry(logrus.New()),
	)
	sink.Start(nil)

	// Inspect data that was flushed, which should have a standard unit and no dimensions
	done := make(chan bool)
	go func(reqBodyCh chan []byte, done chan bool) {
		expectedOutput, err := ioutil.ReadFile("testdata/output.2.txt")
		assert.NoError(t, err)
		data, err := latest(reqBodyCh, 3)
		assert.NoError(t, err)
		assert.Equal(t, string(expectedOutput), string(data))
		done <- true
	}(reqBodyCh, done)

	// Flush the sink
	_, err = sink.Flush(context.Background(), metrics)
	assert.NoError(t, err)

	<-done
}

func TestFlushWithStripTags(t *testing.T) {
	// Listen for PutMetricData
	reqBodyCh := make(chan []byte)
	server := NewTestServer(t, 0, reqBodyCh)
	defer server.Close()

	// input.3.json contains timeseries with tags to strip, and tags to keep
	jsInput, err := ioutil.ReadFile("testdata/input.3.json")
	assert.NoError(t, err)
	var metrics []samplers.InterMetric
	assert.NoError(t, json.Unmarshal(jsInput, &metrics))

	// Initialize sink
	stripTags := []string{"baz"}
	sink := NewCloudwatchMetricSink(
		"cloudwatch", server.URL, "test", "us-east-1000", "cloudwatch_standard_unit",
		time.Second*30, true, stripTags, logrus.NewEntry(logrus.New()),
	)
	sink.Start(nil)

	// Inspect data that was flushed
	// - Datapoint (1, 3) should not have tags
	// - Datapoint (2) should have one tag
	done := make(chan bool)
	go func(reqBodyCh chan []byte, done chan bool) {
		expectedOutput, err := ioutil.ReadFile("testdata/output.3.txt")
		assert.NoError(t, err)
		data, err := latest(reqBodyCh, 3)
		assert.NoError(t, err)
		assert.Equal(t, string(expectedOutput), string(data))
		done <- true
	}(reqBodyCh, done)

	// Flush the sink
	_, err = sink.Flush(context.Background(), metrics)
	assert.NoError(t, err)

	<-done
}

func TestFlushNoop(t *testing.T) {
	// Listen for PutMetricData
	reqBodyCh := make(chan []byte)
	server := NewTestServer(t, 0, reqBodyCh)
	defer server.Close()

	// Pass empty metrics slice
	var metrics []samplers.InterMetric

	// Initialize the sink
	sink := NewCloudwatchMetricSink(
		"cloudwatch", server.URL, "test", "us-east-1000", "cloudwatch_standard_unit",
		time.Second*30, true, []string{}, logrus.NewEntry(logrus.New()),
	)
	sink.Start(nil)

	// Assert the server was never hit
	done := make(chan bool)
	go func(reqBodyCh chan []byte, done chan bool) {
		_, err := latest(reqBodyCh, 3)
		assert.Error(t, err)
		done <- true
	}(reqBodyCh, done)

	// Flush the sink
	_, err := sink.Flush(context.Background(), metrics)
	assert.NoError(t, err)

	<-done
}

func TestFlushRemoteTimeout(t *testing.T) {
	// Server handler should return response after the flush timeout expires
	customTimeout := time.Second * 1
	serverDelay := customTimeout + time.Second

	// Listen for PutMetricData
	reqBodyCh := make(chan []byte)
	server := NewTestServer(t, serverDelay, reqBodyCh)
	defer server.Close()

	// Pass non-empty metrics slice
	metrics := []samplers.InterMetric{{}}

	// Initialize the sink
	sink := NewCloudwatchMetricSink(
		"cloudwatch", server.URL, "test", "us-east-1000", "cloudwatch_standard_unit",
		customTimeout, true, []string{}, logrus.NewEntry(logrus.New()),
	)
	sink.Start(nil)

	// Make sure that the server can Close, eventually
	done := make(chan bool)
	go func(reqBodyCh chan []byte, done chan bool) {
		<-reqBodyCh
		done <- true
	}(reqBodyCh, done)

	// Assert the flush failed
	_, err := sink.Flush(context.Background(), metrics)
	assert.Error(t, err)

	<-done
}
<|endoftext|>


<commit_before>// Copyright (c) 2017 Cisco and/or its affiliates.
//
// 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 resync

import (
	"sync"
	"time"

	"github.com/ligato/cn-infra/flavors/local"
)

// Plugin implements Plugin interface therefore can be loaded with other plugins
type Plugin struct {
	Deps

	registrations map[string]Registration
	access        sync.Mutex
}

// Deps groups dependencies injected into the plugin so that they are
// logically separated from other plugin fields.
type Deps struct {
	local.PluginLogDeps // inject
}

// Init initializes variables
func (plugin *Plugin) Init() (err error) {
	plugin.registrations = make(map[string]Registration)

	//plugin.waingForResync = make(map[core.PluginName]*PluginEvent)
	//plugin.waingForResyncChan = make(chan *PluginEvent)
	//go plugin.watchWaingForResync()

	return nil
}

// AfterInit method starts the resync
func (plugin *Plugin) AfterInit() (err error) {
	plugin.startResync()

	return nil
}

// Close TODO set flag that ignore errors => not start Resync while agent is stopping
// TODO kill existing Resync timeout while agent is stopping
func (plugin *Plugin) Close() error {
	//TODO close error report channel
	plugin.access.Lock()
	defer plugin.access.Unlock()
	plugin.registrations = make(map[string]Registration)

	return nil
}

// Register function is supposed to be called in Init() by all VPP Agent plugins.
// The plugins are supposed to load current state of their objects when newResync() is called.
// But the actual CreateNewObjects(), DeleteObsoleteObjects() and ModifyExistingObjects() will be orchestrated
// to ensure there is proper order of that. If an error occurs during Resync than new Resync is planned.
func (plugin *Plugin) Register(resyncName string) Registration {
	plugin.access.Lock()
	defer plugin.access.Unlock()

	if _, found := plugin.registrations[resyncName]; found {
		plugin.Log.WithField("resyncName", resyncName).Panic("You are trying to register same resync twice")
		return nil
	}

	reg := NewRegistration(resyncName, make(chan StatusEvent, 0)) /*Zero to have back pressure*/
	plugin.registrations[resyncName] = reg
	return reg
}

// call callback on plugins to create/delete/modify objects
func (plugin *Plugin) startResync() {

	startTime := time.Now()
	for regName, reg := range plugin.registrations {
		resyncPartStart := time.Now()

		plugin.startSingleResync(regName, reg)

		resyncPart := time.Since(resyncPartStart)
		plugin.Log.WithField("durationInNs", resyncPart.Nanoseconds()).Info("Resync of ", regName, " took ", resyncPart)
	}

	resyncTime := time.Since(startTime)
	plugin.Log.WithField("durationInNs", resyncTime.Nanoseconds()).Info("Resync took ", resyncTime)
	// TODO check if there ReportError (if not than report) if error occurred even during Resync
}
func (plugin *Plugin) startSingleResync(resyncName string, reg Registration) {
	started := newStatusEvent(Started)
	reg.StatusChan() <- started
	select {
	case <-started.ReceiveAck():
	case <-time.After(5 * time.Second):
		plugin.Log.WithField("regName", resyncName).Warn("Timeout of ACK")
	}
}
<commit_msg>Do resync in deterministic order<commit_after>// Copyright (c) 2017 Cisco and/or its affiliates.
//
// 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 resync

import (
	"sync"
	"time"

	"github.com/ligato/cn-infra/flavors/local"
)

// Plugin implements Plugin interface therefore can be loaded with other plugins
type Plugin struct {
	Deps

	regOrder      []string
	registrations map[string]Registration
	access        sync.Mutex
}

// Deps groups dependencies injected into the plugin so that they are
// logically separated from other plugin fields.
type Deps struct {
	local.PluginLogDeps // inject
}

// Init initializes variables
func (plugin *Plugin) Init() (err error) {
	plugin.registrations = make(map[string]Registration)

	//plugin.waingForResync = make(map[core.PluginName]*PluginEvent)
	//plugin.waingForResyncChan = make(chan *PluginEvent)
	//go plugin.watchWaingForResync()

	return nil
}

// AfterInit method starts the resync
func (plugin *Plugin) AfterInit() (err error) {
	plugin.startResync()

	return nil
}

// Close TODO set flag that ignore errors => not start Resync while agent is stopping
// TODO kill existing Resync timeout while agent is stopping
func (plugin *Plugin) Close() error {
	//TODO close error report channel
	plugin.access.Lock()
	defer plugin.access.Unlock()
	plugin.registrations = make(map[string]Registration)

	return nil
}

// Register function is supposed to be called in Init() by all VPP Agent plugins.
// The plugins are supposed to load current state of their objects when newResync() is called.
// But the actual CreateNewObjects(), DeleteObsoleteObjects() and ModifyExistingObjects() will be orchestrated
// to ensure there is proper order of that. If an error occurs during Resync than new Resync is planned.
func (plugin *Plugin) Register(resyncName string) Registration {
	plugin.access.Lock()
	defer plugin.access.Unlock()

	if _, found := plugin.registrations[resyncName]; found {
		plugin.Log.WithField("resyncName", resyncName).Panic("You are trying to register same resync twice")
		return nil
	}
	// ensure that resync is triggered in the same order as the plugins were registered
	plugin.regOrder = append(plugin.regOrder, resyncName)

	reg := NewRegistration(resyncName, make(chan StatusEvent, 0)) /*Zero to have back pressure*/
	plugin.registrations[resyncName] = reg
	return reg
}

// call callback on plugins to create/delete/modify objects
func (plugin *Plugin) startResync() {
	plugin.Log.Info("Resync order", plugin.regOrder)
	startTime := time.Now()
	for _, regName := range plugin.regOrder {
		if reg, found := plugin.registrations[regName]; found {
			resyncPartStart := time.Now()

			plugin.startSingleResync(regName, reg)

			resyncPart := time.Since(resyncPartStart)
			plugin.Log.WithField("durationInNs", resyncPart.Nanoseconds()).Info("Resync of ", regName, " took ", resyncPart)
		}
	}

	resyncTime := time.Since(startTime)
	plugin.Log.WithField("durationInNs", resyncTime.Nanoseconds()).Info("Resync took ", resyncTime)
	// TODO check if there ReportError (if not than report) if error occurred even during Resync
}
func (plugin *Plugin) startSingleResync(resyncName string, reg Registration) {
	started := newStatusEvent(Started)
	reg.StatusChan() <- started
	select {
	case <-started.ReceiveAck():
	case <-time.After(5 * time.Second):
		plugin.Log.WithField("regName", resyncName).Warn("Timeout of ACK")
	}
}
<|endoftext|>


<commit_before>package termite

import (
	"bytes"
	"os"
	"fmt"
	"crypto"
	"hash"
	"path/filepath"
	"log"
	"io"
	"io/ioutil"
	"sync"
)

// Content based addressing cache.
//
// TODO - a successful GetAttr() will often be followed by a read.  we
// should have a small LRU cache for the content so we can serve the
// contents from memory.
type ContentCache struct {
	dir string

	hashPathMapMutex sync.Mutex
	hashPathMap      map[string]string
}

func NewContentCache(d string) *ContentCache {
	if fi, _ := os.Lstat(d); fi == nil {
		err := os.MkdirAll(d, 0700)
		if err != nil {
			panic(err)
		}
	}

	return &ContentCache{
		dir:         d,
		hashPathMap: make(map[string]string),
	}
}

func HashPath(dir string, md5 []byte) string {
	s := fmt.Sprintf("%x", md5)
	prefix := s[:2]
	name := s[2:]
	dst := filepath.Join(dir, prefix, name)
	prefixDir, _ := filepath.Split(dst)
	if err := os.MkdirAll(prefixDir, 0700); err != nil {
		log.Fatal("MkdirAll error:", err)
	}
	return dst
}

func (me *ContentCache) localPath(hash []byte) string {
	me.hashPathMapMutex.Lock()
	defer me.hashPathMapMutex.Unlock()

	return me.hashPathMap[string(hash)]
}

func (me *ContentCache) HasHash(hash []byte) bool {
	p := me.localPath(hash)
	if p != "" {
		return true
	}

	p = HashPath(me.dir, hash)
	_, err := os.Lstat(p)
	return err == nil
}

func (me *ContentCache) Path(hash []byte) string {
	p := me.localPath(hash)
	if p != "" {
		return p
	}
	return HashPath(me.dir, hash)
}

func (me *ContentCache) NewHashWriter() *HashWriter {
	return NewHashWriter(me.dir, crypto.MD5)
}

type HashWriter struct {
	hasher hash.Hash
	dest   *os.File
	hash   []byte
}

func NewHashWriter(dir string, hashfunc crypto.Hash) *HashWriter {
	me := &HashWriter{}
	tmp, err := ioutil.TempFile(dir, ".md5temp")
	if err != nil {
		panic(err)
		log.Fatal(err)
	}

	me.dest = tmp
	me.hasher = hashfunc.New()
	return me
}

func (me *HashWriter) Write(p []byte) (n int, err os.Error) {
	n, err = me.dest.Write(p)
	me.hasher.Write(p[:n])
	return n, err
}

func (me *HashWriter) Close() os.Error {
	err := me.dest.Close()

	if err != nil {
		return err
	}
	src := me.dest.Name()
	dir, _ := filepath.Split(src)
	sum := me.hasher.Sum()
	sumpath := HashPath(dir, sum)

	log.Printf("saving hash %x\n", sum)
	err = os.Rename(src, sumpath)
	if err != nil {
		if fi, _ := os.Lstat(sumpath); fi == nil {
			log.Println("already have", sumpath)
			os.Remove(src)
		}
	}
	return err
}

const _BUFSIZE = 32 * 1024

func (me *ContentCache) DestructiveSavePath(path string) (md5 []byte, content []byte) {
	f, err := os.Open(path)
	if err != nil {
		return nil, nil
	}
	h := crypto.MD5.New()
	content, err = SavingCopy(h, f, _BUFSIZE)
	if err != nil {
		log.Fatal("DestructiveSavePath:", err)
	}

	s := h.Sum()
	p := me.Path(s)
	err = os.Rename(path, p)
	if err != nil {
		if fi, _ := os.Lstat(p); fi != nil {
			os.Remove(p)
			return s, content
		}
		log.Fatal("DestructiveSavePath:", err)
	}
	return s, content
}

func (me *ContentCache) SavePath(path string) (md5 []byte, content []byte) {
	f, err := os.Open(path)
	if err != nil {
		log.Fatal(err)
	}
	defer f.Close()

	return me.SaveStream(f)
}

func (me *ContentCache) SaveImmutablePath(path string) (md5 []byte, content []byte) {
	hasher := crypto.MD5.New()

	f, err := os.Open(path)
	if err != nil {
		log.Fatal(err)
	}
	defer f.Close()
	content, err = SavingCopy(hasher, f, 32*1024)
	if err != nil && err != os.EOF {
		log.Fatal(err)
	}

	md5 = hasher.Sum()
	me.hashPathMapMutex.Lock()
	defer me.hashPathMapMutex.Unlock()
	me.hashPathMap[string(md5)] = path

	log.Printf("hashed %s to %x", path, md5)
	return md5, content
}

func (me *ContentCache) Save(content []byte) (md5 []byte) {
	buf := bytes.NewBuffer(content)
	md5, _ = me.SaveStream(buf)
	return md5
}

func (me *ContentCache) SaveStream(input io.Reader) (md5 []byte, content []byte) {
	dup := me.NewHashWriter()
	content, err := SavingCopy(dup, input, _BUFSIZE)
	if err != nil {
		log.Fatal(err)
	}
	err = dup.Close()
	if err != nil {
		log.Fatal(err)
	}
	return dup.hasher.Sum(), content
}
<commit_msg>ContentCache.DestructiveSavePath: only rename the file if we don't have it yet.<commit_after>package termite

import (
	"bytes"
	"os"
	"fmt"
	"crypto"
	"hash"
	"path/filepath"
	"log"
	"io"
	"io/ioutil"
	"sync"
)

// Content based addressing cache.
//
// TODO - a successful GetAttr() will often be followed by a read.  we
// should have a small LRU cache for the content so we can serve the
// contents from memory.
type ContentCache struct {
	dir string

	hashPathMapMutex sync.Mutex
	hashPathMap      map[string]string
}

func NewContentCache(d string) *ContentCache {
	if fi, _ := os.Lstat(d); fi == nil {
		err := os.MkdirAll(d, 0700)
		if err != nil {
			panic(err)
		}
	}

	return &ContentCache{
		dir:         d,
		hashPathMap: make(map[string]string),
	}
}

func HashPath(dir string, md5 []byte) string {
	s := fmt.Sprintf("%x", md5)
	prefix := s[:2]
	name := s[2:]
	dst := filepath.Join(dir, prefix, name)
	prefixDir, _ := filepath.Split(dst)
	if err := os.MkdirAll(prefixDir, 0700); err != nil {
		log.Fatal("MkdirAll error:", err)
	}
	return dst
}

func (me *ContentCache) localPath(hash []byte) string {
	me.hashPathMapMutex.Lock()
	defer me.hashPathMapMutex.Unlock()

	return me.hashPathMap[string(hash)]
}

func (me *ContentCache) HasHash(hash []byte) bool {
	p := me.localPath(hash)
	if p != "" {
		return true
	}

	p = HashPath(me.dir, hash)
	_, err := os.Lstat(p)
	return err == nil
}

func (me *ContentCache) Path(hash []byte) string {
	p := me.localPath(hash)
	if p != "" {
		return p
	}
	return HashPath(me.dir, hash)
}

func (me *ContentCache) NewHashWriter() *HashWriter {
	return NewHashWriter(me.dir, crypto.MD5)
}

type HashWriter struct {
	hasher hash.Hash
	dest   *os.File
	hash   []byte
}

func NewHashWriter(dir string, hashfunc crypto.Hash) *HashWriter {
	me := &HashWriter{}
	tmp, err := ioutil.TempFile(dir, ".md5temp")
	if err != nil {
		panic(err)
		log.Fatal(err)
	}

	me.dest = tmp
	me.hasher = hashfunc.New()
	return me
}

func (me *HashWriter) Write(p []byte) (n int, err os.Error) {
	n, err = me.dest.Write(p)
	me.hasher.Write(p[:n])
	return n, err
}

func (me *HashWriter) Close() os.Error {
	err := me.dest.Close()

	if err != nil {
		return err
	}
	src := me.dest.Name()
	dir, _ := filepath.Split(src)
	sum := me.hasher.Sum()
	sumpath := HashPath(dir, sum)

	log.Printf("saving hash %x\n", sum)
	err = os.Rename(src, sumpath)
	if err != nil {
		if fi, _ := os.Lstat(sumpath); fi == nil {
			log.Println("already have", sumpath)
			os.Remove(src)
		}
	}
	return err
}

const _BUFSIZE = 32 * 1024

func (me *ContentCache) DestructiveSavePath(path string) (md5 []byte, content []byte) {
	f, err := os.Open(path)
	if err != nil {
		return nil, nil
	}
	h := crypto.MD5.New()
	content, err = SavingCopy(h, f, _BUFSIZE)
	if err != nil {
		log.Fatal("DestructiveSavePath:", err)
	}

	s := h.Sum()
	if me.HasHash(s) {
		os.Remove(path)
		return s, nil
	}

	p := me.Path(s)
	err = os.Rename(path, p)
	if err != nil {
		if fi, _ := os.Lstat(p); fi != nil {
			os.Remove(p)
			return s, content
		}
		log.Fatal("DestructiveSavePath:", err)
	}
	return s, content
}

func (me *ContentCache) SavePath(path string) (md5 []byte, content []byte) {
	f, err := os.Open(path)
	if err != nil {
		log.Fatal(err)
	}
	defer f.Close()

	return me.SaveStream(f)
}

func (me *ContentCache) SaveImmutablePath(path string) (md5 []byte, content []byte) {
	hasher := crypto.MD5.New()

	f, err := os.Open(path)
	if err != nil {
		log.Fatal(err)
	}
	defer f.Close()
	content, err = SavingCopy(hasher, f, 32*1024)
	if err != nil && err != os.EOF {
		log.Fatal(err)
	}

	md5 = hasher.Sum()
	me.hashPathMapMutex.Lock()
	defer me.hashPathMapMutex.Unlock()
	me.hashPathMap[string(md5)] = path

	log.Printf("hashed %s to %x", path, md5)
	return md5, content
}

func (me *ContentCache) Save(content []byte) (md5 []byte) {
	buf := bytes.NewBuffer(content)
	md5, _ = me.SaveStream(buf)
	return md5
}

func (me *ContentCache) SaveStream(input io.Reader) (md5 []byte, content []byte) {
	dup := me.NewHashWriter()
	content, err := SavingCopy(dup, input, _BUFSIZE)
	if err != nil {
		log.Fatal(err)
	}
	err = dup.Close()
	if err != nil {
		log.Fatal(err)
	}
	return dup.hasher.Sum(), content
}
<|endoftext|>


<commit_before>package admin

import (
	"fmt"
	"log"
	"net/http"
	"path"
	"reflect"
	"regexp"
	"strings"
	"time"

	"github.com/qor/qor"
	"github.com/qor/qor/resource"
	"github.com/qor/qor/roles"
)

type (
	handle func(c *Context)

	handler struct {
		Path   *regexp.Regexp
		Handle handle
	}
)

type Router struct {
	Prefix      string
	routers     map[string][]handler
	middlewares []*Middleware
}

func newRouter() *Router {
	return &Router{routers: map[string][]handler{
		"GET":    []handler{},
		"PUT":    []handler{},
		"POST":   []handler{},
		"DELETE": []handler{},
	}}
}

type Middleware struct {
	Handler func(*Context, *Middleware)
	next    *Middleware
}

func (middleware Middleware) Next(context *Context) {
	if next := middleware.next; next != nil {
		next.Handler(context, next)
	}
}

func (r *Router) Use(handler func(*Context, *Middleware)) {
	r.middlewares = append(r.middlewares, &Middleware{Handler: handler})
}

func (r *Router) Get(path string, handle handle) {
	r.routers["GET"] = append(r.routers["GET"], handler{Path: regexp.MustCompile(path), Handle: handle})
}

func (r *Router) Post(path string, handle handle) {
	r.routers["POST"] = append(r.routers["POST"], handler{Path: regexp.MustCompile(path), Handle: handle})
}

func (r *Router) Put(path string, handle handle) {
	r.routers["PUT"] = append(r.routers["PUT"], handler{Path: regexp.MustCompile(path), Handle: handle})
}

func (r *Router) Delete(path string, handle handle) {
	r.routers["DELETE"] = append(r.routers["DELETE"], handler{Path: regexp.MustCompile(path), Handle: handle})
}

func (admin *Admin) MountTo(prefix string, mux *http.ServeMux) {
	prefix = "/" + strings.Trim(prefix, "/")
	router := admin.router
	router.Prefix = prefix

	admin.compile()

	controller := &controller{admin}
	router.Get("^/?$", controller.Dashboard)
	router.Get("^/!search$", controller.SearchCenter)

	var registerToRouter = func(res *Resource) {
		// New
		router.Get(fmt.Sprintf("/%v/new", res.ToParam()), controller.New)

		// Create
		router.Post(fmt.Sprintf("/%v", res.ToParam()), controller.Create)

		// Show
		router.Get(fmt.Sprintf("/%v/:id", res.ToParam()), controller.Show)

		// Edit
		router.Get(fmt.Sprintf("/%v/:id/edit", res.ToParam()), controller.Edit)

		// Update
		router.Put(fmt.Sprintf("/%v/:id", res.ToParam()), controller.Update)
		router.Post(fmt.Sprintf("/%v/:id", res.ToParam()), controller.Update)

		// Delete
		router.Delete(fmt.Sprintf("/%v/:id", res.ToParam()), controller.Delete)

		// Index
		router.Get(fmt.Sprintf("/%v", res.ToParam()), controller.Index)

		// Action
		router.Post(fmt.Sprintf("/%v/action/[^/]+(\\?.*)?$", res.ToParam()), controller.Action)

		// Sub Resources
		for _, meta := range res.ConvertSectionToMetas(res.ShowAttrs()) {
			if meta.FieldStruct != nil && meta.FieldStruct.Relationship != nil {
				subParam := meta.Resource.ToParam()
				router.Get(fmt.Sprintf("/%v/:id/%v", res.ToParam(), subParam), controller.Index)
				router.Get(fmt.Sprintf("/%v/:id/%v/:id", res.ToParam(), subParam), controller.Show)
			}
		}

		for _, meta := range res.ConvertSectionToMetas(res.EditAttrs()) {
			if meta.FieldStruct != nil && meta.FieldStruct.Relationship != nil {
				subParam := meta.Resource.ToParam()
				router.Post(fmt.Sprintf("/%v/:id/%v/:id", res.ToParam(), subParam), controller.Update)
				router.Put(fmt.Sprintf("/%v/:id/%v/:id", res.ToParam(), subParam), controller.Update)
				router.Delete(fmt.Sprintf("/%v/:id/%v/:id", res.ToParam(), subParam), controller.Delete)
			}
		}

		for _, meta := range res.ConvertSectionToMetas(res.NewAttrs()) {
			if meta.FieldStruct != nil && meta.FieldStruct.Relationship != nil {
				subParam := meta.Resource.ToParam()
				router.Post(fmt.Sprintf("/%v/:id/%v", res.ToParam(), subParam), controller.Create)

				router.Get(fmt.Sprintf("/%v/new", res.ToParam()), controller.New)
			}
		}
	}

	for _, res := range admin.resources {
		if !res.Config.Invisible {
			registerToRouter(res)
		}
	}

	mux.Handle(prefix, admin)     // /:prefix
	mux.Handle(prefix+"/", admin) // /:prefix/:xxx
}

func (res *Resource) configure() {
	modelType := res.GetAdmin().Config.DB.NewScope(res.Value).GetModelStruct().ModelType
	for i := 0; i < modelType.NumField(); i++ {
		if fieldStruct := modelType.Field(i); fieldStruct.Anonymous {
			if injector, ok := reflect.New(fieldStruct.Type).Interface().(resource.ConfigureResourceInterface); ok {
				injector.ConfigureQorResource(res)
			}
		}
	}

	if injector, ok := res.Value.(resource.ConfigureResourceInterface); ok {
		injector.ConfigureQorResource(res)
	}
}

func (admin *Admin) compile() {
	admin.generateMenuLinks()

	router := admin.GetRouter()

	for _, res := range admin.resources {
		res.configure()
	}

	router.Use(func(context *Context, middleware *Middleware) {
		w := context.Writer
		req := context.Request

		// 128 MB
		req.ParseMultipartForm(32 << 22)
		if len(req.Form["_method"]) > 0 {
			req.Method = strings.ToUpper(req.Form["_method"][0])
		}

		var pathMatch = regexp.MustCompile(path.Join(router.Prefix, `(\w+)(?:/(\w+))?[^/]*`))
		var matches = pathMatch.FindStringSubmatch(req.URL.Path)
		if len(matches) > 1 {
			context.setResource(admin.GetResource(matches[1]))
			if len(matches) > 2 {
				context.ResourceID = matches[2]
			}
		}

		handlers := router.routers[strings.ToUpper(req.Method)]
		relativePath := strings.TrimPrefix(req.URL.Path, router.Prefix)
		for _, handler := range handlers {
			if handler.Path.MatchString(relativePath) {
				handler.Handle(context)
				return
			}
		}
		http.NotFound(w, req)
	})

	for index, middleware := range router.middlewares {
		var next *Middleware
		if len(router.middlewares) > index+1 {
			next = router.middlewares[index+1]
		}
		middleware.next = next
	}
}

func (admin *Admin) NewContext(w http.ResponseWriter, r *http.Request) *Context {
	context := Context{Context: &qor.Context{Config: admin.Config, Request: r, Writer: w}, Admin: admin}

	return &context
}

func (admin *Admin) ServeHTTP(w http.ResponseWriter, req *http.Request) {
	var relativePath = strings.TrimPrefix(req.URL.Path, admin.router.Prefix)
	var context = admin.NewContext(w, req)

	if regexp.MustCompile("^/assets/.*$").MatchString(relativePath) {
		(&controller{admin}).Asset(context)
		return
	}

	defer func() func() {
		begin := time.Now()
		log.Printf("Start [%s] %s\n", req.Method, req.RequestURI)

		return func() {
			log.Printf("Finish [%s] %s Took %.2fms\n", req.Method, req.RequestURI, time.Now().Sub(begin).Seconds()*1000)
		}
	}()()

	var currentUser qor.CurrentUser
	if admin.auth != nil {
		if currentUser = admin.auth.GetCurrentUser(context); currentUser == nil {
			http.Redirect(w, req, admin.auth.LoginURL(context), http.StatusSeeOther)
			return
		} else {
			context.CurrentUser = currentUser
			context.SetDB(context.GetDB().Set("qor:current_user", context.CurrentUser))
		}
	}
	context.Roles = roles.MatchedRoles(req, currentUser)

	firstStack := admin.router.middlewares[0]
	firstStack.Handler(context, firstStack)
}
<commit_msg>Register route with resource<commit_after>package admin

import (
	"log"
	"net/http"
	"path"
	"reflect"
	"regexp"
	"strings"
	"time"

	"github.com/qor/qor"
	"github.com/qor/qor/resource"
	"github.com/qor/qor/roles"
)

type (
	handle func(c *Context)

	handler struct {
		Path   *regexp.Regexp
		Handle handle
	}
)

type Router struct {
	Prefix      string
	routers     map[string][]handler
	middlewares []*Middleware
}

func newRouter() *Router {
	return &Router{routers: map[string][]handler{
		"GET":    []handler{},
		"PUT":    []handler{},
		"POST":   []handler{},
		"DELETE": []handler{},
	}}
}

type Middleware struct {
	Handler func(*Context, *Middleware)
	next    *Middleware
}

func (middleware Middleware) Next(context *Context) {
	if next := middleware.next; next != nil {
		next.Handler(context, next)
	}
}

func (r *Router) Use(handler func(*Context, *Middleware)) {
	r.middlewares = append(r.middlewares, &Middleware{Handler: handler})
}

func (r *Router) Get(path string, handle handle) {
	r.routers["GET"] = append(r.routers["GET"], handler{Path: regexp.MustCompile(path), Handle: handle})
}

func (r *Router) Post(path string, handle handle) {
	r.routers["POST"] = append(r.routers["POST"], handler{Path: regexp.MustCompile(path), Handle: handle})
}

func (r *Router) Put(path string, handle handle) {
	r.routers["PUT"] = append(r.routers["PUT"], handler{Path: regexp.MustCompile(path), Handle: handle})
}

func (r *Router) Delete(path string, handle handle) {
	r.routers["DELETE"] = append(r.routers["DELETE"], handler{Path: regexp.MustCompile(path), Handle: handle})
}

func (admin *Admin) MountTo(prefix string, mux *http.ServeMux) {
	prefix = "/" + strings.Trim(prefix, "/")
	router := admin.router
	router.Prefix = prefix

	admin.compile()

	controller := &controller{admin}
	router.Get("^/?$", controller.Dashboard)
	router.Get("^/!search$", controller.SearchCenter)

	var registerResourceToRouter func(*Resource, ...string)
	registerResourceToRouter = func(res *Resource, modes ...string) {
		var prefix = func(r *Resource) string {
			p := r.ToParam()
			for r.base != nil {
				p = path.Join(r.base.ToParam(), ":id", p)
				r = r.base
			}
			return "/" + strings.Trim(p, "/")
		}(res)

		for _, mode := range modes {
			if mode == "create" {
				// New
				router.Get(path.Join(prefix, "new"), controller.New)

				// Create
				router.Post(prefix, controller.Create)
			}

			if mode == "read" {
				// Index
				router.Get(prefix, controller.Index)

				// Show
				router.Get(path.Join(prefix, ":id"), controller.Show)
			}

			if mode == "update" {
				// Edit
				router.Get(path.Join(prefix, ":id", "edit"), controller.Edit)

				// Update
				router.Put(path.Join(prefix, ":id"), controller.Update)
				router.Post(path.Join(prefix, ":id"), controller.Update)

				// Action
				// router.Post(fmt.Sprintf("/%v/action/[^/]+(\\?.*)?$", res.ToParam()), controller.Action)
			}

			if mode == "delete" {
				// Delete
				router.Delete(path.Join(prefix, ":id"), controller.Delete)
			}
		}

		// Sub Resources
		for _, meta := range res.ConvertSectionToMetas(res.NewAttrs()) {
			if meta.FieldStruct != nil && meta.FieldStruct.Relationship != nil {
				registerResourceToRouter(meta.Resource, "create")
			}
		}

		for _, meta := range res.ConvertSectionToMetas(res.ShowAttrs()) {
			if meta.FieldStruct != nil && meta.FieldStruct.Relationship != nil {
				registerResourceToRouter(meta.Resource, "read")
			}
		}

		for _, meta := range res.ConvertSectionToMetas(res.EditAttrs()) {
			if meta.FieldStruct != nil && meta.FieldStruct.Relationship != nil {
				registerResourceToRouter(meta.Resource, "update", "delete")
			}
		}
	}

	for _, res := range admin.resources {
		if !res.Config.Invisible {
			registerResourceToRouter(res, "create", "read", "update", "delete")
		}
	}

	mux.Handle(prefix, admin)     // /:prefix
	mux.Handle(prefix+"/", admin) // /:prefix/:xxx
}

func (res *Resource) configure() {
	modelType := res.GetAdmin().Config.DB.NewScope(res.Value).GetModelStruct().ModelType
	for i := 0; i < modelType.NumField(); i++ {
		if fieldStruct := modelType.Field(i); fieldStruct.Anonymous {
			if injector, ok := reflect.New(fieldStruct.Type).Interface().(resource.ConfigureResourceInterface); ok {
				injector.ConfigureQorResource(res)
			}
		}
	}

	if injector, ok := res.Value.(resource.ConfigureResourceInterface); ok {
		injector.ConfigureQorResource(res)
	}
}

func (admin *Admin) compile() {
	admin.generateMenuLinks()

	router := admin.GetRouter()

	for _, res := range admin.resources {
		res.configure()
	}

	router.Use(func(context *Context, middleware *Middleware) {
		w := context.Writer
		req := context.Request

		// 128 MB
		req.ParseMultipartForm(32 << 22)
		if len(req.Form["_method"]) > 0 {
			req.Method = strings.ToUpper(req.Form["_method"][0])
		}

		var pathMatch = regexp.MustCompile(path.Join(router.Prefix, `(\w+)(?:/(\w+))?[^/]*`))
		var matches = pathMatch.FindStringSubmatch(req.URL.Path)
		if len(matches) > 1 {
			context.setResource(admin.GetResource(matches[1]))
			if len(matches) > 2 {
				context.ResourceID = matches[2]
			}
		}

		handlers := router.routers[strings.ToUpper(req.Method)]
		relativePath := strings.TrimPrefix(req.URL.Path, router.Prefix)
		for _, handler := range handlers {
			if handler.Path.MatchString(relativePath) {
				handler.Handle(context)
				return
			}
		}
		http.NotFound(w, req)
	})

	for index, middleware := range router.middlewares {
		var next *Middleware
		if len(router.middlewares) > index+1 {
			next = router.middlewares[index+1]
		}
		middleware.next = next
	}
}

func (admin *Admin) NewContext(w http.ResponseWriter, r *http.Request) *Context {
	context := Context{Context: &qor.Context{Config: admin.Config, Request: r, Writer: w}, Admin: admin}

	return &context
}

func (admin *Admin) ServeHTTP(w http.ResponseWriter, req *http.Request) {
	var relativePath = strings.TrimPrefix(req.URL.Path, admin.router.Prefix)
	var context = admin.NewContext(w, req)

	if regexp.MustCompile("^/assets/.*$").MatchString(relativePath) {
		(&controller{admin}).Asset(context)
		return
	}

	defer func() func() {
		begin := time.Now()
		log.Printf("Start [%s] %s\n", req.Method, req.RequestURI)

		return func() {
			log.Printf("Finish [%s] %s Took %.2fms\n", req.Method, req.RequestURI, time.Now().Sub(begin).Seconds()*1000)
		}
	}()()

	var currentUser qor.CurrentUser
	if admin.auth != nil {
		if currentUser = admin.auth.GetCurrentUser(context); currentUser == nil {
			http.Redirect(w, req, admin.auth.LoginURL(context), http.StatusSeeOther)
			return
		} else {
			context.CurrentUser = currentUser
			context.SetDB(context.GetDB().Set("qor:current_user", context.CurrentUser))
		}
	}
	context.Roles = roles.MatchedRoles(req, currentUser)

	firstStack := admin.router.middlewares[0]
	firstStack.Handler(context, firstStack)
}
<|endoftext|>


<commit_before>package renderer

import (
	"bytes"
	"html/template"
	"testing"
	"time"

	"github.com/stretchr/testify/assert"
)

func TestDateFormat(t *testing.T) {
	for i, this := range []struct {
		layout string
		value  interface{}
		expect interface{}
	}{
		{"Monday, Jan 2, 2006", "2015-01-21", "Wednesday, Jan 21, 2015"},
		{"Monday, Jan 2, 2006", time.Date(2015, time.January, 21, 0, 0, 0, 0, time.UTC), "Wednesday, Jan 21, 2015"},
		{"This isn't a date layout string", "2015-01-21", "This isn't a date layout string"},
		// The following test case gives either "Tuesday, Jan 20, 2015" or "Monday, Jan 19, 2015" depending on the local time zone
		{"Monday, Jan 2, 2006", 1421733600, time.Unix(1421733600, 0).Format("Monday, Jan 2, 2006")},
		{"Monday, Jan 2, 2006", 1421733600.123, false},
		{time.RFC3339, time.Date(2016, time.March, 3, 4, 5, 0, 0, time.UTC), "2016-03-03T04:05:00Z"},
		{time.RFC1123, time.Date(2016, time.March, 3, 4, 5, 0, 0, time.UTC), "Thu, 03 Mar 2016 04:05:00 UTC"},
		{time.RFC3339, "Thu, 03 Mar 2016 04:05:00 UTC", "2016-03-03T04:05:00Z"},
		{time.RFC1123, "2016-03-03T04:05:00Z", "Thu, 03 Mar 2016 04:05:00 UTC"},
	} {
		result, err := dateFormat(this.layout, this.value)
		if b, ok := this.expect.(bool); ok && !b {
			assert.Error(t, err, "[%d] DateFormat didn't return an expected error", i)
		} else {
			if assert.NoError(t, err, "[%d] DateFormat failed", i) {
				assert.Equal(t, this.expect, result, "[%d] DateFormat failed", i)
			}
		}
	}
}

func TestDictionary(t *testing.T) {
	for i, this := range []struct {
		v1            []interface{}
		expecterr     bool
		expectedValue map[string]interface{}
	}{
		{[]interface{}{"a", "b"}, false, map[string]interface{}{"a": "b"}},
		{[]interface{}{5, "b"}, true, nil},
		{[]interface{}{"a", 12, "b", []int{4}}, false, map[string]interface{}{"a": 12, "b": []int{4}}},
		{[]interface{}{"a", "b", "c"}, true, nil},
	} {
		r, err := dictionary(this.v1...)

		assert.False(t, (this.expecterr && err == nil) || (!this.expecterr && err != nil), "[%d] got an unexpected error", i)
		if !this.expecterr {
			assert.Equal(t, this.expectedValue, r, "[%d] got an unexpected value", i)
		}
	}
}

func TestSafeHTML(t *testing.T) {
	for i, this := range []struct {
		str                 string
		tmplStr             string
		expectWithoutEscape string
		expectWithEscape    string
	}{
		{`<div></div>`, `{{ . }}`, `<div></div>`, `<div></div>`},
	} {
		tmpl, err := template.New("test").Parse(this.tmplStr)
		assert.NoError(t, err, "[%d| unable to create new html template %q", i, this.tmplStr)

		buf := new(bytes.Buffer)
		err = tmpl.Execute(buf, this.str)
		assert.NoError(t, err, "[%d] execute template with a raw string value returns unexpected error", i)
		assert.Equal(t, this.expectWithoutEscape, buf.String(), "[%d] execute template with a raw string value", i)

		buf.Reset()
		v, err := safeHTML(this.str)
		assert.NoError(t, err, "[%d] unexpected error in safeHTML", i)

		err = tmpl.Execute(buf, v)
		assert.NoError(t, err, "[%d] execute template with an escaped string value by safeHTML returns unexpected error", i)
		assert.Equal(t, this.expectWithEscape, buf.String(), "[%d] execute template with an escaped string value by safeHTML", i)
	}
}

func TestSafeURL(t *testing.T) {
	for i, this := range []struct {
		str                 string
		tmplStr             string
		expectWithoutEscape string
		expectWithEscape    string
	}{
		{`irc://irc.freenode.net/#golang`, `<a href="{{ . }}">IRC</a>`, `<a href="#ZgotmplZ">IRC</a>`, `<a href="irc://irc.freenode.net/#golang">IRC</a>`},
	} {
		tmpl, err := template.New("test").Parse(this.tmplStr)
		assert.NoError(t, err, "[%d] unable to create new html template %q", i, this.tmplStr)

		buf := new(bytes.Buffer)
		err = tmpl.Execute(buf, this.str)
		if assert.NoError(t, err, "[%d] execute template with a raw string value returns unexpected error", i) {
			assert.Equal(t, this.expectWithoutEscape, buf.String(), "[%d] execute template with a raw string value", i)
		}

		buf.Reset()
		v, err := safeURL(this.str)
		assert.NoError(t, err, "[%d] unexpected error in safeURL", i)

		err = tmpl.Execute(buf, v)
		if assert.NoError(t, err, "[%d] execute template with an escaped string value by safeURL", i) {
			assert.Equal(t, this.expectWithEscape, buf.String(), "[%d] execute template with an escaped string value by safeURL", i)
		}
	}
}
<commit_msg>adding nil test for dateformat<commit_after>package renderer

import (
	"bytes"
	"html/template"
	"testing"
	"time"

	"github.com/stretchr/testify/assert"
)

func TestDateFormat(t *testing.T) {
	for i, this := range []struct {
		layout string
		value  interface{}
		expect interface{}
	}{
		{"Monday, Jan 2, 2006", nil, time.Now().Format("Monday, Jan 2, 2006")},
		{"Monday, Jan 2, 2006", "2015-01-21", "Wednesday, Jan 21, 2015"},
		{"Monday, Jan 2, 2006", time.Date(2015, time.January, 21, 0, 0, 0, 0, time.UTC), "Wednesday, Jan 21, 2015"},
		{"This isn't a date layout string", "2015-01-21", "This isn't a date layout string"},
		// The following test case gives either "Tuesday, Jan 20, 2015" or "Monday, Jan 19, 2015" depending on the local time zone
		{"Monday, Jan 2, 2006", 1421733600, time.Unix(1421733600, 0).Format("Monday, Jan 2, 2006")},
		{"Monday, Jan 2, 2006", 1421733600.123, false},
		{time.RFC3339, time.Date(2016, time.March, 3, 4, 5, 0, 0, time.UTC), "2016-03-03T04:05:00Z"},
		{time.RFC1123, time.Date(2016, time.March, 3, 4, 5, 0, 0, time.UTC), "Thu, 03 Mar 2016 04:05:00 UTC"},
		{time.RFC3339, "Thu, 03 Mar 2016 04:05:00 UTC", "2016-03-03T04:05:00Z"},
		{time.RFC1123, "2016-03-03T04:05:00Z", "Thu, 03 Mar 2016 04:05:00 UTC"},
	} {
		result, err := dateFormat(this.layout, this.value)
		if b, ok := this.expect.(bool); ok && !b {
			assert.Error(t, err, "[%d] DateFormat didn't return an expected error", i)
		} else {
			if assert.NoError(t, err, "[%d] DateFormat failed", i) {
				assert.Equal(t, this.expect, result, "[%d] DateFormat failed", i)
			}
		}
	}
}

func TestDictionary(t *testing.T) {
	for i, this := range []struct {
		v1            []interface{}
		expecterr     bool
		expectedValue map[string]interface{}
	}{
		{[]interface{}{"a", "b"}, false, map[string]interface{}{"a": "b"}},
		{[]interface{}{5, "b"}, true, nil},
		{[]interface{}{"a", 12, "b", []int{4}}, false, map[string]interface{}{"a": 12, "b": []int{4}}},
		{[]interface{}{"a", "b", "c"}, true, nil},
	} {
		r, err := dictionary(this.v1...)

		assert.False(t, (this.expecterr && err == nil) || (!this.expecterr && err != nil), "[%d] got an unexpected error", i)
		if !this.expecterr {
			assert.Equal(t, this.expectedValue, r, "[%d] got an unexpected value", i)
		}
	}
}

func TestSafeHTML(t *testing.T) {
	for i, this := range []struct {
		str                 string
		tmplStr             string
		expectWithoutEscape string
		expectWithEscape    string
	}{
		{`<div></div>`, `{{ . }}`, `<div></div>`, `<div></div>`},
	} {
		tmpl, err := template.New("test").Parse(this.tmplStr)
		assert.NoError(t, err, "[%d| unable to create new html template %q", i, this.tmplStr)

		buf := new(bytes.Buffer)
		err = tmpl.Execute(buf, this.str)
		assert.NoError(t, err, "[%d] execute template with a raw string value returns unexpected error", i)
		assert.Equal(t, this.expectWithoutEscape, buf.String(), "[%d] execute template with a raw string value", i)

		buf.Reset()
		v, err := safeHTML(this.str)
		assert.NoError(t, err, "[%d] unexpected error in safeHTML", i)

		err = tmpl.Execute(buf, v)
		assert.NoError(t, err, "[%d] execute template with an escaped string value by safeHTML returns unexpected error", i)
		assert.Equal(t, this.expectWithEscape, buf.String(), "[%d] execute template with an escaped string value by safeHTML", i)
	}
}

func TestSafeURL(t *testing.T) {
	for i, this := range []struct {
		str                 string
		tmplStr             string
		expectWithoutEscape string
		expectWithEscape    string
	}{
		{`irc://irc.freenode.net/#golang`, `<a href="{{ . }}">IRC</a>`, `<a href="#ZgotmplZ">IRC</a>`, `<a href="irc://irc.freenode.net/#golang">IRC</a>`},
	} {
		tmpl, err := template.New("test").Parse(this.tmplStr)
		assert.NoError(t, err, "[%d] unable to create new html template %q", i, this.tmplStr)

		buf := new(bytes.Buffer)
		err = tmpl.Execute(buf, this.str)
		if assert.NoError(t, err, "[%d] execute template with a raw string value returns unexpected error", i) {
			assert.Equal(t, this.expectWithoutEscape, buf.String(), "[%d] execute template with a raw string value", i)
		}

		buf.Reset()
		v, err := safeURL(this.str)
		assert.NoError(t, err, "[%d] unexpected error in safeURL", i)

		err = tmpl.Execute(buf, v)
		if assert.NoError(t, err, "[%d] execute template with an escaped string value by safeURL", i) {
			assert.Equal(t, this.expectWithEscape, buf.String(), "[%d] execute template with an escaped string value by safeURL", i)
		}
	}
}
<|endoftext|>


<commit_before>package channels

type MotionDevice interface {
}

type MotionChannel struct {
	baseChannel
	device MotionDevice
}

func NewMotionChannel(device MotionDevice) *MotionChannel {
	return &MotionChannel{baseChannel{
		protocol: "motion",
	}, device}
}

func (c *MotionChannel) SendMotion() error {
	return c.SendEvent("state", true)
}
<commit_msg>Clean up motion channel<commit_after>package channels

type MotionChannel struct {
	baseChannel
}

func NewMotionChannel() *MotionChannel {
	return &MotionChannel{baseChannel{
		protocol: "motion",
	}}
}

func (c *MotionChannel) SendMotion() error {
	return c.SendEvent("state", true)
}
<|endoftext|>


<commit_before>package chapter1

import "fmt"

func Range() {
	numbers:= [5]int{1, 2, 3, 4 ,5}

	for index, value := range numbers {
		fmt.Println("index:", index, "value:", value)
	}
}<commit_msg>updated more detail<commit_after>package chapter1

import "fmt"

// ranges can bu used to iterate over arrays, maps, slices and channels.
// we will discuss channels at a later chapter.
func Range() {
	numbers:= [5]int{1, 2, 3, 4 ,5}

	// simple use of a range over our numbers
	for index, value := range numbers {
		fmt.Println("index:", index, "value:", value)
	}
}<|endoftext|>


<commit_before>package charmap

import (
	"strconv"
	"strings"
)

// Private types for rune and string slices
type unicodeSequence []string
type runeSequence []rune

type sequenceIndex interface {
	index(char interface{}) int
}

// Private map to hold all sequences
type charMap map[string]sequenceIndex

type UnknownCharError struct {
	char    interface{}
	lang    string
	message string
}

func (e *UnknownCharError) Error() string {
	var returnString string

	switch e.char.(type) {
	case rune:
		returnString = strconv.QuoteRune(e.char.(rune))
	case string:
		returnString = e.char.(string)
	}

	if len(e.lang) == 0 {
		return returnString + " : " + e.message
	}

	return returnString + " " + e.message + " " + e.lang
}

// Languagewise unicode ranges
var langBases = map[string]int{
	"en_US": 0,
	"en_IN": 0,
	"hi_IN": '\u0901',
	"bn_IN": '\u0981',
	"pa_IN": '\u0a01',
	"gu_IN": '\u0a81',
	"or_IN": '\u0b01',
	"ta_IN": '\u0b81',
	"te_IN": '\u0c01',
	"kn_IN": '\u0c81',
	"ml_IN": '\u0D01',
}

// Slices to hold unicode range for each languagges
var devaAlphabets = make(runeSequence, 80)
var bengAlphabets = make(runeSequence, 80)
var guruAlphabets = make(runeSequence, 80)
var gujrAlphabets = make(runeSequence, 80)
var oryaAlphabets = make(runeSequence, 80)
var tamlAlphabets = make(runeSequence, 80)
var teluAlphabets = make(runeSequence, 80)
var kndaAlphabets = make(runeSequence, 80)
var mlymAlphabets = make(runeSequence, 80)

var enUsAlphabets = runeSequence{'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'}

// Soundex values for English alphabet series
var soundexEnglish = runeSequence{'0', '1', '2', '3', '0', '1', '2', '0', '0', '2', '2', '4', '5', '5', '0', '1', '2', '6', '2', '3', '0', '1', '0', '2', '0', '2'}

// Soundex values for Indian language unicode series.
var soundexIndic = runeSequence{'0', 'N', '0', '0', 'A', 'A', 'B', 'B', 'C', 'C', 'P', 'Q', '0', 'D', 'D', 'D', 'E', 'E', 'E', 'E', 'F', 'F', 'F', 'F', 'G', 'H', 'H', 'H', 'H', 'G', 'I', 'I', 'I', 'I', 'J', 'K', 'K', 'K', 'K', 'L', 'L', 'M', 'M', 'M', 'M', 'N', 'O', 'P', 'P', 'Q', 'Q', 'Q', 'R', 'S', 'S', 'S', 'T', '0', '0', '0', '0', 'A', 'B', 'B', 'C', 'C', 'P', 'P', 'E', 'D', 'D', 'D', 'D', 'E', 'E', 'E', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', 'E', '0', '0', '0', '0', '0', '0', '0', '0', 'P', 'Q', 'Q', 'Q', '0', '0', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', 'J', 'J', 'Q', 'P', 'P', 'F'}

// ISO15919 series specific to Indian languages
var iso15919IndicSeries = unicodeSequence{`m̐`, `ṁ`, `ḥ`, ``, `a`, `ā`, `i`, `ī`, `u`, `ū`, `ṛ`, `ḷ`, `ê`, `e`, `ē`, `ai`, `ô`, `o`, `ō`, `au`, `ka`, `kha`, `ga`, `gha`, `ṅa`, `ca`, `cha`, `ja`, `jha`, `ña`, `ṭa`, `ṭha`, `ḍa`, `ḍha`, `ṇa`, `ta`, `tha`, `da`, `dha`, `na`, `ṉa`, `pa`, `pha`, `ba`, `bha`, `ma`, `ya`, `ra`, `ṟa`, `la`, `ḷa`, `ḻa`, `va`, `śa`, `ṣa`, `sa`, `ha`, ``, ``, ``, `'`, `ā`, `i`, `ī`, `u`, `ū`, `ṛ`, `ṝ`, `ê`, `e`, `ē`, `ai`, `ô`, `o`, `ō`, `au`, ``, ``, ``, `oṃ`, ``, ``, ``, ``, ``, ``, ``, `qa`, `ḵẖa`, `ġ`, `za`, `ṛa`, `ṛha`, `fa`, `ẏa`, `ṝ`, `ḹ`, `ḷ`, `ḹ`, `.`, `..`, `0`, `1`, `2`, `3`, `4`, `5`, `6`, `7`, `8`, `9`, `…`, ``, ``, ``, ``, ``, ``, ``}

// IPA series specific for Indian languages
var ipaIndicSeries = unicodeSequence{`m`, `m`, ``, ``, `ə`, `aː`, `i`, `iː`, `u`, `uː`, `r̩`, `l̩`, `æ`, `e`, `eː`, `ɛː`, `ɔ`, `o`, `oː`, `ow`, `kə`, `kʰə`, `gə`, `gʱə`, `ŋə`, `ʧə`, `ʧʰə`, `ʤə`, `ʤʱə`, `ɲə`, `ʈə`, `ʈʰə`, `ɖə`, `ɖʱə`, `ɳə`, `t̪ə`, `t̪ʰə`, `d̪ə`, `d̪ʱə`, `n̪ə`, `nə`, `pə`, `pʰə`, `bə`, `bʱə`, `mə`, `jə`, `ɾə`, `rə`, `lə`, `ɭə`, `ɻə`, `ʋə`, `ɕə`, `ʂə`, `sə`, `ɦə`, ``, ``, ``, `ഽ`, `aː`, `i`, `iː`, `u`, `uː`, `r̩`, `l̩`, `e`, `eː`, `ɛː`, `ɔ`, `o`, `oː`, `ow`, ``, ``, ``, ``, ``, ``, ``, ``, ``, ``, `ow`, ``, ``, ``, ``, ``, ``, ``, ``, `r̩ː`, `l̩ː`, ``, ``, ``, ``, `0`, `1`, `2`, `3`, `4`, `5`, `6`, `7`, `8`, `9`, `൰`, ``, ``, ``, ``, ``, ``, ``, ``, ``, ``, ``, ``, ``, ``, ``}

// Map to hold rune sequence of each languages
var langMap = charMap{
	"hi_IN": devaAlphabets,
	"bn_IN": bengAlphabets,
	"pa_IN": guruAlphabets,
	"gu_IN": gujrAlphabets,
	"or_IN": oryaAlphabets,
	"ta_IN": tamlAlphabets,
	"te_IN": teluAlphabets,
	"kn_IN": kndaAlphabets,
	"ml_IN": mlymAlphabets,
}

func initializeUnicodeRange(slice runeSequence, begin int) {
	for i := 0; i < len(slice); i++ {
		slice[i] = rune(begin + i)
	}
}

func init() {
	for key, value := range langMap {
		initializeUnicodeRange(value.(runeSequence), langBases[key])
	}

	langMap["soundex_en"] = soundexEnglish
	langMap["soundex_in"] = soundexIndic
	langMap["ISO15919"] = iso15919IndicSeries
	langMap["IPA"] = ipaIndicSeries
	langMap["en_US"] = enUsAlphabets
}

func (r unicodeSequence) index(char interface{}) int {
	for i, value := range r {
		if value == char {
			return i
		}
	}

	return -1
}

func (r runeSequence) index(char interface{}) int {

	for i, value := range r {
		if value == char.(rune) {
			return i
		}
	}

	return -1
}

func LanguageOf(char interface{}) string {
	for lang, langRange := range langMap {
		if langRange.index(char) != -1 {
			return lang
		}
	}
	// Still not found then something wrong
	return "unknown"
}

func CharCompare(char1, char2 interface{}) bool {

	if char1 == char2 {
		return true
	}

	char1Index := langMap[LanguageOf(char1)].index(char1)
	char2Index := langMap[LanguageOf(char2)].index(char2)

	if char1Index == char2Index {
		return true
	}

	return false
}

func SoundexCode(char interface{}) (rune, error) {
	var lang string

	switch char.(type) {
	case string:
		char = strings.ToLower(char.(string))
	}

	if lang = LanguageOf(char); lang != "unknown" {
		if charIndex := langMap[lang].index(char); charIndex != -1 {
			var sequence runeSequence

			switch lang {
			case "en_US":
				sequence = langMap["soundex_en"].(runeSequence)
			default:
				sequence = langMap["soundex_in"].(runeSequence)
			}
			return sequence[charIndex], nil
		}
		return '0', &UnknownCharError{char, lang, "not found"}
	}
	return '0', &UnknownCharError{char, lang, "unknown language"}
}
<commit_msg>Added documentation for charmap module.<commit_after>/*
  Charmap package implements character map and functions

  This package implements character range slices for Indian languages
  and English. It also implements soundex codes for Indian languages
  and English. Soundex codes are accessed using function SoundexCode.

  It also  implements language detection and char compare function.

*/
package charmap

import (
	"strconv"
	"strings"
)

// Private types for rune and string slices
type unicodeSequence []string
type runeSequence []rune

type sequenceIndex interface {
	index(char interface{}) int
}

// Private map to hold all sequences
type charMap map[string]sequenceIndex

/*
  Custom Error structure for missing or unknown character
*/
type UnknownCharError struct {
	char    interface{}
	lang    string
	message string
}

func (e *UnknownCharError) Error() string {
	var returnString string

	switch e.char.(type) {
	case rune:
		returnString = strconv.QuoteRune(e.char.(rune))
	case string:
		returnString = e.char.(string)
	}

	if len(e.lang) == 0 {
		return returnString + " : " + e.message
	}

	return returnString + " " + e.message + " " + e.lang
}

// Languagewise unicode ranges
var langBases = map[string]int{
	"en_US": 0,
	"en_IN": 0,
	"hi_IN": '\u0901',
	"bn_IN": '\u0981',
	"pa_IN": '\u0a01',
	"gu_IN": '\u0a81',
	"or_IN": '\u0b01',
	"ta_IN": '\u0b81',
	"te_IN": '\u0c01',
	"kn_IN": '\u0c81',
	"ml_IN": '\u0D01',
}

// Slices to hold unicode range for each languagges
var devaAlphabets = make(runeSequence, 80)
var bengAlphabets = make(runeSequence, 80)
var guruAlphabets = make(runeSequence, 80)
var gujrAlphabets = make(runeSequence, 80)
var oryaAlphabets = make(runeSequence, 80)
var tamlAlphabets = make(runeSequence, 80)
var teluAlphabets = make(runeSequence, 80)
var kndaAlphabets = make(runeSequence, 80)
var mlymAlphabets = make(runeSequence, 80)

var enUsAlphabets = runeSequence{'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'}

// Soundex values for English alphabet series
var soundexEnglish = runeSequence{'0', '1', '2', '3', '0', '1', '2', '0', '0', '2', '2', '4', '5', '5', '0', '1', '2', '6', '2', '3', '0', '1', '0', '2', '0', '2'}

// Soundex values for Indian language unicode series.
var soundexIndic = runeSequence{'0', 'N', '0', '0', 'A', 'A', 'B', 'B', 'C', 'C', 'P', 'Q', '0', 'D', 'D', 'D', 'E', 'E', 'E', 'E', 'F', 'F', 'F', 'F', 'G', 'H', 'H', 'H', 'H', 'G', 'I', 'I', 'I', 'I', 'J', 'K', 'K', 'K', 'K', 'L', 'L', 'M', 'M', 'M', 'M', 'N', 'O', 'P', 'P', 'Q', 'Q', 'Q', 'R', 'S', 'S', 'S', 'T', '0', '0', '0', '0', 'A', 'B', 'B', 'C', 'C', 'P', 'P', 'E', 'D', 'D', 'D', 'D', 'E', 'E', 'E', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', 'E', '0', '0', '0', '0', '0', '0', '0', '0', 'P', 'Q', 'Q', 'Q', '0', '0', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', 'J', 'J', 'Q', 'P', 'P', 'F'}

// ISO15919 series specific to Indian languages
var iso15919IndicSeries = unicodeSequence{`m̐`, `ṁ`, `ḥ`, ``, `a`, `ā`, `i`, `ī`, `u`, `ū`, `ṛ`, `ḷ`, `ê`, `e`, `ē`, `ai`, `ô`, `o`, `ō`, `au`, `ka`, `kha`, `ga`, `gha`, `ṅa`, `ca`, `cha`, `ja`, `jha`, `ña`, `ṭa`, `ṭha`, `ḍa`, `ḍha`, `ṇa`, `ta`, `tha`, `da`, `dha`, `na`, `ṉa`, `pa`, `pha`, `ba`, `bha`, `ma`, `ya`, `ra`, `ṟa`, `la`, `ḷa`, `ḻa`, `va`, `śa`, `ṣa`, `sa`, `ha`, ``, ``, ``, `'`, `ā`, `i`, `ī`, `u`, `ū`, `ṛ`, `ṝ`, `ê`, `e`, `ē`, `ai`, `ô`, `o`, `ō`, `au`, ``, ``, ``, `oṃ`, ``, ``, ``, ``, ``, ``, ``, `qa`, `ḵẖa`, `ġ`, `za`, `ṛa`, `ṛha`, `fa`, `ẏa`, `ṝ`, `ḹ`, `ḷ`, `ḹ`, `.`, `..`, `0`, `1`, `2`, `3`, `4`, `5`, `6`, `7`, `8`, `9`, `…`, ``, ``, ``, ``, ``, ``, ``}

// IPA series specific for Indian languages
var ipaIndicSeries = unicodeSequence{`m`, `m`, ``, ``, `ə`, `aː`, `i`, `iː`, `u`, `uː`, `r̩`, `l̩`, `æ`, `e`, `eː`, `ɛː`, `ɔ`, `o`, `oː`, `ow`, `kə`, `kʰə`, `gə`, `gʱə`, `ŋə`, `ʧə`, `ʧʰə`, `ʤə`, `ʤʱə`, `ɲə`, `ʈə`, `ʈʰə`, `ɖə`, `ɖʱə`, `ɳə`, `t̪ə`, `t̪ʰə`, `d̪ə`, `d̪ʱə`, `n̪ə`, `nə`, `pə`, `pʰə`, `bə`, `bʱə`, `mə`, `jə`, `ɾə`, `rə`, `lə`, `ɭə`, `ɻə`, `ʋə`, `ɕə`, `ʂə`, `sə`, `ɦə`, ``, ``, ``, `ഽ`, `aː`, `i`, `iː`, `u`, `uː`, `r̩`, `l̩`, `e`, `eː`, `ɛː`, `ɔ`, `o`, `oː`, `ow`, ``, ``, ``, ``, ``, ``, ``, ``, ``, ``, `ow`, ``, ``, ``, ``, ``, ``, ``, ``, `r̩ː`, `l̩ː`, ``, ``, ``, ``, `0`, `1`, `2`, `3`, `4`, `5`, `6`, `7`, `8`, `9`, `൰`, ``, ``, ``, ``, ``, ``, ``, ``, ``, ``, ``, ``, ``, ``, ``}

// Map to hold rune sequence of each languages
var langMap = charMap{
	"hi_IN": devaAlphabets,
	"bn_IN": bengAlphabets,
	"pa_IN": guruAlphabets,
	"gu_IN": gujrAlphabets,
	"or_IN": oryaAlphabets,
	"ta_IN": tamlAlphabets,
	"te_IN": teluAlphabets,
	"kn_IN": kndaAlphabets,
	"ml_IN": mlymAlphabets,
}

func initializeUnicodeRange(slice runeSequence, begin int) {
	for i := 0; i < len(slice); i++ {
		slice[i] = rune(begin + i)
	}
}

func init() {
	for key, value := range langMap {
		initializeUnicodeRange(value.(runeSequence), langBases[key])
	}

	langMap["soundex_en"] = soundexEnglish
	langMap["soundex_in"] = soundexIndic
	langMap["ISO15919"] = iso15919IndicSeries
	langMap["IPA"] = ipaIndicSeries
	langMap["en_US"] = enUsAlphabets
}

func (r unicodeSequence) index(char interface{}) int {
	for i, value := range r {
		if value == char {
			return i
		}
	}

	return -1
}

func (r runeSequence) index(char interface{}) int {

	for i, value := range r {
		if value == char.(rune) {
			return i
		}
	}

	return -1
}

/*
  Language of returns the language of given character. Function
  accepts string or rune as argument. If language can not be detected
  function returns string "unknown"
*/
func LanguageOf(char interface{}) string {
	for lang, langRange := range langMap {
		if langRange.index(char) != -1 {
			return lang
		}
	}
	// Still not found then something wrong
	return "unknown"
}

/*
  CharCompare compares the given character or string literal to see if
  they are similar from different languages.

  Function accepts string or rune this is because IPA and ISO15919
  series are multibyte sequence and can not be represented as single
  rune.

  Another characteristic of Indian language is all languages have
  similar character set this is the basis of this function if both
  character are in 2 Indian languages but at similar Unicode code
  point function returns true otherwise returns false.
*/
func CharCompare(char1, char2 interface{}) bool {

	if char1 == char2 {
		return true
	}

	char1Index := langMap[LanguageOf(char1)].index(char1)
	char2Index := langMap[LanguageOf(char2)].index(char2)

	if char1Index == char2Index {
		return true
	}

	return false
}

/*
  SoundexCode returns the soundex code for given character function
  returns rune code and UnknownCharError.

  For the sake of allowing IPA and ISO15919 series this function also
  accepts either rune or string.

  If code for char is not found "0" is returned which will be ignored
  by Soundex calculation algorithm and error initiated using composite
  literal which can be used to print error message.
*/
func SoundexCode(char interface{}) (rune, error) {
	var lang string

	switch char.(type) {
	case string:
		char = strings.ToLower(char.(string))
	}

	if lang = LanguageOf(char); lang != "unknown" {
		if charIndex := langMap[lang].index(char); charIndex != -1 {
			var sequence runeSequence

			switch lang {
			case "en_US":
				sequence = langMap["soundex_en"].(runeSequence)
			default:
				sequence = langMap["soundex_in"].(runeSequence)
			}
			return sequence[charIndex], nil
		}
		return '0', &UnknownCharError{char, lang, "not found"}
	}
	return '0', &UnknownCharError{char, lang, "unknown language"}
}
<|endoftext|>


<commit_before>package check

import "fmt"

var baseTemplate = `# Save as MyRule.yml on your StylesPath
# See https://valelint.github.io/styles/#check-types for more info
# "suggestion", "warning" or "error"
level: warning
# Text describing this rule (generally longer than 'message').
description: '...'
# A link the source or reference.
link: '...'
%s`

var existenceTemplate = `extends: existence
# "%s" will be replaced by the active token
message: "found '%s'!"
ignorecase: false
tokens:
  - XXX
  - FIXME
  - TODO
  - NOTE`

var substitutionTemplate = `extends: substitution
message: Consider using '%s' instead of '%s'
ignorecase: false
# swap maps tokens in form of bad: good
swap:
  abundance: plenty
  accelerate: speed up`

var occurrenceTemplate = `extends: occurrence
message: "More than 3 commas!"
# Here, we're counting the number of times a comma appears in a sentence.
# If it occurs more than 3 times, we'll flag it.
scope: sentence
ignorecase: false
max: 3
token: ','`

var conditionalTemplate = `extends: conditional
message: "'%s' has no definition"
scope: text
ignorecase: false
# Ensures that the existence of 'first' implies the existence of 'second'.
first: \b([A-Z]{3,5})\b
second: (?:\b[A-Z][a-z]+ )+\(([A-Z]{3,5})\)
# ... with the exception of these:
exceptions:
  - ABC
  - ADD`

var consistencyTemplate = `extends: consistency
message: "Inconsistent spelling of '%s'"
scope: text
ignorecase: true
nonword: false
# We only want one of these to appear.
either:
  advisor: adviser
  centre: center`

var repetitionTemplate = `extends: repetition
message: "'%s' is repeated!"
scope: paragraph
ignorecase: false
# Will flag repeated occurances of the same token (e.g., "this this").
tokens:
  - '[^\s]+'`

var checkToTemplate = map[string]string{
	"existence":    existenceTemplate,
	"substitution": substitutionTemplate,
	"occurrence":   occurrenceTemplate,
	"conditional":  conditionalTemplate,
	"consistency":  consistencyTemplate,
	"repetition":   repetitionTemplate,
}

// GetTemplate makes a template for the given extension point.
func GetTemplate(name string) string {
	if template, ok := checkToTemplate[name]; ok {
		return fmt.Sprintf(baseTemplate, template)
	}
	return ""
}
<commit_msg>fix: "occurances" -> "occurrences"<commit_after>package check

import "fmt"

var baseTemplate = `# Save as MyRule.yml on your StylesPath
# See https://valelint.github.io/styles/#check-types for more info
# "suggestion", "warning" or "error"
level: warning
# Text describing this rule (generally longer than 'message').
description: '...'
# A link the source or reference.
link: '...'
%s`

var existenceTemplate = `extends: existence
# "%s" will be replaced by the active token
message: "found '%s'!"
ignorecase: false
tokens:
  - XXX
  - FIXME
  - TODO
  - NOTE`

var substitutionTemplate = `extends: substitution
message: Consider using '%s' instead of '%s'
ignorecase: false
# swap maps tokens in form of bad: good
swap:
  abundance: plenty
  accelerate: speed up`

var occurrenceTemplate = `extends: occurrence
message: "More than 3 commas!"
# Here, we're counting the number of times a comma appears in a sentence.
# If it occurs more than 3 times, we'll flag it.
scope: sentence
ignorecase: false
max: 3
token: ','`

var conditionalTemplate = `extends: conditional
message: "'%s' has no definition"
scope: text
ignorecase: false
# Ensures that the existence of 'first' implies the existence of 'second'.
first: \b([A-Z]{3,5})\b
second: (?:\b[A-Z][a-z]+ )+\(([A-Z]{3,5})\)
# ... with the exception of these:
exceptions:
  - ABC
  - ADD`

var consistencyTemplate = `extends: consistency
message: "Inconsistent spelling of '%s'"
scope: text
ignorecase: true
nonword: false
# We only want one of these to appear.
either:
  advisor: adviser
  centre: center`

var repetitionTemplate = `extends: repetition
message: "'%s' is repeated!"
scope: paragraph
ignorecase: false
# Will flag repeated occurrences of the same token (e.g., "this this").
tokens:
  - '[^\s]+'`

var checkToTemplate = map[string]string{
	"existence":    existenceTemplate,
	"substitution": substitutionTemplate,
	"occurrence":   occurrenceTemplate,
	"conditional":  conditionalTemplate,
	"consistency":  consistencyTemplate,
	"repetition":   repetitionTemplate,
}

// GetTemplate makes a template for the given extension point.
func GetTemplate(name string) string {
	if template, ok := checkToTemplate[name]; ok {
		return fmt.Sprintf(baseTemplate, template)
	}
	return ""
}
<|endoftext|>


<commit_before>package check

import (
	"strings"

	"github.com/jdkato/prose/transform"
	"github.com/xrash/smetrics"
)

func lower(s string) bool { return s == strings.ToLower(s) }
func upper(s string) bool { return s == strings.ToUpper(s) }

func title(s string) bool {
	return smetrics.Jaro(s, transform.Title(s)) > 0.95
}

func sentence(s string) bool {
	count := 0.0
	words := 0.0
	for i, w := range strings.Fields(s) {
		if i > 0 && w == strings.Title(w) {
			count++
		}
		words++
	}
	return (count / words) < 0.4
}

var varToFunc = map[string]func(string) bool{
	"$title":    title,
	"$lower":    lower,
	"$upper":    upper,
	"$sentence": sentence,
}
<commit_msg>refactor: increase Jaro distance threshold<commit_after>package check

import (
	"strings"

	"github.com/jdkato/prose/transform"
	"github.com/xrash/smetrics"
)

func lower(s string) bool { return s == strings.ToLower(s) }
func upper(s string) bool { return s == strings.ToUpper(s) }

func title(s string) bool {
	return smetrics.Jaro(s, transform.Title(s)) > 0.97
}

func sentence(s string) bool {
	count := 0.0
	words := 0.0
	for i, w := range strings.Fields(s) {
		if i > 0 && w == strings.Title(w) {
			count++
		}
		words++
	}
	return (count / words) < 0.4
}

var varToFunc = map[string]func(string) bool{
	"$title":    title,
	"$lower":    lower,
	"$upper":    upper,
	"$sentence": sentence,
}
<|endoftext|>


<commit_before>package fuse

// #include <linux/fuse.h>
import "C"

import (
	"os"
	"syscall"
)

const (
	FUSE_ROOT_ID = 1

	FUSE_UNKNOWN_INO = 0xffffffff

	CUSE_UNRESTRICTED_IOCTL = (1 << 0)

	FUSE_LK_FLOCK = (1 << 0)

	FUSE_IOCTL_MAX_IOV = 256

	FUSE_POLL_SCHEDULE_NOTIFY = (1 << 0)

	CUSE_INIT_INFO_MAX = 4096

	S_IFDIR = syscall.S_IFDIR
	S_IFREG = syscall.S_IFREG
	S_IFLNK = syscall.S_IFLNK
	S_IFIFO = syscall.S_IFIFO

	CUSE_INIT = 4096

	O_ANYWRITE = uint32(os.O_WRONLY | os.O_RDWR | os.O_APPEND | os.O_CREATE | os.O_TRUNC)
)

const PAGESIZE = 4096

const (
	_DEFAULT_BACKGROUND_TASKS = 12
)

type Status int32

const (
	OK      = Status(0)
	EACCES  = Status(syscall.EACCES)
	EBUSY   = Status(syscall.EBUSY)
	EINVAL  = Status(syscall.EINVAL)
	EIO     = Status(syscall.EIO)
	ENOENT  = Status(syscall.ENOENT)
	ENOSYS  = Status(syscall.ENOSYS)
	ENODATA = Status(syscall.ENODATA)
	ENOTDIR = Status(syscall.ENOTDIR)
	EPERM   = Status(syscall.EPERM)
	ERANGE  = Status(syscall.ERANGE)
	EXDEV   = Status(syscall.EXDEV)
	EBADF   = Status(syscall.EBADF)
	ENODEV  = Status(syscall.ENODEV)
	EROFS   = Status(syscall.EROFS)
)

type NotifyCode int

const (
	NOTIFY_POLL        = -1
	NOTIFY_INVAL_INODE = -2
	NOTIFY_INVAL_ENTRY = -3
	NOTIFY_CODE_MAX    = -4
)

type Attr struct {
	Ino       uint64
	Size      uint64
	Blocks    uint64
	Atime     uint64
	Mtime     uint64
	Ctime     uint64
	Atimensec uint32
	Mtimensec uint32
	Ctimensec uint32
	Mode      uint32
	Nlink     uint32
	Owner
	Rdev    uint32
	Blksize uint32
	Padding uint32
}

type Owner struct {
	Uid uint32
	Gid uint32
}

type Context struct {
	Owner
	Pid uint32
}

type Kstatfs struct {
	Blocks  uint64
	Bfree   uint64
	Bavail  uint64
	Files   uint64
	Ffree   uint64
	Bsize   uint32
	NameLen uint32
	Frsize  uint32
	Padding uint32
	Spare   [6]uint32
}

type FileLock struct {
	Start uint64
	End   uint64
	Typ   uint32
	Pid   uint32
}

type EntryOut struct {
	NodeId         uint64
	Generation     uint64
	EntryValid     uint64
	AttrValid      uint64
	EntryValidNsec uint32
	AttrValidNsec  uint32
	Attr
}

type ForgetIn struct {
	Nlookup uint64
}

const (
	// Mask for GetAttrIn.Flags. If set, GetAttrIn has a file handle set.
	FUSE_GETATTR_FH = (1 << 0)
)

type GetAttrIn struct {
	Flags uint32
	Dummy uint32
	Fh    uint64
}

type AttrOut struct {
	AttrValid     uint64
	AttrValidNsec uint32
	Dummy         uint32
	Attr
}

type MknodIn struct {
	Mode    uint32
	Rdev    uint32
	Umask   uint32
	Padding uint32
}

type MkdirIn struct {
	Mode  uint32
	Umask uint32
}

type RenameIn struct {
	Newdir uint64
}

type LinkIn struct {
	Oldnodeid uint64
}

const ( // SetAttrIn.Valid
	FATTR_MODE      = (1 << 0)
	FATTR_UID       = (1 << 1)
	FATTR_GID       = (1 << 2)
	FATTR_SIZE      = (1 << 3)
	FATTR_ATIME     = (1 << 4)
	FATTR_MTIME     = (1 << 5)
	FATTR_FH        = (1 << 6)
	FATTR_ATIME_NOW = (1 << 7)
	FATTR_MTIME_NOW = (1 << 8)
	FATTR_LOCKOWNER = (1 << 9)
)

type SetAttrIn struct {
	Valid     uint32
	Padding   uint32
	Fh        uint64
	Size      uint64
	LockOwner uint64
	Atime     uint64
	Mtime     uint64
	Unused2   uint64
	Atimensec uint32
	Mtimensec uint32
	Unused3   uint32
	Mode      uint32
	Unused4   uint32
	Owner
	Unused5 uint32
}

type OpenIn struct {
	Flags  uint32
	Unused uint32
}

type CreateIn struct {
	Flags   uint32
	Mode    uint32
	Umask   uint32
	Padding uint32
}

const (
	// OpenOut.Flags
	FOPEN_DIRECT_IO   = (1 << 0)
	FOPEN_KEEP_CACHE  = (1 << 1)
	FOPEN_NONSEEKABLE = (1 << 2)
)

type OpenOut struct {
	Fh        uint64
	OpenFlags uint32
	Padding   uint32
}

type CreateOut struct {
	EntryOut
	OpenOut
}

const RELEASE_FLUSH = (1 << 0)

type ReleaseIn struct {
	Fh           uint64
	Flags        uint32
	ReleaseFlags uint32
	LockOwner    uint64
}

type FlushIn struct {
	Fh        uint64
	Unused    uint32
	Padding   uint32
	LockOwner uint64
}

const (
	READ_LOCKOWNER = (1 << 1)
)

type ReadIn struct {
	Fh        uint64
	Offset    uint64
	Size      uint32
	ReadFlags uint32
	LockOwner uint64
	Flags     uint32
	Padding   uint32
}

const (
	WRITE_CACHE     = (1 << 0)
	WRITE_LOCKOWNER = (1 << 1)
)

type WriteIn struct {
	Fh         uint64
	Offset     uint64
	Size       uint32
	WriteFlags uint32
	LockOwner  uint64
	Flags      uint32
	Padding    uint32
}

type WriteOut struct {
	Size    uint32
	Padding uint32
}

type StatfsOut struct {
	Kstatfs
}

type FsyncIn struct {
	Fh         uint64
	FsyncFlags uint32
	Padding    uint32
}

type SetXAttrIn struct {
	Size  uint32
	Flags uint32
}

type GetXAttrIn struct {
	Size    uint32
	Padding uint32
}

type GetXAttrOut struct {
	Size    uint32
	Padding uint32
}

type LkIn struct {
	Fh      uint64
	Owner   uint64
	Lk      FileLock
	LkFlags uint32
	Padding uint32
}

type LkOut struct {
	Lk FileLock
}

// For AccessIn.Mask.
const (
	X_OK = 1
	W_OK = 2
	R_OK = 4
	F_OK = 0
)

type AccessIn struct {
	Mask    uint32
	Padding uint32
}

// To be set in InitIn/InitOut.Flags.
const (
	CAP_ASYNC_READ     = (1 << 0)
	CAP_POSIX_LOCKS    = (1 << 1)
	CAP_FILE_OPS       = (1 << 2)
	CAP_ATOMIC_O_TRUNC = (1 << 3)
	CAP_EXPORT_SUPPORT = (1 << 4)
	CAP_BIG_WRITES     = (1 << 5)
	CAP_DONT_MASK      = (1 << 6)
	CAP_SPLICE_WRITE   = (1 << 7)
	CAP_SPLICE_MOVE    = (1 << 8)
	CAP_SPLICE_READ    = (1 << 9)
)

type InitIn struct {
	Major        uint32
	Minor        uint32
	MaxReadAhead uint32
	Flags        uint32
}

type InitOut struct {
	Major               uint32
	Minor               uint32
	MaxReadAhead        uint32
	Flags               uint32
	MaxBackground       uint16
	CongestionThreshold uint16
	MaxWrite            uint32
}

type CuseInitIn struct {
	Major  uint32
	Minor  uint32
	Unused uint32
	Flags  uint32
}

type CuseInitOut struct {
	Major    uint32
	Minor    uint32
	Unused   uint32
	Flags    uint32
	MaxRead  uint32
	MaxWrite uint32
	DevMajor uint32
	DevMinor uint32
	Spare    [10]uint32
}

type InterruptIn struct {
	Unique uint64
}

type BmapIn struct {
	Block     uint64
	Blocksize uint32
	Padding   uint32
}

type BmapOut struct {
	Block uint64
}

const (
	FUSE_IOCTL_COMPAT       = (1 << 0)
	FUSE_IOCTL_UNRESTRICTED = (1 << 1)
	FUSE_IOCTL_RETRY        = (1 << 2)
)

type IoctlIn struct {
	Fh      uint64
	Flags   uint32
	Cmd     uint32
	Arg     uint64
	InSize  uint32
	OutSize uint32
}

type IoctlOut struct {
	Result  int32
	Flags   uint32
	InIovs  uint32
	OutIovs uint32
}

type PollIn struct {
	Fh      uint64
	Kh      uint64
	Flags   uint32
	Padding uint32
}

type PollOut struct {
	Revents uint32
	Padding uint32
}

type NotifyPollWakeupOut struct {
	Kh uint64
}

type InHeader struct {
	Length uint32
	opcode
	Unique uint64
	NodeId uint64
	Context
	Padding uint32
}

type OutHeader struct {
	Length uint32
	Status Status
	Unique uint64
}

type Dirent struct {
	Ino     uint64
	Off     uint64
	NameLen uint32
	Typ     uint32
}

type NotifyInvalInodeOut struct {
	Ino    uint64
	Off    int64
	Length int64
}

type NotifyInvalEntryOut struct {
	Parent  uint64
	NameLen uint32
	Padding uint32
}
<commit_msg>Revert inadvertent 'import "C"' statement.<commit_after>package fuse

import (
	"os"
	"syscall"
)

const (
	FUSE_ROOT_ID = 1

	FUSE_UNKNOWN_INO = 0xffffffff

	CUSE_UNRESTRICTED_IOCTL = (1 << 0)

	FUSE_LK_FLOCK = (1 << 0)

	FUSE_IOCTL_MAX_IOV = 256

	FUSE_POLL_SCHEDULE_NOTIFY = (1 << 0)

	CUSE_INIT_INFO_MAX = 4096

	S_IFDIR = syscall.S_IFDIR
	S_IFREG = syscall.S_IFREG
	S_IFLNK = syscall.S_IFLNK
	S_IFIFO = syscall.S_IFIFO

	CUSE_INIT = 4096

	O_ANYWRITE = uint32(os.O_WRONLY | os.O_RDWR | os.O_APPEND | os.O_CREATE | os.O_TRUNC)
)

const PAGESIZE = 4096

const (
	_DEFAULT_BACKGROUND_TASKS = 12
)

type Status int32

const (
	OK      = Status(0)
	EACCES  = Status(syscall.EACCES)
	EBUSY   = Status(syscall.EBUSY)
	EINVAL  = Status(syscall.EINVAL)
	EIO     = Status(syscall.EIO)
	ENOENT  = Status(syscall.ENOENT)
	ENOSYS  = Status(syscall.ENOSYS)
	ENODATA = Status(syscall.ENODATA)
	ENOTDIR = Status(syscall.ENOTDIR)
	EPERM   = Status(syscall.EPERM)
	ERANGE  = Status(syscall.ERANGE)
	EXDEV   = Status(syscall.EXDEV)
	EBADF   = Status(syscall.EBADF)
	ENODEV  = Status(syscall.ENODEV)
	EROFS   = Status(syscall.EROFS)
)

type NotifyCode int

const (
	NOTIFY_POLL        = -1
	NOTIFY_INVAL_INODE = -2
	NOTIFY_INVAL_ENTRY = -3
	NOTIFY_CODE_MAX    = -4
)

type Attr struct {
	Ino       uint64
	Size      uint64
	Blocks    uint64
	Atime     uint64
	Mtime     uint64
	Ctime     uint64
	Atimensec uint32
	Mtimensec uint32
	Ctimensec uint32
	Mode      uint32
	Nlink     uint32
	Owner
	Rdev    uint32
	Blksize uint32
	Padding uint32
}

type Owner struct {
	Uid uint32
	Gid uint32
}

type Context struct {
	Owner
	Pid uint32
}

type Kstatfs struct {
	Blocks  uint64
	Bfree   uint64
	Bavail  uint64
	Files   uint64
	Ffree   uint64
	Bsize   uint32
	NameLen uint32
	Frsize  uint32
	Padding uint32
	Spare   [6]uint32
}

type FileLock struct {
	Start uint64
	End   uint64
	Typ   uint32
	Pid   uint32
}

type EntryOut struct {
	NodeId         uint64
	Generation     uint64
	EntryValid     uint64
	AttrValid      uint64
	EntryValidNsec uint32
	AttrValidNsec  uint32
	Attr
}

type ForgetIn struct {
	Nlookup uint64
}

const (
	// Mask for GetAttrIn.Flags. If set, GetAttrIn has a file handle set.
	FUSE_GETATTR_FH = (1 << 0)
)

type GetAttrIn struct {
	Flags uint32
	Dummy uint32
	Fh    uint64
}

type AttrOut struct {
	AttrValid     uint64
	AttrValidNsec uint32
	Dummy         uint32
	Attr
}

type MknodIn struct {
	Mode    uint32
	Rdev    uint32
	Umask   uint32
	Padding uint32
}

type MkdirIn struct {
	Mode  uint32
	Umask uint32
}

type RenameIn struct {
	Newdir uint64
}

type LinkIn struct {
	Oldnodeid uint64
}

const ( // SetAttrIn.Valid
	FATTR_MODE      = (1 << 0)
	FATTR_UID       = (1 << 1)
	FATTR_GID       = (1 << 2)
	FATTR_SIZE      = (1 << 3)
	FATTR_ATIME     = (1 << 4)
	FATTR_MTIME     = (1 << 5)
	FATTR_FH        = (1 << 6)
	FATTR_ATIME_NOW = (1 << 7)
	FATTR_MTIME_NOW = (1 << 8)
	FATTR_LOCKOWNER = (1 << 9)
)

type SetAttrIn struct {
	Valid     uint32
	Padding   uint32
	Fh        uint64
	Size      uint64
	LockOwner uint64
	Atime     uint64
	Mtime     uint64
	Unused2   uint64
	Atimensec uint32
	Mtimensec uint32
	Unused3   uint32
	Mode      uint32
	Unused4   uint32
	Owner
	Unused5 uint32
}

type OpenIn struct {
	Flags  uint32
	Unused uint32
}

type CreateIn struct {
	Flags   uint32
	Mode    uint32
	Umask   uint32
	Padding uint32
}

const (
	// OpenOut.Flags
	FOPEN_DIRECT_IO   = (1 << 0)
	FOPEN_KEEP_CACHE  = (1 << 1)
	FOPEN_NONSEEKABLE = (1 << 2)
)

type OpenOut struct {
	Fh        uint64
	OpenFlags uint32
	Padding   uint32
}

type CreateOut struct {
	EntryOut
	OpenOut
}

const RELEASE_FLUSH = (1 << 0)

type ReleaseIn struct {
	Fh           uint64
	Flags        uint32
	ReleaseFlags uint32
	LockOwner    uint64
}

type FlushIn struct {
	Fh        uint64
	Unused    uint32
	Padding   uint32
	LockOwner uint64
}

const (
	READ_LOCKOWNER = (1 << 1)
)

type ReadIn struct {
	Fh        uint64
	Offset    uint64
	Size      uint32
	ReadFlags uint32
	LockOwner uint64
	Flags     uint32
	Padding   uint32
}

const (
	WRITE_CACHE     = (1 << 0)
	WRITE_LOCKOWNER = (1 << 1)
)

type WriteIn struct {
	Fh         uint64
	Offset     uint64
	Size       uint32
	WriteFlags uint32
	LockOwner  uint64
	Flags      uint32
	Padding    uint32
}

type WriteOut struct {
	Size    uint32
	Padding uint32
}

type StatfsOut struct {
	Kstatfs
}

type FsyncIn struct {
	Fh         uint64
	FsyncFlags uint32
	Padding    uint32
}

type SetXAttrIn struct {
	Size  uint32
	Flags uint32
}

type GetXAttrIn struct {
	Size    uint32
	Padding uint32
}

type GetXAttrOut struct {
	Size    uint32
	Padding uint32
}

type LkIn struct {
	Fh      uint64
	Owner   uint64
	Lk      FileLock
	LkFlags uint32
	Padding uint32
}

type LkOut struct {
	Lk FileLock
}

// For AccessIn.Mask.
const (
	X_OK = 1
	W_OK = 2
	R_OK = 4
	F_OK = 0
)

type AccessIn struct {
	Mask    uint32
	Padding uint32
}

// To be set in InitIn/InitOut.Flags.
const (
	CAP_ASYNC_READ     = (1 << 0)
	CAP_POSIX_LOCKS    = (1 << 1)
	CAP_FILE_OPS       = (1 << 2)
	CAP_ATOMIC_O_TRUNC = (1 << 3)
	CAP_EXPORT_SUPPORT = (1 << 4)
	CAP_BIG_WRITES     = (1 << 5)
	CAP_DONT_MASK      = (1 << 6)
	CAP_SPLICE_WRITE   = (1 << 7)
	CAP_SPLICE_MOVE    = (1 << 8)
	CAP_SPLICE_READ    = (1 << 9)
)

type InitIn struct {
	Major        uint32
	Minor        uint32
	MaxReadAhead uint32
	Flags        uint32
}

type InitOut struct {
	Major               uint32
	Minor               uint32
	MaxReadAhead        uint32
	Flags               uint32
	MaxBackground       uint16
	CongestionThreshold uint16
	MaxWrite            uint32
}

type CuseInitIn struct {
	Major  uint32
	Minor  uint32
	Unused uint32
	Flags  uint32
}

type CuseInitOut struct {
	Major    uint32
	Minor    uint32
	Unused   uint32
	Flags    uint32
	MaxRead  uint32
	MaxWrite uint32
	DevMajor uint32
	DevMinor uint32
	Spare    [10]uint32
}

type InterruptIn struct {
	Unique uint64
}

type BmapIn struct {
	Block     uint64
	Blocksize uint32
	Padding   uint32
}

type BmapOut struct {
	Block uint64
}

const (
	FUSE_IOCTL_COMPAT       = (1 << 0)
	FUSE_IOCTL_UNRESTRICTED = (1 << 1)
	FUSE_IOCTL_RETRY        = (1 << 2)
)

type IoctlIn struct {
	Fh      uint64
	Flags   uint32
	Cmd     uint32
	Arg     uint64
	InSize  uint32
	OutSize uint32
}

type IoctlOut struct {
	Result  int32
	Flags   uint32
	InIovs  uint32
	OutIovs uint32
}

type PollIn struct {
	Fh      uint64
	Kh      uint64
	Flags   uint32
	Padding uint32
}

type PollOut struct {
	Revents uint32
	Padding uint32
}

type NotifyPollWakeupOut struct {
	Kh uint64
}

type InHeader struct {
	Length uint32
	opcode
	Unique uint64
	NodeId uint64
	Context
	Padding uint32
}

type OutHeader struct {
	Length uint32
	Status Status
	Unique uint64
}

type Dirent struct {
	Ino     uint64
	Off     uint64
	NameLen uint32
	Typ     uint32
}

type NotifyInvalInodeOut struct {
	Ino    uint64
	Off    int64
	Length int64
}

type NotifyInvalEntryOut struct {
	Parent  uint64
	NameLen uint32
	Padding uint32
}
<|endoftext|>