<commit_before>package admin

import "path"

type Menu struct {
	Name      string
	rawPath   string
	Link      string
	SubMenus  []*Menu
	Ancestors []string
}

func (admin Admin) GetMenus() []*Menu {
	return admin.menus
}

func (admin *Admin) AddMenu(menu *Menu) {
	admin.menus = appendMenu(admin.menus, menu.Ancestors, menu)
}

func (admin Admin) GetMenu(name string) (m *Menu) {
	return getMenu(admin.menus, name)
}

func getMenu(menus []*Menu, name string) *Menu {
	for _, m := range menus {
		if m.Name == name {
			return m
		}

		if len(m.SubMenus) > 0 {
			if mc := getMenu(m.SubMenus, name); mc != nil {
				return mc
			}
		}
	}

	return nil
}

// Generate menu links by current route. e.g "/products" to "/admin/products"
func (admin *Admin) generateMenuLinks() {
	prefixMenuLinks(admin.menus, admin.router.Prefix)
}

func prefixMenuLinks(menus []*Menu, prefix string) {
	for _, m := range menus {
		if m.rawPath != "" {
			m.Link = path.Join(prefix, m.rawPath)
		}
		if len(m.SubMenus) > 0 {
			prefixMenuLinks(m.SubMenus, prefix)
		}
	}
}

func newMenu(menus []string, neoMenu *Menu) *Menu {
	menuCount := len(menus)
	for index, _ := range menus {
		neoMenu = &Menu{Name: menus[menuCount-index-1], SubMenus: []*Menu{neoMenu}}
	}

	return neoMenu
}

func appendMenu(menus []*Menu, ancestors []string, neoMenu *Menu) []*Menu {
	if len(ancestors) > 0 {
		for _, m := range menus {
			if m.Name != ancestors[0] {
				continue
			}

			if len(ancestors) > 1 {
				m.SubMenus = appendMenu(m.SubMenus, ancestors[1:], neoMenu)
			} else {
				m.SubMenus = append(m.SubMenus, newMenu(nil, neoMenu))
			}
			return menus
		}
	}

	return append(menus, newMenu(ancestors, neoMenu))
}
<commit_msg>Rename parameter nominee to menu for better readability.<commit_after>package admin

import "path"

type Menu struct {
	Name      string
	rawPath   string
	Link      string
	SubMenus  []*Menu
	Ancestors []string
}

func (admin Admin) GetMenus() []*Menu {
	return admin.menus
}

func (admin *Admin) AddMenu(menu *Menu) {
	admin.menus = appendMenu(admin.menus, menu.Ancestors, menu)
}

func (admin Admin) GetMenu(name string) (m *Menu) {
	return getMenu(admin.menus, name)
}

func getMenu(menus []*Menu, name string) *Menu {
	for _, m := range menus {
		if m.Name == name {
			return m
		}

		if len(m.SubMenus) > 0 {
			if mc := getMenu(m.SubMenus, name); mc != nil {
				return mc
			}
		}
	}

	return nil
}

// Generate menu links by current route. e.g "/products" to "/admin/products"
func (admin *Admin) generateMenuLinks() {
	prefixMenuLinks(admin.menus, admin.router.Prefix)
}

func prefixMenuLinks(menus []*Menu, prefix string) {
	for _, m := range menus {
		if m.rawPath != "" {
			m.Link = path.Join(prefix, m.rawPath)
		}
		if len(m.SubMenus) > 0 {
			prefixMenuLinks(m.SubMenus, prefix)
		}
	}
}

func newMenu(menus []string, menu *Menu) *Menu {
	menuCount := len(menus)
	for index, _ := range menus {
		menu = &Menu{Name: menus[menuCount-index-1], SubMenus: []*Menu{menu}}
	}

	return menu
}

func appendMenu(menus []*Menu, ancestors []string, menu *Menu) []*Menu {
	if len(ancestors) > 0 {
		for _, m := range menus {
			if m.Name != ancestors[0] {
				continue
			}

			if len(ancestors) > 1 {
				m.SubMenus = appendMenu(m.SubMenus, ancestors[1:], menu)
			} else {
				m.SubMenus = append(m.SubMenus, newMenu(nil, menu))
			}
			return menus
		}
	}

	return append(menus, newMenu(ancestors, menu))
}
<|endoftext|>


<commit_before>package functionaltests

import (
	c "github.com/couchbase/indexing/secondary/common"
	tc "github.com/couchbase/indexing/secondary/tests/framework/common"
	"github.com/couchbase/indexing/secondary/tests/framework/datautility"
	kv "github.com/couchbase/indexing/secondary/tests/framework/kvutility"
	"github.com/couchbase/indexing/secondary/tests/framework/secondaryindex"
	tv "github.com/couchbase/indexing/secondary/tests/framework/validation"
	"log"
	"testing"
	"time"
)

func CreateDocs(num int) {
	i := 0
	keysToBeSet := make(tc.KeyValues)
	for key, value := range mut_docs {
		keysToBeSet[key] = value
		i++
		if i == num {
			break
		}
	}
	kv.SetKeyValues(keysToBeSet, "default", "", clusterconfig.KVAddress)
	// Update docs object with newly added keys and remove those keys from mut_docs
	for key, value := range keysToBeSet {
		docs[key] = value
		delete(mut_docs, key)
	}
}

func DeleteDocs(num int) {
	i := 0
	keysToBeDeleted := make(tc.KeyValues)
	for key, value := range docs {
		keysToBeDeleted[key] = value
		i++
		if i == num {
			break
		}
	}
	kv.DeleteKeys(keysToBeDeleted, "default", "", clusterconfig.KVAddress)
	// Update docs object with deleted keys and add those keys from mut_docs
	for key, value := range keysToBeDeleted {
		delete(docs, key)
		mut_docs[key] = value
	}
}

// delete docs and do not update mut_docs object
func DeleteDocs2(num int) {
	i := 0
	keysToBeDeleted := make(tc.KeyValues)
	for key, value := range docs {
		keysToBeDeleted[key] = value
		i++
		if i == num {
			break
		}
	}
	kv.DeleteKeys(keysToBeDeleted, "default", "", clusterconfig.KVAddress)
	// Update docs object with deleted keys
	for key, _ := range keysToBeDeleted {
		delete(docs, key)
	}
}

func UpdateDocs(num int) {
	i := 0

	// Pick some docs from mut_docs
	keysFromMutDocs := make(tc.KeyValues)
	for key, value := range mut_docs {
		keysFromMutDocs[key] = value
		i++
		if i == num {
			break
		}
	}
	// and , Add them to docs
	keysToBeSet := make(tc.KeyValues)
	for _, value := range keysFromMutDocs {
		n := randomNum(0, float64(len(docs)-1))
		i = 0
		var k string
		for k, _ = range docs {
			if i == n {
				break
			}
			i++
		}
		docs[k] = value
		keysToBeSet[k] = value
	}
	log.Printf("Num of keysFromMutDocs: %d", len(keysFromMutDocs))
	log.Printf("Updating number of documents: %d", len(keysToBeSet))
	kv.SetKeyValues(keysToBeSet, "default", "", clusterconfig.KVAddress)
}

func TestRestartIndexer(t *testing.T) {
	log.Printf("In TestRestartIndexer()")

	tc.KillIndexer()
	time.Sleep(60 * time.Second)

	var indexName = "index_age"
	var bucketName = "default"

	docScanResults := datautility.ExpectedScanResponse_float64(docs, "age", 0, 90, 1)
	scanResults, err := secondaryindex.Range(indexName, bucketName, indexScanAddress, []interface{}{0}, []interface{}{90}, 1, true, defaultlimit, c.SessionConsistency, nil)
	FailTestIfError(err, "Error in scan", t)
	log.Printf("Len of expected and actual scan results are :  %d and %d", len(docScanResults), len(scanResults))
	err = tv.Validate(docScanResults, scanResults)
	FailTestIfError(err, "Error in scan result validation", t)
}

func TestCreateDocsMutation(t *testing.T) {
	log.Printf("In TestCreateDocsMutation()")
	var indexName = "index_age"
	var bucketName = "default"

	err := secondaryindex.CreateSecondaryIndex(indexName, bucketName, indexManagementAddress, "", []string{"age"}, false, nil, true, defaultIndexActiveTimeout, nil)
	FailTestIfError(err, "Error in creating the index", t)

	docScanResults := datautility.ExpectedScanResponse_float64(docs, "age", 0, 90, 1)
	scanResults, err := secondaryindex.Range(indexName, bucketName, indexScanAddress, []interface{}{0}, []interface{}{90}, 1, true, defaultlimit, c.SessionConsistency, nil)
	FailTestIfError(err, "Error in scan", t)
	log.Printf("Len of expected and actual scan results are :  %d and %d", len(docScanResults), len(scanResults))
	err = tv.Validate(docScanResults, scanResults)
	FailTestIfError(err, "Error in scan result validation", t)

	//Create docs mutations: Add new docs to KV
	CreateDocs(100)

	docScanResults = datautility.ExpectedScanResponse_float64(docs, "age", 0, 90, 1)
	start := time.Now()
	scanResults, err = secondaryindex.Range(indexName, bucketName, indexScanAddress, []interface{}{0}, []interface{}{90}, 1, true, defaultlimit, c.SessionConsistency, nil)
	elapsed := time.Since(start)
	log.Printf("Index Scan after mutations took %s\n", elapsed)
	FailTestIfError(err, "Error in scan", t)
	log.Printf("Len of expected and actual scan results are :  %d and %d", len(docScanResults), len(scanResults))
	err = tv.Validate(docScanResults, scanResults)
	FailTestIfError(err, "Error in scan result validation", t)
}

func TestRestartProjector(t *testing.T) {
	log.Printf("In TestRestartProjector()")

	tc.KillProjector()
	time.Sleep(60 * time.Second)

	var indexName = "index_age"
	var bucketName = "default"

	docScanResults := datautility.ExpectedScanResponse_float64(docs, "age", 0, 90, 1)
	scanResults, err := secondaryindex.Range(indexName, bucketName, indexScanAddress, []interface{}{0}, []interface{}{90}, 1, true, defaultlimit, c.SessionConsistency, nil)
	FailTestIfError(err, "Error in scan", t)
	log.Printf("Len of expected and actual scan results are :  %d and %d", len(docScanResults), len(scanResults))
	err = tv.Validate(docScanResults, scanResults)
	FailTestIfError(err, "Error in scan result validation", t)
}

// Test with mutations delay wait of 15s
func TestDeleteDocsMutation(t *testing.T) {
	log.Printf("In TestDeleteDocsMutation()")
	var indexName = "index_age"
	var bucketName = "default"

	err := secondaryindex.CreateSecondaryIndex(indexName, bucketName, indexManagementAddress, "", []string{"age"}, false, nil, true, defaultIndexActiveTimeout, nil)
	FailTestIfError(err, "Error in creating the index", t)

	docScanResults := datautility.ExpectedScanResponse_float64(docs, "age", 0, 90, 1)
	scanResults, err := secondaryindex.Range(indexName, bucketName, indexScanAddress, []interface{}{0}, []interface{}{90}, 1, true, defaultlimit, c.SessionConsistency, nil)
	FailTestIfError(err, "Error in scan", t)
	log.Printf("Len of expected and actual scan results are :  %d and %d", len(docScanResults), len(scanResults))
	err = tv.Validate(docScanResults, scanResults)
	FailTestIfError(err, "Error in scan result validation", t)

	//Delete docs mutations:  Delete docs from KV
	DeleteDocs(200)

	docScanResults = datautility.ExpectedScanResponse_float64(docs, "age", 0, 90, 1)
	start := time.Now()
	scanResults, err = secondaryindex.Range(indexName, bucketName, indexScanAddress, []interface{}{0}, []interface{}{90}, 1, true, defaultlimit, c.SessionConsistency, nil)
	elapsed := time.Since(start)
	log.Printf("Index Scan after mutations took %s\n", elapsed)
	FailTestIfError(err, "Error in scan", t)
	log.Printf("Len of expected and actual scan results are :  %d and %d", len(docScanResults), len(scanResults))
	err = tv.Validate(docScanResults, scanResults)
	FailTestIfError(err, "Error in scan result validation", t)
}

// Test with mutations delay wait of 15s
func TestUpdateDocsMutation(t *testing.T) {
	log.Printf("In TestUpdateDocsMutation()")
	var indexName = "index_age"
	var bucketName = "default"

	err := secondaryindex.CreateSecondaryIndex(indexName, bucketName, indexManagementAddress, "", []string{"age"}, false, nil, true, defaultIndexActiveTimeout, nil)
	FailTestIfError(err, "Error in creating the index", t)

	docScanResults := datautility.ExpectedScanResponse_float64(docs, "age", 20, 40, 2)
	scanResults, err := secondaryindex.Range(indexName, bucketName, indexScanAddress, []interface{}{20}, []interface{}{40}, 2, true, defaultlimit, c.SessionConsistency, nil)
	FailTestIfError(err, "Error in scan", t)
	log.Printf("Len of expected and actual scan results are :  %d and %d", len(docScanResults), len(scanResults))
	err = tv.Validate(docScanResults, scanResults)
	FailTestIfError(err, "Error in scan result validation", t)

	//Update docs mutations:  Update docs in KV
	UpdateDocs(100)

	docScanResults = datautility.ExpectedScanResponse_float64(docs, "age", 20, 40, 2)
	start := time.Now()
	scanResults, err = secondaryindex.Range(indexName, bucketName, indexScanAddress, []interface{}{20}, []interface{}{40}, 2, true, defaultlimit, c.SessionConsistency, nil)
	elapsed := time.Since(start)
	log.Printf("Index Scan after mutations took %s\n", elapsed)
	FailTestIfError(err, "Error in scan", t)
	log.Printf("Len of expected and actual scan results are :  %d and %d", len(docScanResults), len(scanResults))
	err = tv.Validate(docScanResults, scanResults)
	FailTestIfError(err, "Error in scan result validation", t)
}

// Test with large number of mutations
func SkipTestLargeMutations(t *testing.T) {
	log.Printf("In TestLargeMutations()")
	var index1 = "indexmut_1"
	var index2 = "indexmut_2"
	var bucketName = "default"
	var field1 = "company"
	var field2 = "gender"

	// e := secondaryindex.DropAllSecondaryIndexes(indexManagementAddress)
	// FailTestIfError(e, "Error in DropAllSecondaryIndexes", t)

	docsToCreate := generateDocs(20000, "users.prod")
	UpdateKVDocs(docsToCreate, docs)
	kv.SetKeyValues(docsToCreate, "default", "", clusterconfig.KVAddress)

	err := secondaryindex.CreateSecondaryIndex(index1, bucketName, indexManagementAddress, "", []string{field1}, false, nil, true, defaultIndexActiveTimeout, nil)
	FailTestIfError(err, "Error in creating the index", t)

	docScanResults := datautility.ExpectedScanAllResponse(docs, field1)
	scanResults, err := secondaryindex.ScanAll(index1, bucketName, indexScanAddress, defaultlimit, c.SessionConsistency, nil)
	FailTestIfError(err, "Error in scan", t)
	err = tv.Validate(docScanResults, scanResults)
	FailTestIfError(err, "Error in scan result validation", t)
	log.Printf("Len of expected and actual scan results are :  %d and %d", len(docScanResults), len(scanResults))

	for i := 0; i <= 10; i++ {
		log.Printf("ITERATION %v\n", i)

		docsToCreate = generateDocs(10000, "users.prod")
		UpdateKVDocs(docsToCreate, docs)
		kv.SetKeyValues(docsToCreate, "default", "", clusterconfig.KVAddress)

		err := secondaryindex.CreateSecondaryIndex(index2, bucketName, indexManagementAddress, "", []string{field2}, false, nil, true, defaultIndexActiveTimeout, nil)
		FailTestIfError(err, "Error in creating the index", t)

		docScanResults = datautility.ExpectedScanAllResponse(docs, field1)
		scanResults, err = secondaryindex.ScanAll(index1, bucketName, indexScanAddress, defaultlimit, c.SessionConsistency, nil)
		FailTestIfError(err, "Error in scan", t)
		err = tv.Validate(docScanResults, scanResults)
		FailTestIfError(err, "Error in scan result validation", t)
		log.Printf("Len of expected and actual scan results are :  %d and %d", len(docScanResults), len(scanResults))

		docScanResults = datautility.ExpectedScanAllResponse(docs, field2)
		scanResults, err = secondaryindex.ScanAll(index2, bucketName, indexScanAddress, defaultlimit, c.SessionConsistency, nil)
		FailTestIfError(err, "Error in scan", t)
		err = tv.Validate(docScanResults, scanResults)
		FailTestIfError(err, "Error in scan result validation", t)
		log.Printf("Len of expected and actual scan results are :  %d and %d", len(docScanResults), len(scanResults))

		err = secondaryindex.DropSecondaryIndex(index2, bucketName, indexManagementAddress)
		FailTestIfError(err, "Error in drop index", t)
	}
}
<commit_msg>Tests - Enabling TestLargeMutations test case<commit_after>package functionaltests

import (
	c "github.com/couchbase/indexing/secondary/common"
	tc "github.com/couchbase/indexing/secondary/tests/framework/common"
	"github.com/couchbase/indexing/secondary/tests/framework/datautility"
	kv "github.com/couchbase/indexing/secondary/tests/framework/kvutility"
	"github.com/couchbase/indexing/secondary/tests/framework/secondaryindex"
	tv "github.com/couchbase/indexing/secondary/tests/framework/validation"
	"log"
	"testing"
	"time"
)

func CreateDocs(num int) {
	i := 0
	keysToBeSet := make(tc.KeyValues)
	for key, value := range mut_docs {
		keysToBeSet[key] = value
		i++
		if i == num {
			break
		}
	}
	kv.SetKeyValues(keysToBeSet, "default", "", clusterconfig.KVAddress)
	// Update docs object with newly added keys and remove those keys from mut_docs
	for key, value := range keysToBeSet {
		docs[key] = value
		delete(mut_docs, key)
	}
}

func DeleteDocs(num int) {
	i := 0
	keysToBeDeleted := make(tc.KeyValues)
	for key, value := range docs {
		keysToBeDeleted[key] = value
		i++
		if i == num {
			break
		}
	}
	kv.DeleteKeys(keysToBeDeleted, "default", "", clusterconfig.KVAddress)
	// Update docs object with deleted keys and add those keys from mut_docs
	for key, value := range keysToBeDeleted {
		delete(docs, key)
		mut_docs[key] = value
	}
}

// delete docs and do not update mut_docs object
func DeleteDocs2(num int) {
	i := 0
	keysToBeDeleted := make(tc.KeyValues)
	for key, value := range docs {
		keysToBeDeleted[key] = value
		i++
		if i == num {
			break
		}
	}
	kv.DeleteKeys(keysToBeDeleted, "default", "", clusterconfig.KVAddress)
	// Update docs object with deleted keys
	for key, _ := range keysToBeDeleted {
		delete(docs, key)
	}
}

func UpdateDocs(num int) {
	i := 0

	// Pick some docs from mut_docs
	keysFromMutDocs := make(tc.KeyValues)
	for key, value := range mut_docs {
		keysFromMutDocs[key] = value
		i++
		if i == num {
			break
		}
	}
	// and , Add them to docs
	keysToBeSet := make(tc.KeyValues)
	for _, value := range keysFromMutDocs {
		n := randomNum(0, float64(len(docs)-1))
		i = 0
		var k string
		for k, _ = range docs {
			if i == n {
				break
			}
			i++
		}
		docs[k] = value
		keysToBeSet[k] = value
	}
	log.Printf("Num of keysFromMutDocs: %d", len(keysFromMutDocs))
	log.Printf("Updating number of documents: %d", len(keysToBeSet))
	kv.SetKeyValues(keysToBeSet, "default", "", clusterconfig.KVAddress)
}

func TestRestartIndexer(t *testing.T) {
	log.Printf("In TestRestartIndexer()")

	tc.KillIndexer()
	time.Sleep(60 * time.Second)

	var indexName = "index_age"
	var bucketName = "default"

	docScanResults := datautility.ExpectedScanResponse_float64(docs, "age", 0, 90, 1)
	scanResults, err := secondaryindex.Range(indexName, bucketName, indexScanAddress, []interface{}{0}, []interface{}{90}, 1, true, defaultlimit, c.SessionConsistency, nil)
	FailTestIfError(err, "Error in scan", t)
	log.Printf("Len of expected and actual scan results are :  %d and %d", len(docScanResults), len(scanResults))
	err = tv.Validate(docScanResults, scanResults)
	FailTestIfError(err, "Error in scan result validation", t)
}

func TestCreateDocsMutation(t *testing.T) {
	log.Printf("In TestCreateDocsMutation()")
	var indexName = "index_age"
	var bucketName = "default"

	err := secondaryindex.CreateSecondaryIndex(indexName, bucketName, indexManagementAddress, "", []string{"age"}, false, nil, true, defaultIndexActiveTimeout, nil)
	FailTestIfError(err, "Error in creating the index", t)

	docScanResults := datautility.ExpectedScanResponse_float64(docs, "age", 0, 90, 1)
	scanResults, err := secondaryindex.Range(indexName, bucketName, indexScanAddress, []interface{}{0}, []interface{}{90}, 1, true, defaultlimit, c.SessionConsistency, nil)
	FailTestIfError(err, "Error in scan", t)
	log.Printf("Len of expected and actual scan results are :  %d and %d", len(docScanResults), len(scanResults))
	err = tv.Validate(docScanResults, scanResults)
	FailTestIfError(err, "Error in scan result validation", t)

	//Create docs mutations: Add new docs to KV
	CreateDocs(100)

	docScanResults = datautility.ExpectedScanResponse_float64(docs, "age", 0, 90, 1)
	start := time.Now()
	scanResults, err = secondaryindex.Range(indexName, bucketName, indexScanAddress, []interface{}{0}, []interface{}{90}, 1, true, defaultlimit, c.SessionConsistency, nil)
	elapsed := time.Since(start)
	log.Printf("Index Scan after mutations took %s\n", elapsed)
	FailTestIfError(err, "Error in scan", t)
	log.Printf("Len of expected and actual scan results are :  %d and %d", len(docScanResults), len(scanResults))
	err = tv.Validate(docScanResults, scanResults)
	FailTestIfError(err, "Error in scan result validation", t)
}

func TestRestartProjector(t *testing.T) {
	log.Printf("In TestRestartProjector()")

	tc.KillProjector()
	time.Sleep(60 * time.Second)

	var indexName = "index_age"
	var bucketName = "default"

	docScanResults := datautility.ExpectedScanResponse_float64(docs, "age", 0, 90, 1)
	scanResults, err := secondaryindex.Range(indexName, bucketName, indexScanAddress, []interface{}{0}, []interface{}{90}, 1, true, defaultlimit, c.SessionConsistency, nil)
	FailTestIfError(err, "Error in scan", t)
	log.Printf("Len of expected and actual scan results are :  %d and %d", len(docScanResults), len(scanResults))
	err = tv.Validate(docScanResults, scanResults)
	FailTestIfError(err, "Error in scan result validation", t)
}

// Test with mutations delay wait of 15s
func TestDeleteDocsMutation(t *testing.T) {
	log.Printf("In TestDeleteDocsMutation()")
	var indexName = "index_age"
	var bucketName = "default"

	err := secondaryindex.CreateSecondaryIndex(indexName, bucketName, indexManagementAddress, "", []string{"age"}, false, nil, true, defaultIndexActiveTimeout, nil)
	FailTestIfError(err, "Error in creating the index", t)

	docScanResults := datautility.ExpectedScanResponse_float64(docs, "age", 0, 90, 1)
	scanResults, err := secondaryindex.Range(indexName, bucketName, indexScanAddress, []interface{}{0}, []interface{}{90}, 1, true, defaultlimit, c.SessionConsistency, nil)
	FailTestIfError(err, "Error in scan", t)
	log.Printf("Len of expected and actual scan results are :  %d and %d", len(docScanResults), len(scanResults))
	err = tv.Validate(docScanResults, scanResults)
	FailTestIfError(err, "Error in scan result validation", t)

	//Delete docs mutations:  Delete docs from KV
	DeleteDocs(200)

	docScanResults = datautility.ExpectedScanResponse_float64(docs, "age", 0, 90, 1)
	start := time.Now()
	scanResults, err = secondaryindex.Range(indexName, bucketName, indexScanAddress, []interface{}{0}, []interface{}{90}, 1, true, defaultlimit, c.SessionConsistency, nil)
	elapsed := time.Since(start)
	log.Printf("Index Scan after mutations took %s\n", elapsed)
	FailTestIfError(err, "Error in scan", t)
	log.Printf("Len of expected and actual scan results are :  %d and %d", len(docScanResults), len(scanResults))
	err = tv.Validate(docScanResults, scanResults)
	FailTestIfError(err, "Error in scan result validation", t)
}

// Test with mutations delay wait of 15s
func TestUpdateDocsMutation(t *testing.T) {
	log.Printf("In TestUpdateDocsMutation()")
	var indexName = "index_age"
	var bucketName = "default"

	err := secondaryindex.CreateSecondaryIndex(indexName, bucketName, indexManagementAddress, "", []string{"age"}, false, nil, true, defaultIndexActiveTimeout, nil)
	FailTestIfError(err, "Error in creating the index", t)

	docScanResults := datautility.ExpectedScanResponse_float64(docs, "age", 20, 40, 2)
	scanResults, err := secondaryindex.Range(indexName, bucketName, indexScanAddress, []interface{}{20}, []interface{}{40}, 2, true, defaultlimit, c.SessionConsistency, nil)
	FailTestIfError(err, "Error in scan", t)
	log.Printf("Len of expected and actual scan results are :  %d and %d", len(docScanResults), len(scanResults))
	err = tv.Validate(docScanResults, scanResults)
	FailTestIfError(err, "Error in scan result validation", t)

	//Update docs mutations:  Update docs in KV
	UpdateDocs(100)

	docScanResults = datautility.ExpectedScanResponse_float64(docs, "age", 20, 40, 2)
	start := time.Now()
	scanResults, err = secondaryindex.Range(indexName, bucketName, indexScanAddress, []interface{}{20}, []interface{}{40}, 2, true, defaultlimit, c.SessionConsistency, nil)
	elapsed := time.Since(start)
	log.Printf("Index Scan after mutations took %s\n", elapsed)
	FailTestIfError(err, "Error in scan", t)
	log.Printf("Len of expected and actual scan results are :  %d and %d", len(docScanResults), len(scanResults))
	err = tv.Validate(docScanResults, scanResults)
	FailTestIfError(err, "Error in scan result validation", t)
}

// Test with large number of mutations
func TestLargeMutations(t *testing.T) {
	log.Printf("In TestLargeMutations()")
	var index1 = "indexmut_1"
	var index2 = "indexmut_2"
	var bucketName = "default"
	var field1 = "company"
	var field2 = "gender"

	// e := secondaryindex.DropAllSecondaryIndexes(indexManagementAddress)
	// FailTestIfError(e, "Error in DropAllSecondaryIndexes", t)

	docsToCreate := generateDocs(20000, "users.prod")
	UpdateKVDocs(docsToCreate, docs)
	kv.SetKeyValues(docsToCreate, "default", "", clusterconfig.KVAddress)

	err := secondaryindex.CreateSecondaryIndex(index1, bucketName, indexManagementAddress, "", []string{field1}, false, nil, true, defaultIndexActiveTimeout, nil)
	FailTestIfError(err, "Error in creating the index", t)

	docScanResults := datautility.ExpectedScanAllResponse(docs, field1)
	scanResults, err := secondaryindex.ScanAll(index1, bucketName, indexScanAddress, defaultlimit, c.SessionConsistency, nil)
	FailTestIfError(err, "Error in scan", t)
	err = tv.Validate(docScanResults, scanResults)
	FailTestIfError(err, "Error in scan result validation", t)
	log.Printf("Len of expected and actual scan results are :  %d and %d", len(docScanResults), len(scanResults))

	for i := 0; i <= 10; i++ {
		log.Printf("ITERATION %v\n", i)

		docsToCreate = generateDocs(10000, "users.prod")
		UpdateKVDocs(docsToCreate, docs)
		kv.SetKeyValues(docsToCreate, "default", "", clusterconfig.KVAddress)

		err := secondaryindex.CreateSecondaryIndex(index2, bucketName, indexManagementAddress, "", []string{field2}, false, nil, true, defaultIndexActiveTimeout, nil)
		FailTestIfError(err, "Error in creating the index", t)

		docScanResults = datautility.ExpectedScanAllResponse(docs, field1)
		scanResults, err = secondaryindex.ScanAll(index1, bucketName, indexScanAddress, defaultlimit, c.SessionConsistency, nil)
		FailTestIfError(err, "Error in scan", t)
		err = tv.Validate(docScanResults, scanResults)
		FailTestIfError(err, "Error in scan result validation", t)
		log.Printf("Len of expected and actual scan results are :  %d and %d", len(docScanResults), len(scanResults))

		docScanResults = datautility.ExpectedScanAllResponse(docs, field2)
		scanResults, err = secondaryindex.ScanAll(index2, bucketName, indexScanAddress, defaultlimit, c.SessionConsistency, nil)
		FailTestIfError(err, "Error in scan", t)
		err = tv.Validate(docScanResults, scanResults)
		FailTestIfError(err, "Error in scan result validation", t)
		log.Printf("Len of expected and actual scan results are :  %d and %d", len(docScanResults), len(scanResults))

		err = secondaryindex.DropSecondaryIndex(index2, bucketName, indexManagementAddress)
		FailTestIfError(err, "Error in drop index", t)
	}
}
<|endoftext|>


<commit_before>package vizzini_test

import (
	"crypto/tls"
	"crypto/x509"
	"errors"
	"fmt"
	"io/ioutil"
	"net/http"

	"code.cloudfoundry.org/bbs/models"
	"code.cloudfoundry.org/cfhttp"
	. "code.cloudfoundry.org/vizzini/matchers"

	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
)

var _ = Describe("TLS Proxy", func() {
	var (
		lrp       *models.DesiredLRP
		actualLRP models.ActualLRP
	)

	BeforeEach(func() {
		if !enableContainerProxyTests {
			Skip("container proxy tests are disabled")
		}

		lrp = DesiredLRPWithGuid(guid)
		Expect(bbsClient.DesireLRP(logger, lrp)).To(Succeed())
		actualGetterFn := ActualGetter(logger, guid, 0)
		Eventually(actualGetterFn).Should(BeActualLRPWithState(guid, 0, models.ActualLRPStateRunning))
		var err error
		actualLRP, err = actualGetterFn()
		Expect(err).NotTo(HaveOccurred())
	})

	It("proxies traffic to the application process inside the container", func() {
		directURL := "https://" + TLSDirectAddressFor(guid, 0, 8080)

		tlsConfig, err := containerProxyTLSConfig(actualLRP.InstanceGuid)
		Expect(err).NotTo(HaveOccurred())

		client := http.Client{
			Transport: &http.Transport{
				TLSClientConfig: tlsConfig,
			},
		}
		resp, err := client.Get(directURL)
		Expect(err).NotTo(HaveOccurred())
		defer resp.Body.Close()

		Expect(resp.StatusCode).To(Equal(http.StatusOK))
	})

	Describe("has a valid certificate", func() {
		var (
			certs []*x509.Certificate
		)

		BeforeEach(func() {
			tlsConfig, err := containerProxyTLSConfig(actualLRP.InstanceGuid)
			Expect(err).NotTo(HaveOccurred())

			conn, err := tls.Dial("tcp", TLSDirectAddressFor(guid, 0, 8080), tlsConfig)
			Expect(err).NotTo(HaveOccurred())

			err = conn.Handshake()
			Expect(err).NotTo(HaveOccurred())

			connState := conn.ConnectionState()
			Expect(connState.HandshakeComplete).To(BeTrue())
			certs = connState.PeerCertificates
			Expect(certs).To(HaveLen(2)) // the instance identity cert + CA
		})

		It("has a common name that matches the instance guid", func() {
			Expect(certs[0].Subject.CommonName).To(Equal(actualLRP.InstanceGuid))
		})
	})
})

func containerProxyTLSConfig(instanceGuid string) (*tls.Config, error) {
	caCertPool := x509.NewCertPool()
	if proxyCA == "" {
		return nil, errors.New("proxy CA file not provided")
	}
	certBytes, err := ioutil.ReadFile(proxyCA)
	if err != nil {
		return nil, fmt.Errorf("failed read ca cert file: %s", err.Error())
	}

	if ok := caCertPool.AppendCertsFromPEM(certBytes); !ok {
		return nil, errors.New("unable to load ca cert")
	}

	tlsConfig := &tls.Config{
		RootCAs: caCertPool,
	}

	if proxyClientCert != "" && proxyClientKey != "" {
		tlsConfig, err = cfhttp.NewTLSConfigWithCertPool(proxyClientCert, proxyClientKey, caCertPool)
		if err != nil {
			return nil, err
		}
	}
	tlsConfig.ServerName = instanceGuid

	return tlsConfig, nil
}
<commit_msg>used tlsconfig to set tls.Config<commit_after>package vizzini_test

import (
	"crypto/tls"
	"crypto/x509"
	"errors"
	"fmt"
	"io/ioutil"
	"net/http"

	"code.cloudfoundry.org/bbs/models"
	"code.cloudfoundry.org/tlsconfig"
	. "code.cloudfoundry.org/vizzini/matchers"

	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
)

var _ = Describe("TLS Proxy", func() {
	var (
		lrp       *models.DesiredLRP
		actualLRP models.ActualLRP
	)

	BeforeEach(func() {
		if !enableContainerProxyTests {
			Skip("container proxy tests are disabled")
		}

		lrp = DesiredLRPWithGuid(guid)
		Expect(bbsClient.DesireLRP(logger, lrp)).To(Succeed())
		actualGetterFn := ActualGetter(logger, guid, 0)
		Eventually(actualGetterFn).Should(BeActualLRPWithState(guid, 0, models.ActualLRPStateRunning))
		var err error
		actualLRP, err = actualGetterFn()
		Expect(err).NotTo(HaveOccurred())
	})

	It("proxies traffic to the application process inside the container", func() {
		directURL := "https://" + TLSDirectAddressFor(guid, 0, 8080)

		tlsConfig, err := containerProxyTLSConfig(actualLRP.InstanceGuid)
		Expect(err).NotTo(HaveOccurred())

		client := http.Client{
			Transport: &http.Transport{
				TLSClientConfig: tlsConfig,
			},
		}
		resp, err := client.Get(directURL)
		Expect(err).NotTo(HaveOccurred())
		defer resp.Body.Close()

		Expect(resp.StatusCode).To(Equal(http.StatusOK))
	})

	Describe("has a valid certificate", func() {
		var (
			certs []*x509.Certificate
		)

		BeforeEach(func() {
			tlsConfig, err := containerProxyTLSConfig(actualLRP.InstanceGuid)
			Expect(err).NotTo(HaveOccurred())

			conn, err := tls.Dial("tcp", TLSDirectAddressFor(guid, 0, 8080), tlsConfig)
			Expect(err).NotTo(HaveOccurred())

			err = conn.Handshake()
			Expect(err).NotTo(HaveOccurred())

			connState := conn.ConnectionState()
			Expect(connState.HandshakeComplete).To(BeTrue())
			certs = connState.PeerCertificates
			Expect(certs).To(HaveLen(2)) // the instance identity cert + CA
		})

		It("has a common name that matches the instance guid", func() {
			Expect(certs[0].Subject.CommonName).To(Equal(actualLRP.InstanceGuid))
		})
	})
})

func containerProxyTLSConfig(instanceGuid string) (*tls.Config, error) {
	caCertPool := x509.NewCertPool()
	if proxyCA == "" {
		return nil, errors.New("proxy CA file not provided")
	}
	certBytes, err := ioutil.ReadFile(proxyCA)
	if err != nil {
		return nil, fmt.Errorf("failed read ca cert file: %s", err.Error())
	}

	if ok := caCertPool.AppendCertsFromPEM(certBytes); !ok {
		return nil, errors.New("unable to load ca cert")
	}

	tlsConfig := &tls.Config{
		RootCAs: caCertPool,
	}

	if proxyClientCert != "" && proxyClientKey != "" {
		tlsConfig, err = tlsconfig.Build(
			tlsconfig.WithInternalServiceDefaults(),
			tlsconfig.WithIdentityFromFile(proxyClientCert, proxyClientKey),
		).Server(
			tlsconfig.WithClientAuthentication(caCertPool),
		)
		if err != nil {
			return nil, err
		}
		tlsConfig.RootCAs = caCertPool // proxy operates as a client and server
	}
	tlsConfig.ServerName = instanceGuid

	return tlsConfig, nil
}
<|endoftext|>


<commit_before>// Copyright 2014 Google Inc. All rights reserved.
//
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file or at
// https://developers.google.com/open-source/licenses/bsd

// The timestamp tool prints timestamps in various formats.
package main

import (
	"flag"
	"fmt"
	"io"
	"os"
	"strconv"
	"time"

	"willnorris.com/go/newbase60"
)

const day = 24 * time.Hour
const year = 365 * day

// simple, readable time format.  Based off of Time.String() without subseconds
const stdFormat = "2006-01-02 15:04:05 -0700 MST"

var (
	epoch = time.Date(1970, 1, 1, 0, 0, 0, 0, time.UTC)

	// inputFormats identifies the time formats used to parse user input.
	inputFormats = []string{
		time.RFC3339,
		"2006-01-02",
		"2006-002",
		"2006-01-02T15:04:05",
		"2006-01-02 15:04:05",
	}

	//flags
	utc            = flag.Bool("utc", false, "parse times without timezones as UTC")
	printRFC3339   = flag.Bool("rfc3339", false, "print rfc 3339 timestamp only")
	printEpochDays = flag.Bool("epoch", false, "print sexigesimal epoch days only")
)

func usage() {
	const text = `timestamp is a tool for printing timestamps in various formats.

Usage:
  timestamp [-utc] [-rfc3339] [-epoch] [time]

timestamp will print the specified time in the following formats:
  - unix timestamp (number of seconds since January 1, 1970 UTC)
  - rfc 3339 timestamp in the specified timezone (if not UTC)
  - rfc 3339 timestamp in UTC
  - ordinal date (year and day of the year) in the specified timezone (if not UTC)
  - ordinal date (year and day of the year) in UTC
  - epoch days (number of days since January 1, 1970 UTC) as decimal and
    sexigesimal (newbase60) formatted. This is only printed if date is after
    1970-01-01, and is always calculated based on UTC time.

time can be specified as a full rfc 3339 timestamp, just the date component
(YYYY-MM-DD), or as an ordinal date (YYYY-DDD).  If no time is specified, the
current system time will be used.

time values without an explicit timezone will be interpreted as the local
system timezone unless the -utc flag is provided.

Flags:
`

	fmt.Fprintf(os.Stderr, text)
	flag.PrintDefaults()
}

func main() {
	flag.Usage = usage
	flag.Parse()

	loc := time.Local
	if *utc {
		loc = time.UTC
	}

	t, err := parseInput(flag.Arg(0), loc)
	if err != nil {
		fmt.Fprintf(os.Stderr, "%v\n\n", err)
	}

	printOutput(os.Stdout, t, loc)
}

func parseInput(s string, loc *time.Location) (t time.Time, err error) {
	if s == "" {
		return time.Now().In(loc), nil
	}

	if i, err := strconv.ParseInt(s, 10, 64); err == nil {
		// strip sub-second precision
		for i > 1e10 {
			i /= 10
		}
		return time.Unix(i, 0).In(loc), nil
	}

	for _, f := range inputFormats {
		if t, err := time.ParseInLocation(f, s, loc); err == nil {
			return t, nil
		}
	}

	i := newbase60.DecodeToInt(s)
	t = epoch.Add(time.Duration(i) * day)
	if t.Year() < 1970 || time.Now().Add(100*year).Year() < t.Year() {
		err = fmt.Errorf("Parsed %q as a newbase60 epoch date outside of normal bounds. This might be an error.", s)
	}
	return t, err
}

func printOutput(w io.Writer, t time.Time, loc *time.Location) {
	epochDays := int(t.UTC().Sub(epoch) / day)

	if *printRFC3339 {
		fmt.Fprint(w, t.Format(time.RFC3339))
		return
	}

	if *printEpochDays {
		fmt.Fprint(w, newbase60.EncodeInt(epochDays))
		return
	}

	fmt.Fprintf(w, "%s\n\n", t.Format(stdFormat))
	printTime(w, "Unix Timestamp", "%d", t.Unix())

	if t.Location() != time.UTC {
		printTime(w, "RFC 3339", "%s", t.Format(time.RFC3339))
	}
	printTime(w, "RFC 3339 (UTC)", "%s", t.UTC().Format(time.RFC3339))

	if t.Location() != time.UTC {
		printTime(w, "Ordinal Date", "%d-%03d", t.Year(), t.YearDay())
	}
	printTime(w, "Ordinal Date (UTC)", "%d-%03d", t.UTC().Year(), t.UTC().YearDay())

	if epochDays > 0 {
		printTime(w, "Epoch Days", "%d (%s)", epochDays, newbase60.EncodeInt(epochDays))
	}
}

func printTime(w io.Writer, name, format string, a ...interface{}) {
	fmt.Fprintf(w, "%-19s ", name+":")
	fmt.Fprintf(w, format+"\n", a...)
}
<commit_msg>timestamp: update docs and fmt style<commit_after>// Copyright 2014 Google Inc. All rights reserved.
//
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file or at
// https://developers.google.com/open-source/licenses/bsd

// The timestamp tool prints timestamps in various formats.
package main

import (
	"flag"
	"fmt"
	"io"
	"os"
	"strconv"
	"time"

	"willnorris.com/go/newbase60"
)

const day = 24 * time.Hour
const year = 365 * day

// simple, readable time format.  Based off of Time.String() without subseconds
const stdFormat = "2006-01-02 15:04:05 -0700 MST"

var (
	epoch = time.Date(1970, 1, 1, 0, 0, 0, 0, time.UTC)

	// inputFormats identifies the time formats used to parse user input.
	inputFormats = []string{
		time.RFC3339,
		"2006-01-02",
		"2006-002",
		"2006-01-02T15:04:05",
		"2006-01-02 15:04:05",
	}

	//flags
	utc            = flag.Bool("utc", false, "parse times without timezones as UTC")
	printRFC3339   = flag.Bool("rfc3339", false, "print rfc 3339 timestamp only")
	printEpochDays = flag.Bool("epoch", false, "print sexigesimal epoch days only")
)

func usage() {
	const text = `timestamp is a tool for printing timestamps in various formats.

Usage:
  timestamp [-utc] [-rfc3339] [-epoch] [time]

timestamp will print the specified time in the following formats:
  - unix timestamp (number of seconds since January 1, 1970 UTC)
  - rfc 3339 timestamp in the specified timezone (if not UTC)
  - rfc 3339 timestamp in UTC
  - ordinal date (year and day of the year) in the specified timezone (if not UTC)
  - ordinal date (year and day of the year) in UTC
  - epoch days (number of days since January 1, 1970 UTC) as decimal and
    sexigesimal (newbase60) formatted. This is only printed if date is after
    1970-01-01, and is always calculated based on UTC time.

time can be specified as a full rfc 3339 timestamp, just the date component
(YYYY-MM-DD), an ordinal date (YYYY-DDD), or as newbase60 encoded epoch days.
If no time is specified, the current system time will be used.

time values without an explicit timezone will be interpreted as the local
system timezone unless the -utc flag is provided.

Flags:
`

	fmt.Fprint(os.Stderr, text)
	flag.PrintDefaults()
}

func main() {
	flag.Usage = usage
	flag.Parse()

	loc := time.Local
	if *utc {
		loc = time.UTC
	}

	t, err := parseInput(flag.Arg(0), loc)
	if err != nil {
		fmt.Fprintf(os.Stderr, "%v\n\n", err)
	}

	printOutput(os.Stdout, t, loc)
}

func parseInput(s string, loc *time.Location) (t time.Time, err error) {
	if s == "" {
		return time.Now().In(loc), nil
	}

	if i, err := strconv.ParseInt(s, 10, 64); err == nil {
		// strip sub-second precision
		for i > 1e10 {
			i /= 10
		}
		return time.Unix(i, 0).In(loc), nil
	}

	for _, f := range inputFormats {
		if t, err := time.ParseInLocation(f, s, loc); err == nil {
			return t, nil
		}
	}

	i := newbase60.DecodeToInt(s)
	t = epoch.Add(time.Duration(i) * day)
	if t.Year() < 1970 || time.Now().Add(100*year).Year() < t.Year() {
		err = fmt.Errorf("Parsed %q as a newbase60 epoch date outside of normal bounds. This might be an error.", s)
	}
	return t, err
}

func printOutput(w io.Writer, t time.Time, loc *time.Location) {
	epochDays := int(t.UTC().Sub(epoch) / day)

	if *printRFC3339 {
		fmt.Fprint(w, t.Format(time.RFC3339))
		return
	}

	if *printEpochDays {
		fmt.Fprint(w, newbase60.EncodeInt(epochDays))
		return
	}

	fmt.Fprintf(w, "%s\n\n", t.Format(stdFormat))
	printTime(w, "Unix Timestamp", "%d", t.Unix())

	if t.Location() != time.UTC {
		printTime(w, "RFC 3339", "%s", t.Format(time.RFC3339))
	}
	printTime(w, "RFC 3339 (UTC)", "%s", t.UTC().Format(time.RFC3339))

	if t.Location() != time.UTC {
		printTime(w, "Ordinal Date", "%d-%03d", t.Year(), t.YearDay())
	}
	printTime(w, "Ordinal Date (UTC)", "%d-%03d", t.UTC().Year(), t.UTC().YearDay())

	if epochDays > 0 {
		printTime(w, "Epoch Days", "%d (%s)", epochDays, newbase60.EncodeInt(epochDays))
	}
}

func printTime(w io.Writer, name, format string, a ...interface{}) {
	fmt.Fprintf(w, "%-19s ", name+":")
	fmt.Fprintf(w, format+"\n", a...)
}
<|endoftext|>


<commit_before>package server

import (
	"fmt"
	"net/http"
	"net/http/httputil"
	"net/url"
)

// KapacitorProxy proxies requests to kapacitor using the path query parameter.
func (h *Service) KapacitorProxy(w http.ResponseWriter, r *http.Request) {
	srcID, err := paramID("id", r)
	if err != nil {
		Error(w, http.StatusUnprocessableEntity, err.Error(), h.Logger)
		return
	}

	id, err := paramID("kid", r)
	if err != nil {
		Error(w, http.StatusUnprocessableEntity, err.Error(), h.Logger)
		return
	}

	path := r.URL.Query().Get("path")
	if path == "" {
		Error(w, http.StatusUnprocessableEntity, "path query parameter required", h.Logger)
		return
	}

	ctx := r.Context()
	srv, err := h.ServersStore.Get(ctx, id)
	if err != nil || srv.SrcID != srcID {
		notFound(w, id, h.Logger)
		return
	}

	u, err := url.Parse(srv.URL)
	if err != nil {
		msg := fmt.Sprintf("Error parsing kapacitor url: %v", err)
		Error(w, http.StatusUnprocessableEntity, msg, h.Logger)
		return
	}

	u.Path = path

	director := func(req *http.Request) {
		req.URL = u
		// Because we are acting as a proxy, kapacitor needs to have the basic auth information set as
		// a header directly
		if srv.Username != "" && srv.Password != "" {
			req.SetBasicAuth(srv.Username, srv.Password)
		}
	}
	proxy := &httputil.ReverseProxy{
		Director: director,
	}
	proxy.ServeHTTP(w, r)
}

// KapacitorProxyPost proxies POST to kapacitor
func (h *Service) KapacitorProxyPost(w http.ResponseWriter, r *http.Request) {
	h.KapacitorProxy(w, r)
}

// KapacitorProxyPatch proxies PATCH to kapacitor
func (h *Service) KapacitorProxyPatch(w http.ResponseWriter, r *http.Request) {
	h.KapacitorProxy(w, r)
}

// KapacitorProxyGet proxies GET to kapacitor
func (h *Service) KapacitorProxyGet(w http.ResponseWriter, r *http.Request) {
	h.KapacitorProxy(w, r)
}

// KapacitorProxyDelete proxies DELETE to kapacitor
func (h *Service) KapacitorProxyDelete(w http.ResponseWriter, r *http.Request) {
	h.KapacitorProxy(w, r)
}
<commit_msg>Use the Host header from the original Kapacitor URL<commit_after>package server

import (
	"fmt"
	"net/http"
	"net/http/httputil"
	"net/url"
)

// KapacitorProxy proxies requests to kapacitor using the path query parameter.
func (h *Service) KapacitorProxy(w http.ResponseWriter, r *http.Request) {
	srcID, err := paramID("id", r)
	if err != nil {
		Error(w, http.StatusUnprocessableEntity, err.Error(), h.Logger)
		return
	}

	id, err := paramID("kid", r)
	if err != nil {
		Error(w, http.StatusUnprocessableEntity, err.Error(), h.Logger)
		return
	}

	path := r.URL.Query().Get("path")
	if path == "" {
		Error(w, http.StatusUnprocessableEntity, "path query parameter required", h.Logger)
		return
	}

	ctx := r.Context()
	srv, err := h.ServersStore.Get(ctx, id)
	if err != nil || srv.SrcID != srcID {
		notFound(w, id, h.Logger)
		return
	}

	u, err := url.Parse(srv.URL)
	if err != nil {
		msg := fmt.Sprintf("Error parsing kapacitor url: %v", err)
		Error(w, http.StatusUnprocessableEntity, msg, h.Logger)
		return
	}

	u.Path = path

	director := func(req *http.Request) {
		// Set the Host header of the original Kapacitor URL
		req.Host = u.Host

		req.URL = u
		// Because we are acting as a proxy, kapacitor needs to have the basic auth information set as
		// a header directly
		if srv.Username != "" && srv.Password != "" {
			req.SetBasicAuth(srv.Username, srv.Password)
		}
	}
	proxy := &httputil.ReverseProxy{
		Director: director,
	}
	proxy.ServeHTTP(w, r)
}

// KapacitorProxyPost proxies POST to kapacitor
func (h *Service) KapacitorProxyPost(w http.ResponseWriter, r *http.Request) {
	h.KapacitorProxy(w, r)
}

// KapacitorProxyPatch proxies PATCH to kapacitor
func (h *Service) KapacitorProxyPatch(w http.ResponseWriter, r *http.Request) {
	h.KapacitorProxy(w, r)
}

// KapacitorProxyGet proxies GET to kapacitor
func (h *Service) KapacitorProxyGet(w http.ResponseWriter, r *http.Request) {
	h.KapacitorProxy(w, r)
}

// KapacitorProxyDelete proxies DELETE to kapacitor
func (h *Service) KapacitorProxyDelete(w http.ResponseWriter, r *http.Request) {
	h.KapacitorProxy(w, r)
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"io"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"runtime"
	"strconv"
)

type FactorioServer struct {
	Cmd      *exec.Cmd
	Savefile string
	Latency  int  `json:"latency"`
	Port     int  `json:"port"`
	Running  bool `json:"running"`
	StdOut   io.ReadCloser
	StdErr   io.ReadCloser
	StdIn    io.WriteCloser
	Settings FactorioServerSettings
}

type FactorioServerSettings struct {
	Name                                 string   `json:"name"`
	Description                          string   `json:"description"`
	Tags                                 []string `json:"tags"`
	MaxPlayers                           int      `json:"max_players"`
	Visibility                           string   `json:"visibility"`
	Username                             string   `json:"username"`
	Password                             string   `json:"password"`
	Token                                string   `json:"token"`
	GamePassword                         string   `json:"game_password"`
	RequireUserVerification              bool     `json:"require_user_verification"`
	MaxUploadInKilobytesPerSecond        int      `json:"max_upload_in_kilobytes_per_second"`
	IgnorePlayerLimitForReturningPlayers bool     `json:"ignore_player_limit_for_returning_players"`
	AllowCommands                        string   `json:"allow_commands"`
	AutosaveInterval                     int      `json:"autosave_interval"`
	AutosaveSlots                        int      `json:"autosave_slots"`
	AfkAutoKickInterval                  int      `json:"afk_autokick_interval"`
	AutoPause                            bool     `json:"auto_pause"`
	OnlyAdminsCanPauseThegame            bool     `json:"only_admins_can_pause_the_game"`
	Admins                               []string `json:"admins"`
	AutosaveOnlyOnServer                 bool     `json:"autosave_only_on_server"`
}

func initFactorio() *FactorioServer {
	f := FactorioServer{}
	settingsFile := filepath.Join(config.FactorioDir, config.SettingsFile)

	if _, err := os.Stat(settingsFile); err == nil {
		// server-settings.json file exists
		settings, err := os.Open(settingsFile)
		defer settings.Close()
		if err != nil {
			log.Printf("Error in reading %s: %s", settingsFile, err)
		}

		settingsParser := json.NewDecoder(settings)
		if err = settingsParser.Decode(&f.Settings); err != nil {
			log.Printf("Error in reading %s: %s", settingsFile, err)
		}
		log.Printf("Loaded Factorio settings from %s, settings: %+v", settingsFile, &f.Settings)

	} else {
		// default settings from server-settings.example.json
		f.Settings = FactorioServerSettings{
			Name:                                 "Factorio",
			Description:                          "Created by Factorio Server Manager",
			Tags:                                 []string{},
			MaxPlayers:                           0,
			Visibility:                           "public",
			Username:                             "",
			Password:                             "",
			Token:                                "",
			GamePassword:                         "",
			RequireUserVerification:              true,
			MaxUploadInKilobytesPerSecond:        0,
			IgnorePlayerLimitForReturningPlayers: false,
			AllowCommands:                        "admins-only",
			AutosaveInterval:                     10,
			AutosaveSlots:                        5,
			AfkAutoKickInterval:                  0,
			AutosaveOnlyOnServer:                 true,
			AutoPause:                            true,
			OnlyAdminsCanPauseThegame:            true,
			Admins: []string{},
		}
		log.Printf("Loaded Default Factorio settings settings: %s", &f.Settings)
	}

	return &f
}

func (f *FactorioServer) Run() error {
	var err error

	data, err := json.MarshalIndent(f.Settings, "", "  ")
	if err != nil {
		log.Println("Failed to marshal FactorioServerSettings: ", err)
	} else {
		ioutil.WriteFile(filepath.Join(config.FactorioDir, "server-settings.json"), data, 0644)
	}

	args := []string{
		"--start-server", filepath.Join(config.FactorioSavesDir, f.Savefile),
		"--port", strconv.Itoa(f.Port),
		"--server-settings", filepath.Join(config.FactorioDir, "server-settings.json"),
	}

	log.Println("Starting server with command: ", config.FactorioBinary, args)

	f.Cmd = exec.Command(config.FactorioBinary, args...)

	f.StdOut, err = f.Cmd.StdoutPipe()
	if err != nil {
		log.Printf("Error opening stdout pipe: %s", err)
		return err
	}

	f.StdIn, err = f.Cmd.StdinPipe()
	if err != nil {
		log.Printf("Error opening stdin pipe: %s", err)
		return err
	}

	f.StdErr, err = f.Cmd.StderrPipe()
	if err != nil {
		log.Printf("Error opening stderr pipe: %s", err)
		return err
	}

	go io.Copy(os.Stdout, f.StdOut)
	go io.Copy(os.Stderr, f.StdErr)

	err = f.Cmd.Start()
	if err != nil {
		log.Printf("Error starting server process: %s", err)
		return err
	}

	f.Running = true

	err = f.Cmd.Wait()
	if err != nil {
		log.Printf("Command exited with error: %s", err)
		return err
	}

	return nil
}

func (f *FactorioServer) Stop() error {
	// TODO: Find an alternative to os.Kill on Windows. os.Interupt
	// is not implemented. Maps will not be saved.
	if runtime.GOOS == "windows" {
		err := f.Cmd.Process.Signal(os.Kill)
		if err != nil {
			log.Printf("Error sending SIGKILLL to Factorio process: %s", err)
			return err
		} else {
			f.Running = false
			log.Println("Sent SIGKILL to Factorio process. Factorio forced to exit.")
		}
	} else {
		err := f.Cmd.Process.Signal(os.Interrupt)
		if err != nil {
			log.Printf("Error sending SIGINT to Factorio process: %s", err)
			return err
		} else {
			f.Running = false
			log.Printf("Sent SIGINT to Factorio process. Factorio shutting down...")
		}
	}

	return nil
}
<commit_msg>moved defer after err<commit_after>package main

import (
	"encoding/json"
	"io"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"runtime"
	"strconv"
)

type FactorioServer struct {
	Cmd      *exec.Cmd
	Savefile string
	Latency  int  `json:"latency"`
	Port     int  `json:"port"`
	Running  bool `json:"running"`
	StdOut   io.ReadCloser
	StdErr   io.ReadCloser
	StdIn    io.WriteCloser
	Settings FactorioServerSettings
}

type FactorioServerSettings struct {
	Name                                 string   `json:"name"`
	Description                          string   `json:"description"`
	Tags                                 []string `json:"tags"`
	MaxPlayers                           int      `json:"max_players"`
	Visibility                           string   `json:"visibility"`
	Username                             string   `json:"username"`
	Password                             string   `json:"password"`
	Token                                string   `json:"token"`
	GamePassword                         string   `json:"game_password"`
	RequireUserVerification              bool     `json:"require_user_verification"`
	MaxUploadInKilobytesPerSecond        int      `json:"max_upload_in_kilobytes_per_second"`
	IgnorePlayerLimitForReturningPlayers bool     `json:"ignore_player_limit_for_returning_players"`
	AllowCommands                        string   `json:"allow_commands"`
	AutosaveInterval                     int      `json:"autosave_interval"`
	AutosaveSlots                        int      `json:"autosave_slots"`
	AfkAutoKickInterval                  int      `json:"afk_autokick_interval"`
	AutoPause                            bool     `json:"auto_pause"`
	OnlyAdminsCanPauseThegame            bool     `json:"only_admins_can_pause_the_game"`
	Admins                               []string `json:"admins"`
	AutosaveOnlyOnServer                 bool     `json:"autosave_only_on_server"`
}

func initFactorio() *FactorioServer {
	f := FactorioServer{}
	settingsFile := filepath.Join(config.FactorioDir, config.SettingsFile)

	if _, err := os.Stat(settingsFile); err == nil {
		// server-settings.json file exists
		settings, err := os.Open(settingsFile)
		if err != nil {
			log.Printf("Error in reading %s: %s", settingsFile, err)
		}
		defer settings.Close()

		settingsParser := json.NewDecoder(settings)
		if err = settingsParser.Decode(&f.Settings); err != nil {
			log.Printf("Error in reading %s: %s", settingsFile, err)
		}
		log.Printf("Loaded Factorio settings from %s, settings: %+v", settingsFile, &f.Settings)

	} else {
		// default settings from server-settings.example.json
		f.Settings = FactorioServerSettings{
			Name:                                 "Factorio",
			Description:                          "Created by Factorio Server Manager",
			Tags:                                 []string{},
			MaxPlayers:                           0,
			Visibility:                           "public",
			Username:                             "",
			Password:                             "",
			Token:                                "",
			GamePassword:                         "",
			RequireUserVerification:              true,
			MaxUploadInKilobytesPerSecond:        0,
			IgnorePlayerLimitForReturningPlayers: false,
			AllowCommands:                        "admins-only",
			AutosaveInterval:                     10,
			AutosaveSlots:                        5,
			AfkAutoKickInterval:                  0,
			AutosaveOnlyOnServer:                 true,
			AutoPause:                            true,
			OnlyAdminsCanPauseThegame:            true,
			Admins: []string{},
		}
		log.Printf("Loaded Default Factorio settings settings: %s", &f.Settings)
	}

	return &f
}

func (f *FactorioServer) Run() error {
	var err error

	data, err := json.MarshalIndent(f.Settings, "", "  ")
	if err != nil {
		log.Println("Failed to marshal FactorioServerSettings: ", err)
	} else {
		ioutil.WriteFile(filepath.Join(config.FactorioDir, "server-settings.json"), data, 0644)
	}

	args := []string{
		"--start-server", filepath.Join(config.FactorioSavesDir, f.Savefile),
		"--port", strconv.Itoa(f.Port),
		"--server-settings", filepath.Join(config.FactorioDir, "server-settings.json"),
	}

	log.Println("Starting server with command: ", config.FactorioBinary, args)

	f.Cmd = exec.Command(config.FactorioBinary, args...)

	f.StdOut, err = f.Cmd.StdoutPipe()
	if err != nil {
		log.Printf("Error opening stdout pipe: %s", err)
		return err
	}

	f.StdIn, err = f.Cmd.StdinPipe()
	if err != nil {
		log.Printf("Error opening stdin pipe: %s", err)
		return err
	}

	f.StdErr, err = f.Cmd.StderrPipe()
	if err != nil {
		log.Printf("Error opening stderr pipe: %s", err)
		return err
	}

	go io.Copy(os.Stdout, f.StdOut)
	go io.Copy(os.Stderr, f.StdErr)

	err = f.Cmd.Start()
	if err != nil {
		log.Printf("Error starting server process: %s", err)
		return err
	}

	f.Running = true

	err = f.Cmd.Wait()
	if err != nil {
		log.Printf("Command exited with error: %s", err)
		return err
	}

	return nil
}

func (f *FactorioServer) Stop() error {
	// TODO: Find an alternative to os.Kill on Windows. os.Interupt
	// is not implemented. Maps will not be saved.
	if runtime.GOOS == "windows" {
		err := f.Cmd.Process.Signal(os.Kill)
		if err != nil {
			log.Printf("Error sending SIGKILLL to Factorio process: %s", err)
			return err
		} else {
			f.Running = false
			log.Println("Sent SIGKILL to Factorio process. Factorio forced to exit.")
		}
	} else {
		err := f.Cmd.Process.Signal(os.Interrupt)
		if err != nil {
			log.Printf("Error sending SIGINT to Factorio process: %s", err)
			return err
		} else {
			f.Running = false
			log.Printf("Sent SIGINT to Factorio process. Factorio shutting down...")
		}
	}

	return nil
}
<|endoftext|>


<commit_before>package regression

import (
	"errors"
	"fmt"
	"math"
	"strconv"
	"strings"

	"gonum.org/v1/gonum/mat"
)

var (
	errNotEnoughData = errors.New("Not enough data points")
	errTooManyvars   = errors.New("Not enough observations to to support this many variables")
	errRegressionRun = errors.New("Regression has already been run")
)

type Regression struct {
	names             describe
	data              []*dataPoint
	coeff             map[int]float64
	R2                float64
	Varianceobserved  float64
	VariancePredicted float64
	initialised       bool
	Formula           string
	crosses           []featureCross
	hasRun            bool
}

type dataPoint struct {
	Observed  float64
	Variables []float64
	Predicted float64
	Error     float64
}

type describe struct {
	obs  string
	vars map[int]string
}

// Creates a new dataPoint
func DataPoint(obs float64, vars []float64) *dataPoint {
	return &dataPoint{Observed: obs, Variables: vars}
}

// Predict updates the "Predicted" value for the input dataPoint
func (r *Regression) Predict(vars []float64) (float64, error) {
	if !r.initialised {
		return 0, errNotEnoughData
	}

	// apply any features crosses to vars
	for _, cross := range r.crosses {
		vars = append(vars, cross.Calculate(vars)...)
	}

	p := r.Coeff(0)
	for j := 1; j < len(r.data[0].Variables)+1; j++ {
		p += r.Coeff(j) * vars[j-1]
	}
	return p, nil
}

// Set the name of the observed value
func (r *Regression) SetObserved(name string) {
	r.names.obs = name
}

// Get the name of the observed value
func (r *Regression) GetObserved() string {
	return r.names.obs
}

// Set the name of variable i
func (r *Regression) SetVar(i int, name string) {
	if len(r.names.vars) == 0 {
		r.names.vars = make(map[int]string, 5)
	}
	r.names.vars[i] = name
}

// Get the name of variable i
func (r *Regression) GetVar(i int) string {
	x := r.names.vars[i]
	if x == "" {
		s := []string{"X", strconv.Itoa(i)}
		return strings.Join(s, "")
	}
	return x
}

// Registers a feature cross to be applied to the data points.
func (r *Regression) AddCross(cross featureCross) {
	r.crosses = append(r.crosses, cross)
}

// Train the regression with some data points
func (r *Regression) Train(d ...*dataPoint) {
	r.data = append(r.data, d...)
	if len(r.data) > 2 {
		r.initialised = true
	}
}

// Apply any feature crosses, generating new observations and updating the data points, as well as
// populating variable names for the feature crosses.
// this should only be run once, as part of Run().
func (r *Regression) applyCrosses() {
	unusedVariableIndexCursor := len(r.data[0].Variables)
	for _, point := range r.data {
		for _, cross := range r.crosses {
			point.Variables = append(point.Variables, cross.Calculate(point.Variables)...)
		}
	}

	if len(r.names.vars) == 0 {
		r.names.vars = make(map[int]string, 5)
	}
	for _, cross := range r.crosses {
		unusedVariableIndexCursor += cross.ExtendNames(r.names.vars, unusedVariableIndexCursor)
	}
}

// Run the regression
func (r *Regression) Run() error {
	if !r.initialised {
		return errNotEnoughData
	}
	if r.hasRun {
		return errRegressionRun
	}

	//apply any features crosses
	r.applyCrosses()
	r.hasRun = true

	observations := len(r.data)
	numOfvars := len(r.data[0].Variables)

	if observations < (numOfvars + 1) {
		return errTooManyvars
	}

	// Create some blank variable space
	observed := mat.NewDense(observations, 1, nil)
	variables := mat.NewDense(observations, numOfvars+1, nil)

	for i := 0; i < observations; i++ {
		observed.Set(i, 0, r.data[i].Observed)
		for j := 0; j < numOfvars+1; j++ {
			if j == 0 {
				variables.Set(i, 0, 1)
			} else {
				variables.Set(i, j, r.data[i].Variables[j-1])
			}
		}
	}

	// Now run the regression
	_, n := variables.Dims() // cols
	qr := new(mat.QR)
	qr.Factorize(variables)
	q := qr.QTo(nil)
	reg := qr.RTo(nil)

	qtr := q.T()
	qtrd := mat.DenseCopyOf(qtr)
	qty := new(mat.Dense)
	qty.Mul(qtrd, observed)

	c := make([]float64, n)
	for i := n - 1; i >= 0; i-- {
		c[i] = qty.At(i, 0)
		for j := i + 1; j < n; j++ {
			c[i] -= c[j] * reg.At(i, j)
		}
		c[i] /= reg.At(i, i)
	}

	// Output the regression results
	r.coeff = make(map[int]float64, numOfvars)
	for i, val := range c {
		r.coeff[i] = val
		if i == 0 {
			r.Formula = fmt.Sprintf("Predicted = %.2f", val)
		} else {
			r.Formula += fmt.Sprintf(" + %v*%.2f", r.GetVar(i-1), val)
		}
	}

	r.calcPredicted()
	r.calcVariance()
	r.calcR2()
	return nil
}

// Return the calulated coefficient for variable i
func (r *Regression) Coeff(i int) float64 {
	if len(r.coeff) == 0 {
		return 0
	}
	return r.coeff[i]
}

func (r *Regression) calcPredicted() string {
	observations := len(r.data)
	var predicted float64
	var output string
	for i := 0; i < observations; i++ {
		r.data[i].Predicted, _ = r.Predict(r.data[i].Variables)
		r.data[i].Error = r.data[i].Predicted - r.data[i].Observed

		output += fmt.Sprintf("%v. observed = %v, Predicted = %v, Error = %v", i, r.data[i].Observed, predicted, r.data[i].Error)
	}
	return output
}

func (r *Regression) calcVariance() string {
	observations := len(r.data)
	var obtotal, prtotal, obvar, prvar float64
	for i := 0; i < observations; i++ {
		obtotal += r.data[i].Observed
		prtotal += r.data[i].Predicted
	}
	obaverage := obtotal / float64(observations)
	praverage := prtotal / float64(observations)

	for i := 0; i < observations; i++ {
		obvar += math.Pow(r.data[i].Observed-obaverage, 2)
		prvar += math.Pow(r.data[i].Predicted-praverage, 2)
	}
	r.Varianceobserved = obvar / float64(observations)
	r.VariancePredicted = prvar / float64(observations)
	return fmt.Sprintf("N = %v\nVariance observed = %v\nVariance Predicted = %v\n", observations, r.Varianceobserved, r.VariancePredicted)
}

func (r *Regression) calcR2() string {
	r.R2 = r.VariancePredicted / r.Varianceobserved
	return fmt.Sprintf("R2 = %.2f", r.R2)
}

func (r *Regression) calcResiduals() string {
	str := fmt.Sprintf("Residuals:\nobserved|\tPredicted|\tResidual\n")
	for _, d := range r.data {
		str += fmt.Sprintf("%.2f|\t%.2f|\t%.2f\n", d.Observed, d.Predicted, d.Observed-d.Predicted)
	}
	str += "\n"
	return str
}

// Display a dataPoint as a string
func (d *dataPoint) String() string {
	str := fmt.Sprintf("%.2f", d.Observed)
	for _, v := range d.Variables {
		str += fmt.Sprintf("|\t%.2f", v)
	}
	return str
}

// Display a regression as a string
func (r *Regression) String() string {
	if !r.initialised {
		return errNotEnoughData.Error()
	}
	str := fmt.Sprintf("%v", r.GetObserved())
	for i := 0; i < len(r.names.vars); i++ {
		str += fmt.Sprintf("|\t%v", r.GetVar(i))
	}
	str += "\n"
	for _, d := range r.data {
		str += fmt.Sprintf("%v\n", d)
	}
	fmt.Println(r.calcResiduals())
	str += fmt.Sprintf("\nN = %v\nVariance observed = %v\nVariance Predicted = %v", len(r.data), r.Varianceobserved, r.VariancePredicted)
	str += fmt.Sprintf("\nR2 = %v\n", r.R2)
	return str
}

// MakeDataPoints makes a `[]*dataPoint` from a `[][]float64`. The expected fomat for the input is a row-major [][]float64.
// That is to say the first slice represents a row, and the second represents the cols.
// Furthermore it is expected that all the col slices are of the same length.
// The obsIndex parameter indicates which column should be used
func MakeDataPoints(a [][]float64, obsIndex int) []*dataPoint {
	if obsIndex != 0 && obsIndex != len(a[0])-1 {
		return perverseMakeDataPoints(a, obsIndex)
	}

	retVal := make([]*dataPoint, 0, len(a))
	if obsIndex == 0 {
		for _, r := range a {
			retVal = append(retVal, DataPoint(r[0], r[1:]))
		}
		return retVal
	}

	// otherwise the observation is expected to be the last col
	last := len(a[0]) - 1
	for _, r := range a {
		retVal = append(retVal, DataPoint(r[last], r[:last]))
	}
	return retVal
}

func perverseMakeDataPoints(a [][]float64, obsIndex int) []*dataPoint {
	retVal := make([]*dataPoint, 0, len(a))
	for _, r := range a {
		obs := r[obsIndex]
		others := make([]float64, 0, len(r)-1)
		for i, c := range r {
			if i == obsIndex {
				continue
			}
			others = append(others, c)
		}
		retVal = append(retVal, DataPoint(obs, others))
	}
	return retVal
}
<commit_msg>Added exported DataPoints<commit_after>package regression

import (
	"errors"
	"fmt"
	"math"
	"strconv"
	"strings"

	"gonum.org/v1/gonum/mat"
)

var (
	errNotEnoughData = errors.New("Not enough data points")
	errTooManyvars   = errors.New("Not enough observations to to support this many variables")
	errRegressionRun = errors.New("Regression has already been run")
)

type Regression struct {
	names             describe
	data              []*dataPoint
	coeff             map[int]float64
	R2                float64
	Varianceobserved  float64
	VariancePredicted float64
	initialised       bool
	Formula           string
	crosses           []featureCross
	hasRun            bool
}

type dataPoint struct {
	Observed  float64
	Variables []float64
	Predicted float64
	Error     float64
}

type describe struct {
	obs  string
	vars map[int]string
}

// DataPoints is a slice of *dataPoint .
// This type allows for easier constuction of training data points
type DataPoints []*dataPoint

// Creates a new dataPoint
func DataPoint(obs float64, vars []float64) *dataPoint {
	return &dataPoint{Observed: obs, Variables: vars}
}

// Predict updates the "Predicted" value for the input dataPoint
func (r *Regression) Predict(vars []float64) (float64, error) {
	if !r.initialised {
		return 0, errNotEnoughData
	}

	// apply any features crosses to vars
	for _, cross := range r.crosses {
		vars = append(vars, cross.Calculate(vars)...)
	}

	p := r.Coeff(0)
	for j := 1; j < len(r.data[0].Variables)+1; j++ {
		p += r.Coeff(j) * vars[j-1]
	}
	return p, nil
}

// Set the name of the observed value
func (r *Regression) SetObserved(name string) {
	r.names.obs = name
}

// Get the name of the observed value
func (r *Regression) GetObserved() string {
	return r.names.obs
}

// Set the name of variable i
func (r *Regression) SetVar(i int, name string) {
	if len(r.names.vars) == 0 {
		r.names.vars = make(map[int]string, 5)
	}
	r.names.vars[i] = name
}

// Get the name of variable i
func (r *Regression) GetVar(i int) string {
	x := r.names.vars[i]
	if x == "" {
		s := []string{"X", strconv.Itoa(i)}
		return strings.Join(s, "")
	}
	return x
}

// Registers a feature cross to be applied to the data points.
func (r *Regression) AddCross(cross featureCross) {
	r.crosses = append(r.crosses, cross)
}

// Train the regression with some data points
func (r *Regression) Train(d ...*dataPoint) {
	r.data = append(r.data, d...)
	if len(r.data) > 2 {
		r.initialised = true
	}
}

// Apply any feature crosses, generating new observations and updating the data points, as well as
// populating variable names for the feature crosses.
// this should only be run once, as part of Run().
func (r *Regression) applyCrosses() {
	unusedVariableIndexCursor := len(r.data[0].Variables)
	for _, point := range r.data {
		for _, cross := range r.crosses {
			point.Variables = append(point.Variables, cross.Calculate(point.Variables)...)
		}
	}

	if len(r.names.vars) == 0 {
		r.names.vars = make(map[int]string, 5)
	}
	for _, cross := range r.crosses {
		unusedVariableIndexCursor += cross.ExtendNames(r.names.vars, unusedVariableIndexCursor)
	}
}

// Run the regression
func (r *Regression) Run() error {
	if !r.initialised {
		return errNotEnoughData
	}
	if r.hasRun {
		return errRegressionRun
	}

	//apply any features crosses
	r.applyCrosses()
	r.hasRun = true

	observations := len(r.data)
	numOfvars := len(r.data[0].Variables)

	if observations < (numOfvars + 1) {
		return errTooManyvars
	}

	// Create some blank variable space
	observed := mat.NewDense(observations, 1, nil)
	variables := mat.NewDense(observations, numOfvars+1, nil)

	for i := 0; i < observations; i++ {
		observed.Set(i, 0, r.data[i].Observed)
		for j := 0; j < numOfvars+1; j++ {
			if j == 0 {
				variables.Set(i, 0, 1)
			} else {
				variables.Set(i, j, r.data[i].Variables[j-1])
			}
		}
	}

	// Now run the regression
	_, n := variables.Dims() // cols
	qr := new(mat.QR)
	qr.Factorize(variables)
	q := qr.QTo(nil)
	reg := qr.RTo(nil)

	qtr := q.T()
	qtrd := mat.DenseCopyOf(qtr)
	qty := new(mat.Dense)
	qty.Mul(qtrd, observed)

	c := make([]float64, n)
	for i := n - 1; i >= 0; i-- {
		c[i] = qty.At(i, 0)
		for j := i + 1; j < n; j++ {
			c[i] -= c[j] * reg.At(i, j)
		}
		c[i] /= reg.At(i, i)
	}

	// Output the regression results
	r.coeff = make(map[int]float64, numOfvars)
	for i, val := range c {
		r.coeff[i] = val
		if i == 0 {
			r.Formula = fmt.Sprintf("Predicted = %.2f", val)
		} else {
			r.Formula += fmt.Sprintf(" + %v*%.2f", r.GetVar(i-1), val)
		}
	}

	r.calcPredicted()
	r.calcVariance()
	r.calcR2()
	return nil
}

// Return the calulated coefficient for variable i
func (r *Regression) Coeff(i int) float64 {
	if len(r.coeff) == 0 {
		return 0
	}
	return r.coeff[i]
}

func (r *Regression) calcPredicted() string {
	observations := len(r.data)
	var predicted float64
	var output string
	for i := 0; i < observations; i++ {
		r.data[i].Predicted, _ = r.Predict(r.data[i].Variables)
		r.data[i].Error = r.data[i].Predicted - r.data[i].Observed

		output += fmt.Sprintf("%v. observed = %v, Predicted = %v, Error = %v", i, r.data[i].Observed, predicted, r.data[i].Error)
	}
	return output
}

func (r *Regression) calcVariance() string {
	observations := len(r.data)
	var obtotal, prtotal, obvar, prvar float64
	for i := 0; i < observations; i++ {
		obtotal += r.data[i].Observed
		prtotal += r.data[i].Predicted
	}
	obaverage := obtotal / float64(observations)
	praverage := prtotal / float64(observations)

	for i := 0; i < observations; i++ {
		obvar += math.Pow(r.data[i].Observed-obaverage, 2)
		prvar += math.Pow(r.data[i].Predicted-praverage, 2)
	}
	r.Varianceobserved = obvar / float64(observations)
	r.VariancePredicted = prvar / float64(observations)
	return fmt.Sprintf("N = %v\nVariance observed = %v\nVariance Predicted = %v\n", observations, r.Varianceobserved, r.VariancePredicted)
}

func (r *Regression) calcR2() string {
	r.R2 = r.VariancePredicted / r.Varianceobserved
	return fmt.Sprintf("R2 = %.2f", r.R2)
}

func (r *Regression) calcResiduals() string {
	str := fmt.Sprintf("Residuals:\nobserved|\tPredicted|\tResidual\n")
	for _, d := range r.data {
		str += fmt.Sprintf("%.2f|\t%.2f|\t%.2f\n", d.Observed, d.Predicted, d.Observed-d.Predicted)
	}
	str += "\n"
	return str
}

// Display a dataPoint as a string
func (d *dataPoint) String() string {
	str := fmt.Sprintf("%.2f", d.Observed)
	for _, v := range d.Variables {
		str += fmt.Sprintf("|\t%.2f", v)
	}
	return str
}

// Display a regression as a string
func (r *Regression) String() string {
	if !r.initialised {
		return errNotEnoughData.Error()
	}
	str := fmt.Sprintf("%v", r.GetObserved())
	for i := 0; i < len(r.names.vars); i++ {
		str += fmt.Sprintf("|\t%v", r.GetVar(i))
	}
	str += "\n"
	for _, d := range r.data {
		str += fmt.Sprintf("%v\n", d)
	}
	fmt.Println(r.calcResiduals())
	str += fmt.Sprintf("\nN = %v\nVariance observed = %v\nVariance Predicted = %v", len(r.data), r.Varianceobserved, r.VariancePredicted)
	str += fmt.Sprintf("\nR2 = %v\n", r.R2)
	return str
}

// MakeDataPoints makes a `[]*dataPoint` from a `[][]float64`. The expected fomat for the input is a row-major [][]float64.
// That is to say the first slice represents a row, and the second represents the cols.
// Furthermore it is expected that all the col slices are of the same length.
// The obsIndex parameter indicates which column should be used
func MakeDataPoints(a [][]float64, obsIndex int) []*dataPoint {
	if obsIndex != 0 && obsIndex != len(a[0])-1 {
		return perverseMakeDataPoints(a, obsIndex)
	}

	retVal := make([]*dataPoint, 0, len(a))
	if obsIndex == 0 {
		for _, r := range a {
			retVal = append(retVal, DataPoint(r[0], r[1:]))
		}
		return retVal
	}

	// otherwise the observation is expected to be the last col
	last := len(a[0]) - 1
	for _, r := range a {
		retVal = append(retVal, DataPoint(r[last], r[:last]))
	}
	return retVal
}

func perverseMakeDataPoints(a [][]float64, obsIndex int) []*dataPoint {
	retVal := make([]*dataPoint, 0, len(a))
	for _, r := range a {
		obs := r[obsIndex]
		others := make([]float64, 0, len(r)-1)
		for i, c := range r {
			if i == obsIndex {
				continue
			}
			others = append(others, c)
		}
		retVal = append(retVal, DataPoint(obs, others))
	}
	return retVal
}
<|endoftext|>


<commit_before>// Copyright (C) 2015 The Android Open Source Project
//
// 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 main

import (
	"archive/zip"
	"bufio"
	"bytes"
	"compress/gzip"
	"encoding/json"
	"errors"
	"flag"
	"io"
	"io/ioutil"
	"log"
	"net"
	"net/http"
	"net/url"
	"os"
	"path/filepath"
	"regexp"
	"strings"

	"golang.org/x/tools/godoc/vfs/httpfs"
	"golang.org/x/tools/godoc/vfs/zipfs"
)

var (
	plugins    = flag.String("plugins", "", "comma seperated plugin paths to serve")
	port       = flag.String("port", ":8081", "Port to serve HTTP requests on")
	host       = flag.String("host", "gerrit-review.googlesource.com", "Host to proxy requests to")
	scheme     = flag.String("scheme", "https", "URL scheme")
	cdnPattern = regexp.MustCompile("https://cdn.googlesource.com/polygerrit_ui/[0-9.]*")
)

func main() {
	flag.Parse()

	fontsArchive, err := openDataArchive("fonts.zip")
	if err != nil {
		log.Fatal(err)
	}

	componentsArchive, err := openDataArchive("app/test_components.zip")
	if err != nil {
		log.Fatal(err)
	}

	workspace := os.Getenv("BUILD_WORKSPACE_DIRECTORY")
	if err := os.Chdir(filepath.Join(workspace, "polygerrit-ui")); err != nil {
		log.Fatal(err)
	}

	http.Handle("/", http.FileServer(http.Dir("app")))
	http.Handle("/bower_components/",
		http.FileServer(httpfs.New(zipfs.New(componentsArchive, "bower_components"))))
	http.Handle("/fonts/",
		http.FileServer(httpfs.New(zipfs.New(fontsArchive, "fonts"))))

	http.HandleFunc("/index.html", handleIndex)
	http.HandleFunc("/changes/", handleProxy)
	http.HandleFunc("/accounts/", handleProxy)
	http.HandleFunc("/config/", handleProxy)
	http.HandleFunc("/projects/", handleProxy)
	http.HandleFunc("/static/", handleProxy)
	http.HandleFunc("/accounts/self/detail", handleAccountDetail)

	if len(*plugins) > 0 {
		http.Handle("/plugins/", http.StripPrefix("/plugins/",
			http.FileServer(http.Dir("../plugins"))))
		log.Println("Local plugins from", "../plugins")
	} else {
		http.HandleFunc("/plugins/", handleProxy)
	}
	log.Println("Serving on port", *port)
	log.Fatal(http.ListenAndServe(*port, &server{}))
}

func openDataArchive(path string) (*zip.ReadCloser, error) {
	absBinPath, err := resourceBasePath()
	if err != nil {
		return nil, err
	}
	return zip.OpenReader(absBinPath + ".runfiles/gerrit/polygerrit-ui/" + path)
}

func resourceBasePath() (string, error) {
	return filepath.Abs(os.Args[0])
}

func handleIndex(writer http.ResponseWriter, originalRequest *http.Request) {
	fakeRequest := &http.Request{
		URL: &url.URL{
			Path:     "/",
			RawQuery: originalRequest.URL.RawQuery,
		},
	}
	handleProxy(writer, fakeRequest)
}

func handleProxy(writer http.ResponseWriter, originalRequest *http.Request) {
	patchedRequest := &http.Request{
		Method: "GET",
		URL: &url.URL{
			Scheme:   *scheme,
			Host:     *host,
			Opaque:   originalRequest.URL.EscapedPath(),
			RawQuery: originalRequest.URL.RawQuery,
		},
	}
	response, err := http.DefaultClient.Do(patchedRequest)
	if err != nil {
		http.Error(writer, err.Error(), http.StatusInternalServerError)
		return
	}
	defer response.Body.Close()
	for name, values := range response.Header {
		for _, value := range values {
			if name != "Content-Length" {
				writer.Header().Add(name, value)
			}
		}
	}
	writer.WriteHeader(response.StatusCode)
	if _, err := io.Copy(writer, patchResponse(originalRequest, response)); err != nil {
		log.Println("Error copying response to ResponseWriter:", err)
		return
	}
}

func getJsonPropByPath(json map[string]interface{}, path []string) interface{} {
	prop, path := path[0], path[1:]
	if json[prop] == nil {
		return nil
	}
	switch json[prop].(type) {
	case map[string]interface{}: // map
		return getJsonPropByPath(json[prop].(map[string]interface{}), path)
	case []interface{}: // array
		return json[prop].([]interface{})
	default:
		return json[prop].(interface{})
	}
}

func setJsonPropByPath(json map[string]interface{}, path []string, value interface{}) {
	prop, path := path[0], path[1:]
	if json[prop] == nil {
		return // path not found
	}
	if len(path) > 0 {
		setJsonPropByPath(json[prop].(map[string]interface{}), path, value)
	} else {
		json[prop] = value
	}
}

func patchResponse(req *http.Request, res *http.Response) io.Reader {
	switch req.URL.EscapedPath() {
	case "/":
		return rewriteHostPage(res.Body)
	case "/config/server/info":
		return injectLocalPlugins(res.Body)
	default:
		return res.Body
	}
}

func rewriteHostPage(reader io.Reader) io.Reader {
	buf := new(bytes.Buffer)
	buf.ReadFrom(reader)
	original := buf.String()

	// Simply remove all CDN references, so files are loaded from the local file system  or the proxy
	// server instead.
	replaced := cdnPattern.ReplaceAllString(original, "")

	// Modify window.INITIAL_DATA so that it has the same effect as injectLocalPlugins. To achieve
	// this let's add JavaScript lines at the end of the <script>...</script> snippet that also
	// contains window.INITIAL_DATA=...
	// Here we rely on the fact that the <script> snippet that we want to append to is the first one.
	if len(*plugins) > 0 {
		insertionPoint := strings.Index(replaced, "</script>")
		builder := new(strings.Builder)
		builder.WriteString(
			"window.INITIAL_DATA['/config/server/info'].plugin.html_resource_paths = []; ")
		builder.WriteString(
			"window.INITIAL_DATA['/config/server/info'].plugin.js_resource_paths = []; ")
		for _, p := range strings.Split(*plugins, ",") {
			if filepath.Ext(p) == ".html" {
				builder.WriteString(
					"window.INITIAL_DATA['/config/server/info'].plugin.html_resource_paths.push('" + p + "'); ")
			}
			if filepath.Ext(p) == ".js" {
				builder.WriteString(
					"window.INITIAL_DATA['/config/server/info'].plugin.js_resource_paths.push('" + p + "'); ")
			}
		}
		replaced = replaced[:insertionPoint] + builder.String() + replaced[insertionPoint:]
	}

	return strings.NewReader(replaced)
}

func injectLocalPlugins(reader io.Reader) io.Reader {
	if len(*plugins) == 0 {
		return reader
	}
	// Skip escape prefix
	io.CopyN(ioutil.Discard, reader, 5)
	dec := json.NewDecoder(reader)

	var response map[string]interface{}
	err := dec.Decode(&response)
	if err != nil {
		log.Fatal(err)
	}

	// Configuration path in the JSON server response
	jsPluginsPath := []string{"plugin", "js_resource_paths"}
	htmlPluginsPath := []string{"plugin", "html_resource_paths"}
	htmlResources := getJsonPropByPath(response, htmlPluginsPath).([]interface{})
	jsResources := getJsonPropByPath(response, jsPluginsPath).([]interface{})

	for _, p := range strings.Split(*plugins, ",") {
		if filepath.Ext(p) == ".html" {
			htmlResources = append(htmlResources, p)
		}

		if filepath.Ext(p) == ".js" {
			jsResources = append(jsResources, p)
		}
	}

	setJsonPropByPath(response, jsPluginsPath, jsResources)
	setJsonPropByPath(response, htmlPluginsPath, htmlResources)

	reader, writer := io.Pipe()
	go func() {
		defer writer.Close()
		io.WriteString(writer, ")]}'") // Write escape prefix
		err := json.NewEncoder(writer).Encode(&response)
		if err != nil {
			log.Fatal(err)
		}
	}()
	return reader
}

func handleAccountDetail(w http.ResponseWriter, r *http.Request) {
	http.Error(w, http.StatusText(http.StatusForbidden), http.StatusForbidden)
}

type gzipResponseWriter struct {
	io.WriteCloser
	http.ResponseWriter
}

func newGzipResponseWriter(w http.ResponseWriter) *gzipResponseWriter {
	gz := gzip.NewWriter(w)
	return &gzipResponseWriter{WriteCloser: gz, ResponseWriter: w}
}

func (w gzipResponseWriter) Write(b []byte) (int, error) {
	return w.WriteCloser.Write(b)
}

func (w gzipResponseWriter) Hijack() (net.Conn, *bufio.ReadWriter, error) {
	h, ok := w.ResponseWriter.(http.Hijacker)
	if !ok {
		return nil, nil, errors.New("gzipResponseWriter: ResponseWriter does not satisfy http.Hijacker interface")
	}
	return h.Hijack()
}

type server struct{}

// Any path prefixes that should resolve to index.html.
var (
	fePaths    = []string{"/q/", "/c/", "/p/", "/x/", "/dashboard/", "/admin/", "/settings/"}
	issueNumRE = regexp.MustCompile(`^\/\d+\/?$`)
)

func (_ *server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	log.Printf("%s %s %s %s\n", r.Proto, r.Method, r.RemoteAddr, r.URL)
	for _, prefix := range fePaths {
		if strings.HasPrefix(r.URL.Path, prefix) || r.URL.Path == "/" {
			r.URL.Path = "/index.html"
			log.Println("Redirecting to /index.html")
			break
		} else if match := issueNumRE.Find([]byte(r.URL.Path)); match != nil {
			r.URL.Path = "/index.html"
			log.Println("Redirecting to /index.html")
			break
		}
	}
	if !strings.Contains(r.Header.Get("Accept-Encoding"), "gzip") {
		http.DefaultServeMux.ServeHTTP(w, r)
		return
	}
	w.Header().Set("Content-Encoding", "gzip")
	gzw := newGzipResponseWriter(w)
	defer gzw.Close()
	http.DefaultServeMux.ServeHTTP(gzw, r)
}
<commit_msg>Avoid loading plugin bundles when running locally<commit_after>// Copyright (C) 2015 The Android Open Source Project
//
// 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 main

import (
	"archive/zip"
	"bufio"
	"bytes"
	"compress/gzip"
	"encoding/json"
	"errors"
	"flag"
	"io"
	"io/ioutil"
	"log"
	"net"
	"net/http"
	"net/url"
	"os"
	"path/filepath"
	"regexp"
	"strings"

	"golang.org/x/tools/godoc/vfs/httpfs"
	"golang.org/x/tools/godoc/vfs/zipfs"
)

var (
	plugins               = flag.String("plugins", "", "comma seperated plugin paths to serve")
	port                  = flag.String("port", ":8081", "Port to serve HTTP requests on")
	host                  = flag.String("host", "gerrit-review.googlesource.com", "Host to proxy requests to")
	scheme                = flag.String("scheme", "https", "URL scheme")
	cdnPattern            = regexp.MustCompile("https://cdn.googlesource.com/polygerrit_ui/[0-9.]*")
	bundledPluginsPattern = regexp.MustCompile("https://cdn.googlesource.com/polygerrit_assets/[0-9.]*")
)

func main() {
	flag.Parse()

	fontsArchive, err := openDataArchive("fonts.zip")
	if err != nil {
		log.Fatal(err)
	}

	componentsArchive, err := openDataArchive("app/test_components.zip")
	if err != nil {
		log.Fatal(err)
	}

	workspace := os.Getenv("BUILD_WORKSPACE_DIRECTORY")
	if err := os.Chdir(filepath.Join(workspace, "polygerrit-ui")); err != nil {
		log.Fatal(err)
	}

	http.Handle("/", http.FileServer(http.Dir("app")))
	http.Handle("/bower_components/",
		http.FileServer(httpfs.New(zipfs.New(componentsArchive, "bower_components"))))
	http.Handle("/fonts/",
		http.FileServer(httpfs.New(zipfs.New(fontsArchive, "fonts"))))

	http.HandleFunc("/index.html", handleIndex)
	http.HandleFunc("/changes/", handleProxy)
	http.HandleFunc("/accounts/", handleProxy)
	http.HandleFunc("/config/", handleProxy)
	http.HandleFunc("/projects/", handleProxy)
	http.HandleFunc("/static/", handleProxy)
	http.HandleFunc("/accounts/self/detail", handleAccountDetail)

	if len(*plugins) > 0 {
		http.Handle("/plugins/", http.StripPrefix("/plugins/",
			http.FileServer(http.Dir("../plugins"))))
		log.Println("Local plugins from", "../plugins")
	} else {
		http.HandleFunc("/plugins/", handleProxy)
	}
	log.Println("Serving on port", *port)
	log.Fatal(http.ListenAndServe(*port, &server{}))
}

func openDataArchive(path string) (*zip.ReadCloser, error) {
	absBinPath, err := resourceBasePath()
	if err != nil {
		return nil, err
	}
	return zip.OpenReader(absBinPath + ".runfiles/gerrit/polygerrit-ui/" + path)
}

func resourceBasePath() (string, error) {
	return filepath.Abs(os.Args[0])
}

func handleIndex(writer http.ResponseWriter, originalRequest *http.Request) {
	fakeRequest := &http.Request{
		URL: &url.URL{
			Path:     "/",
			RawQuery: originalRequest.URL.RawQuery,
		},
	}
	handleProxy(writer, fakeRequest)
}

func handleProxy(writer http.ResponseWriter, originalRequest *http.Request) {
	patchedRequest := &http.Request{
		Method: "GET",
		URL: &url.URL{
			Scheme:   *scheme,
			Host:     *host,
			Opaque:   originalRequest.URL.EscapedPath(),
			RawQuery: originalRequest.URL.RawQuery,
		},
	}
	response, err := http.DefaultClient.Do(patchedRequest)
	if err != nil {
		http.Error(writer, err.Error(), http.StatusInternalServerError)
		return
	}
	defer response.Body.Close()
	for name, values := range response.Header {
		for _, value := range values {
			if name != "Content-Length" {
				writer.Header().Add(name, value)
			}
		}
	}
	writer.WriteHeader(response.StatusCode)
	if _, err := io.Copy(writer, patchResponse(originalRequest, response)); err != nil {
		log.Println("Error copying response to ResponseWriter:", err)
		return
	}
}

func getJsonPropByPath(json map[string]interface{}, path []string) interface{} {
	prop, path := path[0], path[1:]
	if json[prop] == nil {
		return nil
	}
	switch json[prop].(type) {
	case map[string]interface{}: // map
		return getJsonPropByPath(json[prop].(map[string]interface{}), path)
	case []interface{}: // array
		return json[prop].([]interface{})
	default:
		return json[prop].(interface{})
	}
}

func setJsonPropByPath(json map[string]interface{}, path []string, value interface{}) {
	prop, path := path[0], path[1:]
	if json[prop] == nil {
		return // path not found
	}
	if len(path) > 0 {
		setJsonPropByPath(json[prop].(map[string]interface{}), path, value)
	} else {
		json[prop] = value
	}
}

func patchResponse(req *http.Request, res *http.Response) io.Reader {
	switch req.URL.EscapedPath() {
	case "/":
		return rewriteHostPage(res.Body)
	case "/config/server/info":
		return injectLocalPlugins(res.Body)
	default:
		return res.Body
	}
}

func rewriteHostPage(reader io.Reader) io.Reader {
	buf := new(bytes.Buffer)
	buf.ReadFrom(reader)
	original := buf.String()

	// Simply remove all CDN references, so files are loaded from the local file system  or the proxy
	// server instead.
	replaced := cdnPattern.ReplaceAllString(original, "")

	// Modify window.INITIAL_DATA so that it has the same effect as injectLocalPlugins. To achieve
	// this let's add JavaScript lines at the end of the <script>...</script> snippet that also
	// contains window.INITIAL_DATA=...
	// Here we rely on the fact that the <script> snippet that we want to append to is the first one.
	if len(*plugins) > 0 {
		// If the host page contains a reference to a plugin bundle that would be preloaded, then remove it.
		replaced = bundledPluginsPattern.ReplaceAllString(replaced, "")

		insertionPoint := strings.Index(replaced, "</script>")
		builder := new(strings.Builder)
		builder.WriteString(
			"window.INITIAL_DATA['/config/server/info'].plugin.html_resource_paths = []; ")
		builder.WriteString(
			"window.INITIAL_DATA['/config/server/info'].plugin.js_resource_paths = []; ")
		for _, p := range strings.Split(*plugins, ",") {
			if filepath.Ext(p) == ".html" {
				builder.WriteString(
					"window.INITIAL_DATA['/config/server/info'].plugin.html_resource_paths.push('" + p + "'); ")
			}
			if filepath.Ext(p) == ".js" {
				builder.WriteString(
					"window.INITIAL_DATA['/config/server/info'].plugin.js_resource_paths.push('" + p + "'); ")
			}
		}
		replaced = replaced[:insertionPoint] + builder.String() + replaced[insertionPoint:]
	}

	return strings.NewReader(replaced)
}

func injectLocalPlugins(reader io.Reader) io.Reader {
	if len(*plugins) == 0 {
		return reader
	}
	// Skip escape prefix
	io.CopyN(ioutil.Discard, reader, 5)
	dec := json.NewDecoder(reader)

	var response map[string]interface{}
	err := dec.Decode(&response)
	if err != nil {
		log.Fatal(err)
	}

	// Configuration path in the JSON server response
	jsPluginsPath := []string{"plugin", "js_resource_paths"}
	htmlPluginsPath := []string{"plugin", "html_resource_paths"}
	htmlResources := getJsonPropByPath(response, htmlPluginsPath).([]interface{})
	jsResources := getJsonPropByPath(response, jsPluginsPath).([]interface{})

	for _, p := range strings.Split(*plugins, ",") {
		if filepath.Ext(p) == ".html" {
			htmlResources = append(htmlResources, p)
		}

		if filepath.Ext(p) == ".js" {
			jsResources = append(jsResources, p)
		}
	}

	setJsonPropByPath(response, jsPluginsPath, jsResources)
	setJsonPropByPath(response, htmlPluginsPath, htmlResources)

	reader, writer := io.Pipe()
	go func() {
		defer writer.Close()
		io.WriteString(writer, ")]}'") // Write escape prefix
		err := json.NewEncoder(writer).Encode(&response)
		if err != nil {
			log.Fatal(err)
		}
	}()
	return reader
}

func handleAccountDetail(w http.ResponseWriter, r *http.Request) {
	http.Error(w, http.StatusText(http.StatusForbidden), http.StatusForbidden)
}

type gzipResponseWriter struct {
	io.WriteCloser
	http.ResponseWriter
}

func newGzipResponseWriter(w http.ResponseWriter) *gzipResponseWriter {
	gz := gzip.NewWriter(w)
	return &gzipResponseWriter{WriteCloser: gz, ResponseWriter: w}
}

func (w gzipResponseWriter) Write(b []byte) (int, error) {
	return w.WriteCloser.Write(b)
}

func (w gzipResponseWriter) Hijack() (net.Conn, *bufio.ReadWriter, error) {
	h, ok := w.ResponseWriter.(http.Hijacker)
	if !ok {
		return nil, nil, errors.New("gzipResponseWriter: ResponseWriter does not satisfy http.Hijacker interface")
	}
	return h.Hijack()
}

type server struct{}

// Any path prefixes that should resolve to index.html.
var (
	fePaths    = []string{"/q/", "/c/", "/p/", "/x/", "/dashboard/", "/admin/", "/settings/"}
	issueNumRE = regexp.MustCompile(`^\/\d+\/?$`)
)

func (_ *server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	log.Printf("%s %s %s %s\n", r.Proto, r.Method, r.RemoteAddr, r.URL)
	for _, prefix := range fePaths {
		if strings.HasPrefix(r.URL.Path, prefix) || r.URL.Path == "/" {
			r.URL.Path = "/index.html"
			log.Println("Redirecting to /index.html")
			break
		} else if match := issueNumRE.Find([]byte(r.URL.Path)); match != nil {
			r.URL.Path = "/index.html"
			log.Println("Redirecting to /index.html")
			break
		}
	}
	if !strings.Contains(r.Header.Get("Accept-Encoding"), "gzip") {
		http.DefaultServeMux.ServeHTTP(w, r)
		return
	}
	w.Header().Set("Content-Encoding", "gzip")
	gzw := newGzipResponseWriter(w)
	defer gzw.Close()
	http.DefaultServeMux.ServeHTTP(gzw, r)
}
<|endoftext|>


<commit_before>package alias

import (
	"context"
	"fmt"
	"regexp"
	"strconv"
	"strings"

	"github.com/zetamatta/nyagos/completion"
	"github.com/zetamatta/nyagos/shell"
	"github.com/zetamatta/nyagos/texts"
)

var dbg = false

type callableT interface {
	String() string
	Call(ctx context.Context, cmd *shell.Cmd) (int, error)
}

type AliasFunc struct {
	BaseStr string
}

func New(baseStr string) *AliasFunc {
	return &AliasFunc{baseStr}
}

func (this *AliasFunc) String() string {
	return this.BaseStr
}

func (this *AliasFunc) Call(ctx context.Context, cmd *shell.Cmd) (next int, err error) {
	isReplaced := false
	if dbg {
		print("AliasFunc.Call('", cmd.Arg(0), "')\n")
	}
	cmdline := paramMatch.ReplaceAllStringFunc(this.BaseStr, func(s string) string {
		if s == "$~*" {
			isReplaced = true
			if cmd.Args() != nil && len(cmd.Args()) >= 2 {
				return strings.Join(cmd.Args()[1:], " ")
			} else {
				return ""
			}
		} else if s == "$*" {
			isReplaced = true
			if cmd.Args != nil && len(cmd.Args()) >= 2 {
				return strings.Join(cmd.RawArgs()[1:], " ")
			} else {
				return ""
			}
		} else if len(s) >= 3 && s[0] == '$' && s[1] == '~' && strings.IndexByte("0123456789", s[2]) >= 0 {
			i, err := strconv.ParseInt(s[2:], 10, 0)
			if err == nil {
				isReplaced = true
				if 0 <= i && cmd.Args() != nil && int(i) < len(cmd.Args()) {
					return cmd.Arg(int(i))
				} else {
					return ""
				}
			}
		}
		i, err := strconv.ParseInt(s[1:], 10, 0)
		if err == nil {
			isReplaced = true
			if 0 <= i && cmd.Args != nil && int(i) < len(cmd.Args()) {
				return cmd.RawArg(int(i))
			} else {
				return ""
			}
		}
		return s
	})

	if !isReplaced {
		var buffer strings.Builder
		buffer.WriteString(this.BaseStr)
		for _, s := range cmd.RawArgs()[1:] {
			fmt.Fprintf(&buffer, " %s", s)
		}
		cmdline = buffer.String()
	}
	if dbg {
		print("replaced cmdline=='", cmdline, "'\n")
		print("cmd.Clone\n")
	}
	it, err := cmd.Clone()
	if err != nil {
		return 255, err
	}
	if dbg {
		print("done cmd.Clone\n")
	}

	arg1 := texts.FirstWord(cmdline)
	if strings.EqualFold(arg1, cmd.Arg(0)) {
		it.HookCount = 100
	} else {
		it.HookCount = cmd.HookCount + 1
	}
	if dbg {
		print("it.Interpret\n")
	}
	next, err = it.Eval(ctx, cmdline)
	if dbg {
		print("done it.Interpret\n")
	}
	return
}

var Table = map[string]callableT{}
var paramMatch = regexp.MustCompile(`\$(\~)?(\*|[0-9]+)`)

func AllNames() []completion.Element {
	names := make([]completion.Element, 0, len(Table))
	for name1 := range Table {
		names = append(names, completion.Element{InsertStr: name1, ListupStr: name1})
	}
	return names
}

func quoteAndJoin(list []string) string {
	var buffer strings.Builder
	for i, value := range list {
		if i > 0 {
			buffer.WriteRune(' ')
		}
		if strings.IndexByte(value, ' ') >= 0 {
			fmt.Fprintf(&buffer, `"%s"`, value)
		} else {
			buffer.WriteString(value)
		}
	}
	return buffer.String()
}

var nextHook shell.HookT

func hook(ctx context.Context, cmd *shell.Cmd) (int, bool, error) {
	if cmd.HookCount > 5 {
		return nextHook(ctx, cmd)
	}
	callee, ok := Table[strings.ToLower(cmd.Arg(0))]
	if !ok {
		return nextHook(ctx, cmd)
	}
	next, err := callee.Call(ctx, cmd)
	return next, true, err
}

func Init() {
	nextHook = shell.SetHook(hook)
}
<commit_msg>Remove unused function: alias.quoteAndJoin()<commit_after>package alias

import (
	"context"
	"fmt"
	"regexp"
	"strconv"
	"strings"

	"github.com/zetamatta/nyagos/completion"
	"github.com/zetamatta/nyagos/shell"
	"github.com/zetamatta/nyagos/texts"
)

var dbg = false

type callableT interface {
	String() string
	Call(ctx context.Context, cmd *shell.Cmd) (int, error)
}

type AliasFunc struct {
	BaseStr string
}

func New(baseStr string) *AliasFunc {
	return &AliasFunc{baseStr}
}

func (this *AliasFunc) String() string {
	return this.BaseStr
}

func (this *AliasFunc) Call(ctx context.Context, cmd *shell.Cmd) (next int, err error) {
	isReplaced := false
	if dbg {
		print("AliasFunc.Call('", cmd.Arg(0), "')\n")
	}
	cmdline := paramMatch.ReplaceAllStringFunc(this.BaseStr, func(s string) string {
		if s == "$~*" {
			isReplaced = true
			if cmd.Args() != nil && len(cmd.Args()) >= 2 {
				return strings.Join(cmd.Args()[1:], " ")
			} else {
				return ""
			}
		} else if s == "$*" {
			isReplaced = true
			if cmd.Args != nil && len(cmd.Args()) >= 2 {
				return strings.Join(cmd.RawArgs()[1:], " ")
			} else {
				return ""
			}
		} else if len(s) >= 3 && s[0] == '$' && s[1] == '~' && strings.IndexByte("0123456789", s[2]) >= 0 {
			i, err := strconv.ParseInt(s[2:], 10, 0)
			if err == nil {
				isReplaced = true
				if 0 <= i && cmd.Args() != nil && int(i) < len(cmd.Args()) {
					return cmd.Arg(int(i))
				} else {
					return ""
				}
			}
		}
		i, err := strconv.ParseInt(s[1:], 10, 0)
		if err == nil {
			isReplaced = true
			if 0 <= i && cmd.Args != nil && int(i) < len(cmd.Args()) {
				return cmd.RawArg(int(i))
			} else {
				return ""
			}
		}
		return s
	})

	if !isReplaced {
		var buffer strings.Builder
		buffer.WriteString(this.BaseStr)
		for _, s := range cmd.RawArgs()[1:] {
			fmt.Fprintf(&buffer, " %s", s)
		}
		cmdline = buffer.String()
	}
	if dbg {
		print("replaced cmdline=='", cmdline, "'\n")
		print("cmd.Clone\n")
	}
	it, err := cmd.Clone()
	if err != nil {
		return 255, err
	}
	if dbg {
		print("done cmd.Clone\n")
	}

	arg1 := texts.FirstWord(cmdline)
	if strings.EqualFold(arg1, cmd.Arg(0)) {
		it.HookCount = 100
	} else {
		it.HookCount = cmd.HookCount + 1
	}
	if dbg {
		print("it.Interpret\n")
	}
	next, err = it.Eval(ctx, cmdline)
	if dbg {
		print("done it.Interpret\n")
	}
	return
}

var Table = map[string]callableT{}
var paramMatch = regexp.MustCompile(`\$(\~)?(\*|[0-9]+)`)

func AllNames() []completion.Element {
	names := make([]completion.Element, 0, len(Table))
	for name1 := range Table {
		names = append(names, completion.Element{InsertStr: name1, ListupStr: name1})
	}
	return names
}

var nextHook shell.HookT

func hook(ctx context.Context, cmd *shell.Cmd) (int, bool, error) {
	if cmd.HookCount > 5 {
		return nextHook(ctx, cmd)
	}
	callee, ok := Table[strings.ToLower(cmd.Arg(0))]
	if !ok {
		return nextHook(ctx, cmd)
	}
	next, err := callee.Call(ctx, cmd)
	return next, true, err
}

func Init() {
	nextHook = shell.SetHook(hook)
}
<|endoftext|>