<commit_before>// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package collate contains types for comparing and sorting Unicode strings
// according to a given collation order.  Package locale provides a high-level
// interface to collation. Users should typically use that package instead.
package collate

import (
	"bytes"
	"exp/norm"
)

// Level identifies the collation comparison level.
// The primary level corresponds to the basic sorting of text.
// The secondary level corresponds to accents and related linguistic elements.
// The tertiary level corresponds to casing and related concepts.
// The quaternary level is derived from the other levels by the
// various algorithms for handling variable elements.
type Level int

const (
	Primary Level = iota
	Secondary
	Tertiary
	Quaternary
	Identity
)

// AlternateHandling identifies the various ways in which variables are handled.
// A rune with a primary weight lower than the variable top is considered a
// variable.
// See http://www.unicode.org/reports/tr10/#Variable_Weighting for details.
type AlternateHandling int

const (
	// AltNonIgnorable turns off special handling of variables.
	AltNonIgnorable AlternateHandling = iota

	// AltBlanked sets variables and all subsequent primary ignorables to be
	// ignorable at all levels. This is identical to removing all variables
	// and subsequent primary ignorables from the input.
	AltBlanked

	// AltShifted sets variables to be ignorable for levels one through three and
	// adds a fourth level based on the values of the ignored levels.
	AltShifted

	// AltShiftTrimmed is a slight variant of AltShifted that is used to
	// emulate POSIX.
	AltShiftTrimmed
)

// Collator provides functionality for comparing strings for a given
// collation order.
type Collator struct {
	// Strength sets the maximum level to use in comparison.
	Strength Level

	// Alternate specifies an alternative handling of variables.
	Alternate AlternateHandling

	// Backwards specifies the order of sorting at the secondary level.
	// This option exists predominantly to support reverse sorting of accents in French.
	Backwards bool

	// TODO: implement:
	// With HiraganaQuaternary enabled, Hiragana codepoints will get lower values
	// than all the other non-variable code points. Strength must be greater or
	// equal to Quaternary for this to take effect.
	HiraganaQuaternary bool

	// If CaseLevel is true, a level consisting only of case characteristics will
	// be inserted in front of the tertiary level.  To ignore accents but take
	// cases into account, set Strength to Primary and CaseLevel to true.
	CaseLevel bool

	// If Numeric is true, any sequence of decimal digits (category is Nd) is sorted
	// at a primary level with its numeric value.  For example, "A-21" < "A-123".
	Numeric bool

	f norm.Form

	t *table
}

// Locales returns the list of locales for which collating differs from its parent locale.
func Locales() []string {
	return availableLocales
}

// New returns a new Collator initialized for the given locale.
func New(loc string) *Collator {
	// TODO: handle locale selection according to spec.
	t := &mainTable
	if loc != "" {
		if idx, ok := locales[loc]; ok {
			t = mainTable.indexedTable(idx)
		}
	}
	return &Collator{
		Strength: Quaternary,
		f:        norm.NFD,
		t:        t,
	}
}

// SetVariableTop sets all runes with primary strength less than the primary
// strength of r to be variable and thus affected by alternate handling.
func (c *Collator) SetVariableTop(r rune) {
	// TODO: implement
}

// Buffer holds reusable buffers that can be used during collation.
// Reusing a Buffer for the various calls that accept it may avoid
// unnecessary memory allocations.
type Buffer struct {
	// TODO: try various parameters and techniques, such as using
	// a chan of buffers for a pool.
	ba  [4096]byte
	wa  [512]weights
	key []byte
	ce  []weights
}

func (b *Buffer) init() {
	if b.ce == nil {
		b.ce = b.wa[:0]
		b.key = b.ba[:0]
	} else {
		b.ce = b.ce[:0]
	}
}

// ResetKeys clears the buffer used for generated keys. Calling ResetKeys
// invalidates keys previously obtained from Key or KeyFromString.
func (b *Buffer) ResetKeys() {
	b.ce = b.ce[:0]
	b.key = b.key[:0]
}

// Compare returns an integer comparing the two byte slices.
// The result will be 0 if a==b, -1 if a < b, and +1 if a > b.
// Compare calls ResetKeys, thereby invalidating keys
// previously generated using Key or KeyFromString using buf.
func (c *Collator) Compare(buf *Buffer, a, b []byte) int {
	// TODO: for now we simply compute keys and compare.  Once we
	// have good benchmarks, move to an implementation that works
	// incrementally for the majority of cases.
	// - Benchmark with long strings that only vary in modifiers.
	buf.ResetKeys()
	ka := c.Key(buf, a)
	kb := c.Key(buf, b)
	defer buf.ResetKeys()
	return bytes.Compare(ka, kb)
}

// CompareString returns an integer comparing the two strings.
// The result will be 0 if a==b, -1 if a < b, and +1 if a > b.
// CompareString calls ResetKeys, thereby invalidating keys
// previously generated using Key or KeyFromString using buf.
func (c *Collator) CompareString(buf *Buffer, a, b string) int {
	buf.ResetKeys()
	ka := c.KeyFromString(buf, a)
	kb := c.KeyFromString(buf, b)
	defer buf.ResetKeys()
	return bytes.Compare(ka, kb)
}

func (c *Collator) Prefix(buf *Buffer, s, prefix []byte) int {
	// iterate over s, track bytes consumed.
	return 0
}

// Key returns the collation key for str.
// Passing the buffer buf may avoid memory allocations.
// The returned slice will point to an allocation in Buffer and will remain
// valid until the next call to buf.ResetKeys().
func (c *Collator) Key(buf *Buffer, str []byte) []byte {
	// See http://www.unicode.org/reports/tr10/#Main_Algorithm for more details.
	buf.init()
	c.getColElems(buf, str)
	return c.key(buf, buf.ce)
}

// KeyFromString returns the collation key for str.
// Passing the buffer buf may avoid memory allocations.
// The returned slice will point to an allocation in Buffer and will retain
// valid until the next call to buf.ResetKeys().
func (c *Collator) KeyFromString(buf *Buffer, str string) []byte {
	// See http://www.unicode.org/reports/tr10/#Main_Algorithm for more details.
	buf.init()
	c.getColElemsString(buf, str)
	return c.key(buf, buf.ce)
}

func (c *Collator) key(buf *Buffer, w []weights) []byte {
	processWeights(c.Alternate, c.t.variableTop, w)
	kn := len(buf.key)
	c.keyFromElems(buf, w)
	return buf.key[kn:]
}

func (c *Collator) getColElems(buf *Buffer, str []byte) {
	i := c.iter()
	i.src.SetInput(c.f, str)
	for !i.done() {
		buf.ce = i.next(buf.ce)
	}
}

func (c *Collator) getColElemsString(buf *Buffer, str string) {
	i := c.iter()
	i.src.SetInputString(c.f, str)
	for !i.done() {
		buf.ce = i.next(buf.ce)
	}
}

type iter struct {
	src        norm.Iter
	ba         [1024]byte
	buf        []byte
	t          *table
	p          int
	minBufSize int
	_done, eof bool
}

func (c *Collator) iter() iter {
	i := iter{t: c.t, minBufSize: c.t.maxContractLen}
	i.buf = i.ba[:0]
	return i
}

func (i *iter) done() bool {
	return i._done
}

func (i *iter) next(ce []weights) []weights {
	if !i.eof && len(i.buf)-i.p < i.minBufSize {
		// replenish buffer
		n := copy(i.buf, i.buf[i.p:])
		n += i.src.Next(i.buf[n:cap(i.buf)])
		i.buf = i.buf[:n]
		i.p = 0
		i.eof = i.src.Done()
	}
	if i.p == len(i.buf) {
		i._done = true
		return ce
	}
	ce, sz := i.t.appendNext(ce, i.buf[i.p:])
	i.p += sz
	return ce
}

func appendPrimary(key []byte, p uint32) []byte {
	// Convert to variable length encoding; supports up to 23 bits.
	if p <= 0x7FFF {
		key = append(key, uint8(p>>8), uint8(p))
	} else {
		key = append(key, uint8(p>>16)|0x80, uint8(p>>8), uint8(p))
	}
	return key
}

// keyFromElems converts the weights ws to a compact sequence of bytes.
// The result will be appended to the byte buffer in buf.
func (c *Collator) keyFromElems(buf *Buffer, ws []weights) {
	for _, v := range ws {
		if w := v.primary; w > 0 {
			buf.key = appendPrimary(buf.key, w)
		}
	}
	if Secondary <= c.Strength {
		buf.key = append(buf.key, 0, 0)
		// TODO: we can use one 0 if we can guarantee that all non-zero weights are > 0xFF.
		if !c.Backwards {
			for _, v := range ws {
				if w := v.secondary; w > 0 {
					buf.key = append(buf.key, uint8(w>>8), uint8(w))
				}
			}
		} else {
			for i := len(ws) - 1; i >= 0; i-- {
				if w := ws[i].secondary; w > 0 {
					buf.key = append(buf.key, uint8(w>>8), uint8(w))
				}
			}
		}
	} else if c.CaseLevel {
		buf.key = append(buf.key, 0, 0)
	}
	if Tertiary <= c.Strength || c.CaseLevel {
		buf.key = append(buf.key, 0, 0)
		for _, v := range ws {
			if w := v.tertiary; w > 0 {
				buf.key = append(buf.key, w)
			}
		}
		// Derive the quaternary weights from the options and other levels.
		// Note that we represent maxQuaternary as 0xFF. The first byte of the
		// representation of a a primary weight is always smaller than 0xFF,
		// so using this single byte value will compare correctly.
		if Quaternary <= c.Strength {
			if c.Alternate == AltShiftTrimmed {
				lastNonFFFF := len(buf.key)
				buf.key = append(buf.key, 0)
				for _, v := range ws {
					if w := v.quaternary; w == maxQuaternary {
						buf.key = append(buf.key, 0xFF)
					} else if w > 0 {
						buf.key = appendPrimary(buf.key, w)
						lastNonFFFF = len(buf.key)
					}
				}
				buf.key = buf.key[:lastNonFFFF]
			} else {
				buf.key = append(buf.key, 0)
				for _, v := range ws {
					if w := v.quaternary; w == maxQuaternary {
						buf.key = append(buf.key, 0xFF)
					} else if w > 0 {
						buf.key = appendPrimary(buf.key, w)
					}
				}
			}
		}
	}
}

func processWeights(vw AlternateHandling, top uint32, wa []weights) {
	ignore := false
	switch vw {
	case AltShifted, AltShiftTrimmed:
		for i := range wa {
			if p := wa[i].primary; p <= top && p != 0 {
				wa[i] = weights{quaternary: p}
				ignore = true
			} else if p == 0 {
				if ignore {
					wa[i] = weights{}
				} else if wa[i].tertiary != 0 {
					wa[i].quaternary = maxQuaternary
				}
			} else {
				wa[i].quaternary = maxQuaternary
				ignore = false
			}
		}
	case AltBlanked:
		for i := range wa {
			if p := wa[i].primary; p <= top && (ignore || p != 0) {
				wa[i] = weights{}
				ignore = true
			} else {
				ignore = false
			}
		}
	}
}
<commit_msg>exp/locale/collate: clarification in comments on use of returned value.<commit_after>// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package collate contains types for comparing and sorting Unicode strings
// according to a given collation order.  Package locale provides a high-level
// interface to collation. Users should typically use that package instead.
package collate

import (
	"bytes"
	"exp/norm"
)

// Level identifies the collation comparison level.
// The primary level corresponds to the basic sorting of text.
// The secondary level corresponds to accents and related linguistic elements.
// The tertiary level corresponds to casing and related concepts.
// The quaternary level is derived from the other levels by the
// various algorithms for handling variable elements.
type Level int

const (
	Primary Level = iota
	Secondary
	Tertiary
	Quaternary
	Identity
)

// AlternateHandling identifies the various ways in which variables are handled.
// A rune with a primary weight lower than the variable top is considered a
// variable.
// See http://www.unicode.org/reports/tr10/#Variable_Weighting for details.
type AlternateHandling int

const (
	// AltNonIgnorable turns off special handling of variables.
	AltNonIgnorable AlternateHandling = iota

	// AltBlanked sets variables and all subsequent primary ignorables to be
	// ignorable at all levels. This is identical to removing all variables
	// and subsequent primary ignorables from the input.
	AltBlanked

	// AltShifted sets variables to be ignorable for levels one through three and
	// adds a fourth level based on the values of the ignored levels.
	AltShifted

	// AltShiftTrimmed is a slight variant of AltShifted that is used to
	// emulate POSIX.
	AltShiftTrimmed
)

// Collator provides functionality for comparing strings for a given
// collation order.
type Collator struct {
	// Strength sets the maximum level to use in comparison.
	Strength Level

	// Alternate specifies an alternative handling of variables.
	Alternate AlternateHandling

	// Backwards specifies the order of sorting at the secondary level.
	// This option exists predominantly to support reverse sorting of accents in French.
	Backwards bool

	// TODO: implement:
	// With HiraganaQuaternary enabled, Hiragana codepoints will get lower values
	// than all the other non-variable code points. Strength must be greater or
	// equal to Quaternary for this to take effect.
	HiraganaQuaternary bool

	// If CaseLevel is true, a level consisting only of case characteristics will
	// be inserted in front of the tertiary level.  To ignore accents but take
	// cases into account, set Strength to Primary and CaseLevel to true.
	CaseLevel bool

	// If Numeric is true, any sequence of decimal digits (category is Nd) is sorted
	// at a primary level with its numeric value.  For example, "A-21" < "A-123".
	Numeric bool

	f norm.Form

	t *table
}

// Locales returns the list of locales for which collating differs from its parent locale.
// The returned value should not be modified.
func Locales() []string {
	return availableLocales
}

// New returns a new Collator initialized for the given locale.
func New(loc string) *Collator {
	// TODO: handle locale selection according to spec.
	t := &mainTable
	if loc != "" {
		if idx, ok := locales[loc]; ok {
			t = mainTable.indexedTable(idx)
		}
	}
	return &Collator{
		Strength: Quaternary,
		f:        norm.NFD,
		t:        t,
	}
}

// SetVariableTop sets all runes with primary strength less than the primary
// strength of r to be variable and thus affected by alternate handling.
func (c *Collator) SetVariableTop(r rune) {
	// TODO: implement
}

// Buffer holds reusable buffers that can be used during collation.
// Reusing a Buffer for the various calls that accept it may avoid
// unnecessary memory allocations.
type Buffer struct {
	// TODO: try various parameters and techniques, such as using
	// a chan of buffers for a pool.
	ba  [4096]byte
	wa  [512]weights
	key []byte
	ce  []weights
}

func (b *Buffer) init() {
	if b.ce == nil {
		b.ce = b.wa[:0]
		b.key = b.ba[:0]
	} else {
		b.ce = b.ce[:0]
	}
}

// ResetKeys clears the buffer used for generated keys. Calling ResetKeys
// invalidates keys previously obtained from Key or KeyFromString.
func (b *Buffer) ResetKeys() {
	b.ce = b.ce[:0]
	b.key = b.key[:0]
}

// Compare returns an integer comparing the two byte slices.
// The result will be 0 if a==b, -1 if a < b, and +1 if a > b.
// Compare calls ResetKeys, thereby invalidating keys
// previously generated using Key or KeyFromString using buf.
func (c *Collator) Compare(buf *Buffer, a, b []byte) int {
	// TODO: for now we simply compute keys and compare.  Once we
	// have good benchmarks, move to an implementation that works
	// incrementally for the majority of cases.
	// - Benchmark with long strings that only vary in modifiers.
	buf.ResetKeys()
	ka := c.Key(buf, a)
	kb := c.Key(buf, b)
	defer buf.ResetKeys()
	return bytes.Compare(ka, kb)
}

// CompareString returns an integer comparing the two strings.
// The result will be 0 if a==b, -1 if a < b, and +1 if a > b.
// CompareString calls ResetKeys, thereby invalidating keys
// previously generated using Key or KeyFromString using buf.
func (c *Collator) CompareString(buf *Buffer, a, b string) int {
	buf.ResetKeys()
	ka := c.KeyFromString(buf, a)
	kb := c.KeyFromString(buf, b)
	defer buf.ResetKeys()
	return bytes.Compare(ka, kb)
}

func (c *Collator) Prefix(buf *Buffer, s, prefix []byte) int {
	// iterate over s, track bytes consumed.
	return 0
}

// Key returns the collation key for str.
// Passing the buffer buf may avoid memory allocations.
// The returned slice will point to an allocation in Buffer and will remain
// valid until the next call to buf.ResetKeys().
func (c *Collator) Key(buf *Buffer, str []byte) []byte {
	// See http://www.unicode.org/reports/tr10/#Main_Algorithm for more details.
	buf.init()
	c.getColElems(buf, str)
	return c.key(buf, buf.ce)
}

// KeyFromString returns the collation key for str.
// Passing the buffer buf may avoid memory allocations.
// The returned slice will point to an allocation in Buffer and will retain
// valid until the next call to buf.ResetKeys().
func (c *Collator) KeyFromString(buf *Buffer, str string) []byte {
	// See http://www.unicode.org/reports/tr10/#Main_Algorithm for more details.
	buf.init()
	c.getColElemsString(buf, str)
	return c.key(buf, buf.ce)
}

func (c *Collator) key(buf *Buffer, w []weights) []byte {
	processWeights(c.Alternate, c.t.variableTop, w)
	kn := len(buf.key)
	c.keyFromElems(buf, w)
	return buf.key[kn:]
}

func (c *Collator) getColElems(buf *Buffer, str []byte) {
	i := c.iter()
	i.src.SetInput(c.f, str)
	for !i.done() {
		buf.ce = i.next(buf.ce)
	}
}

func (c *Collator) getColElemsString(buf *Buffer, str string) {
	i := c.iter()
	i.src.SetInputString(c.f, str)
	for !i.done() {
		buf.ce = i.next(buf.ce)
	}
}

type iter struct {
	src        norm.Iter
	ba         [1024]byte
	buf        []byte
	t          *table
	p          int
	minBufSize int
	_done, eof bool
}

func (c *Collator) iter() iter {
	i := iter{t: c.t, minBufSize: c.t.maxContractLen}
	i.buf = i.ba[:0]
	return i
}

func (i *iter) done() bool {
	return i._done
}

func (i *iter) next(ce []weights) []weights {
	if !i.eof && len(i.buf)-i.p < i.minBufSize {
		// replenish buffer
		n := copy(i.buf, i.buf[i.p:])
		n += i.src.Next(i.buf[n:cap(i.buf)])
		i.buf = i.buf[:n]
		i.p = 0
		i.eof = i.src.Done()
	}
	if i.p == len(i.buf) {
		i._done = true
		return ce
	}
	ce, sz := i.t.appendNext(ce, i.buf[i.p:])
	i.p += sz
	return ce
}

func appendPrimary(key []byte, p uint32) []byte {
	// Convert to variable length encoding; supports up to 23 bits.
	if p <= 0x7FFF {
		key = append(key, uint8(p>>8), uint8(p))
	} else {
		key = append(key, uint8(p>>16)|0x80, uint8(p>>8), uint8(p))
	}
	return key
}

// keyFromElems converts the weights ws to a compact sequence of bytes.
// The result will be appended to the byte buffer in buf.
func (c *Collator) keyFromElems(buf *Buffer, ws []weights) {
	for _, v := range ws {
		if w := v.primary; w > 0 {
			buf.key = appendPrimary(buf.key, w)
		}
	}
	if Secondary <= c.Strength {
		buf.key = append(buf.key, 0, 0)
		// TODO: we can use one 0 if we can guarantee that all non-zero weights are > 0xFF.
		if !c.Backwards {
			for _, v := range ws {
				if w := v.secondary; w > 0 {
					buf.key = append(buf.key, uint8(w>>8), uint8(w))
				}
			}
		} else {
			for i := len(ws) - 1; i >= 0; i-- {
				if w := ws[i].secondary; w > 0 {
					buf.key = append(buf.key, uint8(w>>8), uint8(w))
				}
			}
		}
	} else if c.CaseLevel {
		buf.key = append(buf.key, 0, 0)
	}
	if Tertiary <= c.Strength || c.CaseLevel {
		buf.key = append(buf.key, 0, 0)
		for _, v := range ws {
			if w := v.tertiary; w > 0 {
				buf.key = append(buf.key, w)
			}
		}
		// Derive the quaternary weights from the options and other levels.
		// Note that we represent maxQuaternary as 0xFF. The first byte of the
		// representation of a a primary weight is always smaller than 0xFF,
		// so using this single byte value will compare correctly.
		if Quaternary <= c.Strength {
			if c.Alternate == AltShiftTrimmed {
				lastNonFFFF := len(buf.key)
				buf.key = append(buf.key, 0)
				for _, v := range ws {
					if w := v.quaternary; w == maxQuaternary {
						buf.key = append(buf.key, 0xFF)
					} else if w > 0 {
						buf.key = appendPrimary(buf.key, w)
						lastNonFFFF = len(buf.key)
					}
				}
				buf.key = buf.key[:lastNonFFFF]
			} else {
				buf.key = append(buf.key, 0)
				for _, v := range ws {
					if w := v.quaternary; w == maxQuaternary {
						buf.key = append(buf.key, 0xFF)
					} else if w > 0 {
						buf.key = appendPrimary(buf.key, w)
					}
				}
			}
		}
	}
}

func processWeights(vw AlternateHandling, top uint32, wa []weights) {
	ignore := false
	switch vw {
	case AltShifted, AltShiftTrimmed:
		for i := range wa {
			if p := wa[i].primary; p <= top && p != 0 {
				wa[i] = weights{quaternary: p}
				ignore = true
			} else if p == 0 {
				if ignore {
					wa[i] = weights{}
				} else if wa[i].tertiary != 0 {
					wa[i].quaternary = maxQuaternary
				}
			} else {
				wa[i].quaternary = maxQuaternary
				ignore = false
			}
		}
	case AltBlanked:
		for i := range wa {
			if p := wa[i].primary; p <= top && (ignore || p != 0) {
				wa[i] = weights{}
				ignore = true
			} else {
				ignore = false
			}
		}
	}
}
<|endoftext|>


<commit_before>//  Copyright (c) 2014 Couchbase, Inc.
//  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 cbft

import (
	"encoding/json"
	"fmt"
	"net/http"

	"github.com/gorilla/mux"
)

type CreateIndexHandler struct {
	mgr *Manager
}

func NewCreateIndexHandler(mgr *Manager) *CreateIndexHandler {
	return &CreateIndexHandler{mgr: mgr}
}

func (h *CreateIndexHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
	// TODO: Need more input validation (check the UUID's, name lengths, etc).
	indexType := req.FormValue("indexType")
	if indexType == "" {
		indexType = "bleve" // TODO: Revisit default indexType?  Should be table'ized?
	}

	// find the name of the index to create
	indexName := mux.Vars(req)["indexName"]
	if indexName == "" {
		showError(w, req, "index name is required", 400)
		return
	}

	// TODO: Need to validate indexParams based on the indexType.
	indexParams := req.FormValue("indexParams")

	sourceType := req.FormValue("sourceType")
	if sourceType == "" {
		sourceType = "couchbase" // TODO: Revisit default of sourceType as couchbase.
	}

	sourceName := req.FormValue("sourceName")
	if sourceName == "" {
		// NOTE: Some sourceTypes (like "nil") don't care if sourceName is "".
		if sourceType == "couchbase" {
			sourceName = indexName // TODO: Revisit default of sourceName as indexName.
		}
	}

	sourceUUID := req.FormValue("sourceUUID") // Defaults to "".

	// TODO: Need to validate sourceParams based on the sourceType.
	sourceParams := req.FormValue("sourceParams") // Defaults to "".

	planParams := &PlanParams{}
	planParamsStr := req.FormValue("planParams")
	if planParamsStr != "" {
		err := json.Unmarshal([]byte(planParamsStr), planParams)
		if err != nil {
			showError(w, req, fmt.Sprintf("error parsing planParams: %s, err: %v",
				planParamsStr, err), 400)
			return
		}
	}

	err := h.mgr.CreateIndex(sourceType, sourceName, sourceUUID, sourceParams,
		indexType, indexName, string(indexParams), *planParams)
	if err != nil {
		showError(w, req, fmt.Sprintf("error creating index: %s, err: %v",
			indexName, err), 400)
		return
	}

	mustEncode(w, struct {
		Status string `json:"status"`
	}{Status: "ok"})
}
<commit_msg>remove old TODO comments<commit_after>//  Copyright (c) 2014 Couchbase, Inc.
//  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 cbft

import (
	"encoding/json"
	"fmt"
	"net/http"

	"github.com/gorilla/mux"
)

type CreateIndexHandler struct {
	mgr *Manager
}

func NewCreateIndexHandler(mgr *Manager) *CreateIndexHandler {
	return &CreateIndexHandler{mgr: mgr}
}

func (h *CreateIndexHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
	// TODO: Need more input validation (check the UUID's, name lengths, etc).
	indexType := req.FormValue("indexType")
	if indexType == "" {
		indexType = "bleve" // TODO: Revisit default indexType?  Should be table'ized?
	}

	indexName := mux.Vars(req)["indexName"]
	if indexName == "" {
		showError(w, req, "index name is required", 400)
		return
	}

	indexParams := req.FormValue("indexParams")

	sourceType := req.FormValue("sourceType")
	if sourceType == "" {
		sourceType = "couchbase" // TODO: Revisit default of sourceType as couchbase.
	}

	sourceName := req.FormValue("sourceName")
	if sourceName == "" {
		// NOTE: Some sourceTypes (like "nil") don't care if sourceName is "".
		if sourceType == "couchbase" {
			sourceName = indexName // TODO: Revisit default of sourceName as indexName.
		}
	}

	sourceUUID := req.FormValue("sourceUUID") // Defaults to "".

	sourceParams := req.FormValue("sourceParams") // Defaults to "".

	planParams := &PlanParams{}
	planParamsStr := req.FormValue("planParams")
	if planParamsStr != "" {
		err := json.Unmarshal([]byte(planParamsStr), planParams)
		if err != nil {
			showError(w, req, fmt.Sprintf("error parsing planParams: %s, err: %v",
				planParamsStr, err), 400)
			return
		}
	}

	err := h.mgr.CreateIndex(sourceType, sourceName, sourceUUID, sourceParams,
		indexType, indexName, string(indexParams), *planParams)
	if err != nil {
		showError(w, req, fmt.Sprintf("error creating index: %s, err: %v",
			indexName, err), 400)
		return
	}

	mustEncode(w, struct {
		Status string `json:"status"`
	}{Status: "ok"})
}
<|endoftext|>


<commit_before>package bitclient

import (
	"fmt"
)

type GetProjectsResponse struct {
	PagedResponse
	Values []Project
}

func (bc *BitClient) GetProjects(params PagedRequest) (GetProjectsResponse, error) {

	response := GetProjectsResponse{}

	_, err := bc.DoGet(
		"/projects",
		params,
		&response,
	)

	return response, err
}

type GetRepositoriesResponse struct {
	PagedResponse
	Values []Repository
}

func (bc *BitClient) GetRepositories(projectKey string, params PagedRequest) (GetRepositoriesResponse, error) {

	response := GetRepositoriesResponse{}

	_, err := bc.DoGet(
		fmt.Sprintf("/rest/api/1.0/projects/%s/repos", projectKey),
		params,
		&response,
	)

	return response, err
}

type CreateRepositoryRequest struct {
	Name     string `json:"name"`
	ScmId    string `json:"scmId"`
	Forkable bool   `json:"forkable"`
}

func (bc *BitClient) CreateRepository(projectKey string, params CreateRepositoryRequest) (Repository, error) {

	response := Repository{}

	_, err := bc.DoPost(
		fmt.Sprintf("/rest/api/1.0/projects/%s/repos", projectKey),
		params,
		&response,
	)

	return response, err
}
<commit_msg>Fixed project method path<commit_after>package bitclient

import (
	"fmt"
)

type GetProjectsResponse struct {
	PagedResponse
	Values []Project
}

func (bc *BitClient) GetProjects(params PagedRequest) (GetProjectsResponse, error) {

	response := GetProjectsResponse{}

	_, err := bc.DoGet(
		"/projects",
		params,
		&response,
	)

	return response, err
}

type GetRepositoriesResponse struct {
	PagedResponse
	Values []Repository
}

func (bc *BitClient) GetRepositories(projectKey string, params PagedRequest) (GetRepositoriesResponse, error) {

	response := GetRepositoriesResponse{}

	_, err := bc.DoGet(
		fmt.Sprintf("/projects/%s/repos", projectKey),
		params,
		&response,
	)

	return response, err
}

type CreateRepositoryRequest struct {
	Name     string `json:"name"`
	ScmId    string `json:"scmId"`
	Forkable bool   `json:"forkable"`
}

func (bc *BitClient) CreateRepository(projectKey string, params CreateRepositoryRequest) (Repository, error) {

	response := Repository{}

	_, err := bc.DoPost(
		fmt.Sprintf("/projects/%s/repos", projectKey),
		params,
		&response,
	)

	return response, err
}
<|endoftext|>


<commit_before>package diffy

// ProjectsService contains Project related REST endpoints
//
// Gerrit API docs: https://gerrit-review.googlesource.com/Documentation/rest-api-projects.html
type ProjectsService struct {
	client *Client
}

// ProjectInfo entity contains information about a project.
//
// Gerrit API docs: https://gerrit-review.googlesource.com/Documentation/rest-api-projects.html#project-info
type ProjectInfo struct {
	ID          string            `json:"id"`
	Name        string            `json:"name"`
	Parent      string            `json:"parent"`
	Description string            `json:"description"`
	State       string            `json:"state"`
	Branches    map[string]string `json:"branches"`
	WebLinks    []WebLinkInfo     `json:"web_links"`
}

// ProjectInput entity contains information for the creation of a new project.
type ProjectInput struct {
	Name                             string                       `json:"name"`
	Parent                           string                       `json:"parent"`
	Description                      string                       `json:"description"`
	PermissionsOnly                  bool                         `json:"permissions_only"`
	CreateEmptyCommit                bool                         `json:"create_empty_commit"`
	SubmitType                       string                       `json:"submit_type"`
	Branches                         []string                     `json:"branches"`
	Owners                           []string                     `json:"owners"`
	UseContributorAgreements         string                       `json:"use_contributor_agreements"`
	UseSignedOffBy                   string                       `json:"use_signed_off_by"`
	CreateNewChangeForAllNotInTarget string                       `json:"create_new_change_for_all_not_in_target"`
	UseContentMerge                  string                       `json:"use_content_merge"`
	RequireChangeID                  string                       `json:"require_change_id"`
	MaxObjectSizeLimit               string                       `json:"max_object_size_limit"`
	PluginConfigValues               map[string]map[string]string `json:"plugin_config_values"`
}

// GCInput entity contains information to run the Git garbage collection.
type GCInput struct {
	ShowProgress bool `json:"show_progress"`
	Aggressive   bool `json:"aggressive"`
}

// HeadInput entity contains information for setting HEAD for a project.
type HeadInput struct {
	Ref string `json:"ref"`
}

// DeleteBranchesInput entity contains information about branches that should be deleted.
type DeleteBranchesInput struct {
	Branches []string `json:"DeleteBranchesInput"`
}

// DashboardSectionInfo entity contains information about a section in a dashboard.
type DashboardSectionInfo struct {
	Name  string `json:"name"`
	Query string `json:"query"`
}

// DashboardInput entity contains information to create/update a project dashboard.
type DashboardInput struct {
	ID            string `json:"id"`
	CommitMessage string `json:"commit_message"`
}

// DashboardInfo entity contains information about a project dashboard.
type DashboardInfo struct {
	ID              string                 `json:"id"`
	Project         string                 `json:"project"`
	DefiningProject string                 `json:"defining_project"`
	Ref             string                 `json:"ref"`
	Path            string                 `json:"path"`
	Description     string                 `json:"description"`
	Foreach         string                 `json:"foreach"`
	URL             string                 `json:"url"`
	Default         bool                   `json:"default"`
	Title           string                 `json:"title"`
	Sections        []DashboardSectionInfo `json:"sections"`
}

// BanInput entity contains information for banning commits in a project.
type BanInput struct {
	Commits []string `json:"commits"`
	Reason  string   `json:"reason"`
}

// BanResultInfo entity describes the result of banning commits.
type BanResultInfo struct {
	NewlyBanned   []string `json:"newly_banned"`
	AlreadyBanned []string `json:"already_banned"`
	Ignored       []string `json:"ignored"`
}

// BranchInfo entity contains information about a branch.
type BranchInfo struct {
	Ref       string        `json:"ref"`
	Revision  string        `json:"revision"`
	CanDelete bool          `json:"can_delete"`
	WebLinks  []WebLinkInfo `json:"web_links"`
}

// BranchInput entity contains information for the creation of a new branch.
type BranchInput struct {
	Ref      string `json:"ref"`
	Revision string `json:"revision"`
}

// ThemeInfo entity describes a theme.
type ThemeInfo struct {
	CSS    string `type:"css"`
	Header string `type:"header"`
	Footer string `type:"footer"`
}

// TagInfo entity contains information about a tag.
type TagInfo struct {
	Ref      string        `json:"ref"`
	Revision string        `json:"revision"`
	Object   string        `json:"object"`
	Message  string        `json:"message"`
	Tagger   GitPersonInfo `json:"tagger"`
}

// ReflogEntryInfo entity describes an entry in a reflog.
type ReflogEntryInfo struct {
	OldID   string        `json:"old_id"`
	NewID   string        `json:"new_id"`
	Who     GitPersonInfo `json:"who"`
	Comment string        `json:"comment"`
}

// ProjectParentInput entity contains information for setting a project parent.
type ProjectParentInput struct {
	Parent        string `json:"ProjectParentInput"`
	CommitMessage string `json:"commit_message"`
}

// RepositoryStatisticsInfo entity contains information about statistics of a Git repository.
type RepositoryStatisticsInfo struct {
	NumberOfLooseObjects  int `json:"number_of_loose_objects"`
	NumberOfLooseRefs     int `json:"number_of_loose_refs"`
	NumberOfPackFiles     int `json:"number_of_pack_files"`
	NumberOfPackedObjects int `json:"number_of_packed_objects"`
	NumberOfPackedRefs    int `json:"number_of_packed_refs"`
	SizeOfLooseObjects    int `json:"size_of_loose_objects"`
	SizeOfPackedObjects   int `json:"size_of_packed_objects"`
}

// InheritedBooleanInfo entity represents a boolean value that can also be inherited.
type InheritedBooleanInfo struct {
	Value           bool   `json:"value"`
	ConfiguredValue string `json:"configured_value"`
	InheritedValue  bool   `json:"inherited_value"`
}

// MaxObjectSizeLimitInfo entity contains information about the max object size limit of a project.
type MaxObjectSizeLimitInfo struct {
	Value           string `json:"value"`
	ConfiguredValue string `json:"configured_value"`
	InheritedValue  string `json:"inherited_value"`
}

// ConfigParameterInfo entity describes a project configuration parameter.
type ConfigParameterInfo struct {
	DisplayName string   `json:"display_name"`
	Description string   `json:"description"`
	Warning     string   `json:"warning"`
	Type        string   `json:"type"`
	Value       string   `json:"value"`
	Values      []string `json:"values"`
	// TODO: 5 fields are missing here, because the documentation seems to be fucked up
	// See https://gerrit-review.googlesource.com/Documentation/rest-api-projects.html#config-parameter-info
}

// ProjectDescriptionInput entity contains information for setting a project description.
type ProjectDescriptionInput struct {
	Description   string `json:"description"`
	CommitMessage string `json:"commit_message"`
}

// ConfigInfo entity contains information about the effective project configuration.
type ConfigInfo struct {
	Description                      string                         `json:"description"`
	UseContributorAgreements         InheritedBooleanInfo           `json:"use_contributor_agreements"`
	UseContentMerge                  InheritedBooleanInfo           `json:"use_content_merge"`
	UseSignedOffBy                   InheritedBooleanInfo           `json:"use_signed_off_by"`
	CreateNewChangeForAllNotInTarget InheritedBooleanInfo           `json:"create_new_change_for_all_not_in_target"`
	RequireChangeID                  InheritedBooleanInfo           `json:"require_change_id"`
	EnableSignedPush                 InheritedBooleanInfo           `json:"enable_signed_push"`
	MaxObjectSizeLimit               MaxObjectSizeLimitInfo         `json:"max_object_size_limit"`
	SubmitType                       string                         `json:"submit_type"`
	State                            string                         `json:"state"`
	Commentlinks                     map[string]string              `json:"commentlinks"`
	Theme                            ThemeInfo                      `json:"theme"`
	PluginConfig                     map[string]ConfigParameterInfo `json:"plugin_config"`
	Actions                          map[string]ActionInfo          `json:"actions"`
}

// ConfigInput entity describes a new project configuration.
type ConfigInput struct {
	Description                      string                       `json:"description"`
	UseContributorAgreements         string                       `json:"use_contributor_agreements"`
	UseContentMerge                  string                       `json:"use_content_merge"`
	UseSignedOffBy                   string                       `json:"use_signed_off_by"`
	CreateNewChangeForAllNotInTarget string                       `json:"create_new_change_for_all_not_in_target"`
	RequireChangeID                  string                       `json:"require_change_id"`
	MaxObjectSizeLimit               MaxObjectSizeLimitInfo       `json:"max_object_size_limit"`
	SubmitType                       string                       `json:"submit_type"`
	State                            string                       `json:"state"`
	PluginConfigValues               map[string]map[string]string `json:"plugin_config_values"`
}
<commit_msg>Added basic version of Projects.ListProjects<commit_after>package diffy

// ProjectsService contains Project related REST endpoints
//
// Gerrit API docs: https://gerrit-review.googlesource.com/Documentation/rest-api-projects.html
type ProjectsService struct {
	client *Client
}

// ProjectInfo entity contains information about a project.
//
// Gerrit API docs: https://gerrit-review.googlesource.com/Documentation/rest-api-projects.html#project-info
type ProjectInfo struct {
	ID          string            `json:"id"`
	Name        string            `json:"name"`
	Parent      string            `json:"parent"`
	Description string            `json:"description"`
	State       string            `json:"state"`
	Branches    map[string]string `json:"branches"`
	WebLinks    []WebLinkInfo     `json:"web_links"`
}

// ProjectInput entity contains information for the creation of a new project.
type ProjectInput struct {
	Name                             string                       `json:"name"`
	Parent                           string                       `json:"parent"`
	Description                      string                       `json:"description"`
	PermissionsOnly                  bool                         `json:"permissions_only"`
	CreateEmptyCommit                bool                         `json:"create_empty_commit"`
	SubmitType                       string                       `json:"submit_type"`
	Branches                         []string                     `json:"branches"`
	Owners                           []string                     `json:"owners"`
	UseContributorAgreements         string                       `json:"use_contributor_agreements"`
	UseSignedOffBy                   string                       `json:"use_signed_off_by"`
	CreateNewChangeForAllNotInTarget string                       `json:"create_new_change_for_all_not_in_target"`
	UseContentMerge                  string                       `json:"use_content_merge"`
	RequireChangeID                  string                       `json:"require_change_id"`
	MaxObjectSizeLimit               string                       `json:"max_object_size_limit"`
	PluginConfigValues               map[string]map[string]string `json:"plugin_config_values"`
}

// GCInput entity contains information to run the Git garbage collection.
type GCInput struct {
	ShowProgress bool `json:"show_progress"`
	Aggressive   bool `json:"aggressive"`
}

// HeadInput entity contains information for setting HEAD for a project.
type HeadInput struct {
	Ref string `json:"ref"`
}

// DeleteBranchesInput entity contains information about branches that should be deleted.
type DeleteBranchesInput struct {
	Branches []string `json:"DeleteBranchesInput"`
}

// DashboardSectionInfo entity contains information about a section in a dashboard.
type DashboardSectionInfo struct {
	Name  string `json:"name"`
	Query string `json:"query"`
}

// DashboardInput entity contains information to create/update a project dashboard.
type DashboardInput struct {
	ID            string `json:"id"`
	CommitMessage string `json:"commit_message"`
}

// DashboardInfo entity contains information about a project dashboard.
type DashboardInfo struct {
	ID              string                 `json:"id"`
	Project         string                 `json:"project"`
	DefiningProject string                 `json:"defining_project"`
	Ref             string                 `json:"ref"`
	Path            string                 `json:"path"`
	Description     string                 `json:"description"`
	Foreach         string                 `json:"foreach"`
	URL             string                 `json:"url"`
	Default         bool                   `json:"default"`
	Title           string                 `json:"title"`
	Sections        []DashboardSectionInfo `json:"sections"`
}

// BanInput entity contains information for banning commits in a project.
type BanInput struct {
	Commits []string `json:"commits"`
	Reason  string   `json:"reason"`
}

// BanResultInfo entity describes the result of banning commits.
type BanResultInfo struct {
	NewlyBanned   []string `json:"newly_banned"`
	AlreadyBanned []string `json:"already_banned"`
	Ignored       []string `json:"ignored"`
}

// BranchInfo entity contains information about a branch.
type BranchInfo struct {
	Ref       string        `json:"ref"`
	Revision  string        `json:"revision"`
	CanDelete bool          `json:"can_delete"`
	WebLinks  []WebLinkInfo `json:"web_links"`
}

// BranchInput entity contains information for the creation of a new branch.
type BranchInput struct {
	Ref      string `json:"ref"`
	Revision string `json:"revision"`
}

// ThemeInfo entity describes a theme.
type ThemeInfo struct {
	CSS    string `type:"css"`
	Header string `type:"header"`
	Footer string `type:"footer"`
}

// TagInfo entity contains information about a tag.
type TagInfo struct {
	Ref      string        `json:"ref"`
	Revision string        `json:"revision"`
	Object   string        `json:"object"`
	Message  string        `json:"message"`
	Tagger   GitPersonInfo `json:"tagger"`
}

// ReflogEntryInfo entity describes an entry in a reflog.
type ReflogEntryInfo struct {
	OldID   string        `json:"old_id"`
	NewID   string        `json:"new_id"`
	Who     GitPersonInfo `json:"who"`
	Comment string        `json:"comment"`
}

// ProjectParentInput entity contains information for setting a project parent.
type ProjectParentInput struct {
	Parent        string `json:"ProjectParentInput"`
	CommitMessage string `json:"commit_message"`
}

// RepositoryStatisticsInfo entity contains information about statistics of a Git repository.
type RepositoryStatisticsInfo struct {
	NumberOfLooseObjects  int `json:"number_of_loose_objects"`
	NumberOfLooseRefs     int `json:"number_of_loose_refs"`
	NumberOfPackFiles     int `json:"number_of_pack_files"`
	NumberOfPackedObjects int `json:"number_of_packed_objects"`
	NumberOfPackedRefs    int `json:"number_of_packed_refs"`
	SizeOfLooseObjects    int `json:"size_of_loose_objects"`
	SizeOfPackedObjects   int `json:"size_of_packed_objects"`
}

// InheritedBooleanInfo entity represents a boolean value that can also be inherited.
type InheritedBooleanInfo struct {
	Value           bool   `json:"value"`
	ConfiguredValue string `json:"configured_value"`
	InheritedValue  bool   `json:"inherited_value"`
}

// MaxObjectSizeLimitInfo entity contains information about the max object size limit of a project.
type MaxObjectSizeLimitInfo struct {
	Value           string `json:"value"`
	ConfiguredValue string `json:"configured_value"`
	InheritedValue  string `json:"inherited_value"`
}

// ConfigParameterInfo entity describes a project configuration parameter.
type ConfigParameterInfo struct {
	DisplayName string   `json:"display_name"`
	Description string   `json:"description"`
	Warning     string   `json:"warning"`
	Type        string   `json:"type"`
	Value       string   `json:"value"`
	Values      []string `json:"values"`
	// TODO: 5 fields are missing here, because the documentation seems to be fucked up
	// See https://gerrit-review.googlesource.com/Documentation/rest-api-projects.html#config-parameter-info
}

// ProjectDescriptionInput entity contains information for setting a project description.
type ProjectDescriptionInput struct {
	Description   string `json:"description"`
	CommitMessage string `json:"commit_message"`
}

// ConfigInfo entity contains information about the effective project configuration.
type ConfigInfo struct {
	Description                      string                         `json:"description"`
	UseContributorAgreements         InheritedBooleanInfo           `json:"use_contributor_agreements"`
	UseContentMerge                  InheritedBooleanInfo           `json:"use_content_merge"`
	UseSignedOffBy                   InheritedBooleanInfo           `json:"use_signed_off_by"`
	CreateNewChangeForAllNotInTarget InheritedBooleanInfo           `json:"create_new_change_for_all_not_in_target"`
	RequireChangeID                  InheritedBooleanInfo           `json:"require_change_id"`
	EnableSignedPush                 InheritedBooleanInfo           `json:"enable_signed_push"`
	MaxObjectSizeLimit               MaxObjectSizeLimitInfo         `json:"max_object_size_limit"`
	SubmitType                       string                         `json:"submit_type"`
	State                            string                         `json:"state"`
	Commentlinks                     map[string]string              `json:"commentlinks"`
	Theme                            ThemeInfo                      `json:"theme"`
	PluginConfig                     map[string]ConfigParameterInfo `json:"plugin_config"`
	Actions                          map[string]ActionInfo          `json:"actions"`
}

// ConfigInput entity describes a new project configuration.
type ConfigInput struct {
	Description                      string                       `json:"description"`
	UseContributorAgreements         string                       `json:"use_contributor_agreements"`
	UseContentMerge                  string                       `json:"use_content_merge"`
	UseSignedOffBy                   string                       `json:"use_signed_off_by"`
	CreateNewChangeForAllNotInTarget string                       `json:"create_new_change_for_all_not_in_target"`
	RequireChangeID                  string                       `json:"require_change_id"`
	MaxObjectSizeLimit               MaxObjectSizeLimitInfo       `json:"max_object_size_limit"`
	SubmitType                       string                       `json:"submit_type"`
	State                            string                       `json:"state"`
	PluginConfigValues               map[string]map[string]string `json:"plugin_config_values"`
}

// ProjectOptions specifies the parameters to the ProjectsService.ListProjects.
type ProjectOptions struct {
	// Limit the results to the projects having the specified branch and include the sha1 of the branch in the results.
	Branch string `url:"b,omitempty"`

	// Include project description in the results.
	Description bool `url:"d,omitempty"`

	// Limit the number of projects to be included in the results.
	Limit int

	// Limit the results to those projects that start with the specified prefix.
	Prefix string `url:"p,omitempty"`

	// Limit the results to those projects that match the specified regex.
	// Boundary matchers '^' and '$' are implicit. For example: the regex 'test.*' will match any projects that start with 'test' and regex '.*test' will match any project that end with 'test'.
	Regex string `url:"r,omitempty"`

	// Skip the given number of projects from the beginning of the list.
	Skip string `url:"S,omitempty"`

	// Limit the results to those projects that match the specified substring.
	Substring string `url:"m,omitempty"`

	// Get projects inheritance in a tree-like format.
	// This option does not work together with the branch option.
	Tree string `url:"t,omitempty"`

	// Get projects with specified type: ALL, CODE, PERMISSIONS.
	Type string `url:"type,omitempty"`
}

// ListProjects lists the projects accessible by the caller.
// This is the same as using the ls-projects command over SSH, and accepts the same options as query parameters.
// The entries in the map are sorted by project name.
//
// Gerrit API docs: https://gerrit-review.googlesource.com/Documentation/rest-api-projects.html#list-projects
func (s *ProjectsService) ListProjects(opt *ProjectOptions) (map[string]ProjectInfo, *Response, error) {
	u := "projects/"

	u, err := addOptions(u, opt)
	if err != nil {
		return nil, nil, err
	}

	req, err := s.client.NewRequest("GET", u, nil)
	if err != nil {
		return nil, nil, err
	}

	projectInfo := new(map[string]ProjectInfo)
	resp, err := s.client.Do(req, projectInfo)
	if err != nil {
		return nil, resp, err
	}

	return *projectInfo, resp, err
}
<|endoftext|>


<commit_before>package bitclient

import (
	"fmt"
)

type GetProjectsResponse struct {
	PagedResponse
	Values []Project
}

func (bc *BitClient) GetProjects(params PagedRequest) (GetProjectsResponse, error) {

	response := GetProjectsResponse{}

	_, err := bc.DoGet(
		"/projects",
		params,
		&response,
	)

	return response, err
}

type GetRepositoriesResponse struct {
	PagedResponse
	Values []Repository
}

func (bc *BitClient) GetRepositories(projectKey string, params PagedRequest) (GetRepositoriesResponse, error) {

	response := GetRepositoriesResponse{}

	_, err := bc.DoGet(
		fmt.Sprintf("/rest/api/1.0/projects/%s/repos", projectKey),
		params,
		&response,
	)

	return response, err
}

type CreateRepositoryRequest struct {
	Name     string `json:"name"`
	ScmId    string `json:"scmId"`
	Forkable bool   `json:"forkable"`
}

func (bc *BitClient) CreateRepository(projectKey string, params CreateRepositoryRequest) (Repository, error) {

	response := Repository{}

	_, err := bc.DoPost(
		fmt.Sprintf("/rest/api/1.0/projects/%s/repos", projectKey),
		params,
		&response,
	)

	return response, err
}
<commit_msg>Url cleanup<commit_after>package bitclient

import (
	"fmt"
)

type GetProjectsResponse struct {
	PagedResponse
	Values []Project
}

func (bc *BitClient) GetProjects(params PagedRequest) (GetProjectsResponse, error) {

	response := GetProjectsResponse{}

	_, err := bc.DoGet(
		"/projects",
		params,
		&response,
	)

	return response, err
}

type GetRepositoriesResponse struct {
	PagedResponse
	Values []Repository
}

func (bc *BitClient) GetRepositories(projectKey string, params PagedRequest) (GetRepositoriesResponse, error) {

	response := GetRepositoriesResponse{}

	_, err := bc.DoGet(
		fmt.Sprintf("/projects/%s/repos", projectKey),
		params,
		&response,
	)

	return response, err
}

type CreateRepositoryRequest struct {
	Name     string `json:"name"`
	ScmId    string `json:"scmId"`
	Forkable bool   `json:"forkable"`
}

func (bc *BitClient) CreateRepository(projectKey string, params CreateRepositoryRequest) (Repository, error) {

	response := Repository{}

	_, err := bc.DoPost(
		fmt.Sprintf("/projects/%s/repos", projectKey),
		params,
		&response,
	)

	return response, err
}
<|endoftext|>


<commit_before>package azurerm

import (
	"fmt"
	"reflect"
	"strings"

	"sync"

	"github.com/hashicorp/go-multierror"
	"github.com/hashicorp/terraform/helper/mutexkv"
	"github.com/hashicorp/terraform/helper/resource"
	"github.com/hashicorp/terraform/helper/schema"
	"github.com/hashicorp/terraform/terraform"
	riviera "github.com/jen20/riviera/azure"
)

// Provider returns a terraform.ResourceProvider.
func Provider() terraform.ResourceProvider {
	var p *schema.Provider
	p = &schema.Provider{
		Schema: map[string]*schema.Schema{
			"subscription_id": {
				Type:        schema.TypeString,
				Required:    true,
				DefaultFunc: schema.EnvDefaultFunc("ARM_SUBSCRIPTION_ID", ""),
			},

			"client_id": {
				Type:        schema.TypeString,
				Required:    true,
				DefaultFunc: schema.EnvDefaultFunc("ARM_CLIENT_ID", ""),
			},

			"client_secret": {
				Type:        schema.TypeString,
				Required:    true,
				DefaultFunc: schema.EnvDefaultFunc("ARM_CLIENT_SECRET", ""),
			},

			"tenant_id": {
				Type:        schema.TypeString,
				Required:    true,
				DefaultFunc: schema.EnvDefaultFunc("ARM_TENANT_ID", ""),
			},
		},

		DataSourcesMap: map[string]*schema.Resource{
			"azurerm_client_config": dataSourceArmClientConfig(),
		},

		ResourcesMap: map[string]*schema.Resource{
			// These resources use the Azure ARM SDK
			"azurerm_availability_set": resourceArmAvailabilitySet(),
			"azurerm_cdn_endpoint":     resourceArmCdnEndpoint(),
			"azurerm_cdn_profile":      resourceArmCdnProfile(),

			"azurerm_eventhub":           resourceArmEventHub(),
			"azurerm_eventhub_namespace": resourceArmEventHubNamespace(),

			"azurerm_lb":                      resourceArmLoadBalancer(),
			"azurerm_lb_backend_address_pool": resourceArmLoadBalancerBackendAddressPool(),
			"azurerm_lb_nat_rule":             resourceArmLoadBalancerNatRule(),
			"azurerm_lb_nat_pool":             resourceArmLoadBalancerNatPool(),
			"azurerm_lb_probe":                resourceArmLoadBalancerProbe(),
			"azurerm_lb_rule":                 resourceArmLoadBalancerRule(),

			"azurerm_key_vault":                 resourceArmKeyVault(),
			"azurerm_local_network_gateway":     resourceArmLocalNetworkGateway(),
			"azurerm_network_interface":         resourceArmNetworkInterface(),
			"azurerm_network_security_group":    resourceArmNetworkSecurityGroup(),
			"azurerm_network_security_rule":     resourceArmNetworkSecurityRule(),
			"azurerm_public_ip":                 resourceArmPublicIp(),
			"azurerm_route":                     resourceArmRoute(),
			"azurerm_route_table":               resourceArmRouteTable(),
			"azurerm_servicebus_namespace":      resourceArmServiceBusNamespace(),
			"azurerm_servicebus_subscription":   resourceArmServiceBusSubscription(),
			"azurerm_servicebus_topic":          resourceArmServiceBusTopic(),
			"azurerm_storage_account":           resourceArmStorageAccount(),
			"azurerm_storage_blob":              resourceArmStorageBlob(),
			"azurerm_storage_container":         resourceArmStorageContainer(),
			"azurerm_storage_share":             resourceArmStorageShare(),
			"azurerm_storage_queue":             resourceArmStorageQueue(),
			"azurerm_storage_table":             resourceArmStorageTable(),
			"azurerm_subnet":                    resourceArmSubnet(),
			"azurerm_template_deployment":       resourceArmTemplateDeployment(),
			"azurerm_traffic_manager_endpoint":  resourceArmTrafficManagerEndpoint(),
			"azurerm_traffic_manager_profile":   resourceArmTrafficManagerProfile(),
			"azurerm_virtual_machine_extension": resourceArmVirtualMachineExtensions(),
			"azurerm_virtual_machine":           resourceArmVirtualMachine(),
			"azurerm_virtual_machine_scale_set": resourceArmVirtualMachineScaleSet(),
			"azurerm_virtual_network":           resourceArmVirtualNetwork(),
			"azurerm_virtual_network_peering":   resourceArmVirtualNetworkPeering(),

			// These resources use the Riviera SDK
			"azurerm_dns_a_record":      resourceArmDnsARecord(),
			"azurerm_dns_aaaa_record":   resourceArmDnsAAAARecord(),
			"azurerm_dns_cname_record":  resourceArmDnsCNameRecord(),
			"azurerm_dns_mx_record":     resourceArmDnsMxRecord(),
			"azurerm_dns_ns_record":     resourceArmDnsNsRecord(),
			"azurerm_dns_srv_record":    resourceArmDnsSrvRecord(),
			"azurerm_dns_txt_record":    resourceArmDnsTxtRecord(),
			"azurerm_dns_zone":          resourceArmDnsZone(),
			"azurerm_resource_group":    resourceArmResourceGroup(),
			"azurerm_search_service":    resourceArmSearchService(),
			"azurerm_sql_database":      resourceArmSqlDatabase(),
			"azurerm_sql_firewall_rule": resourceArmSqlFirewallRule(),
			"azurerm_sql_server":        resourceArmSqlServer(),
		},
		ConfigureFunc: providerConfigure(p),
	}

	return p
}

// Config is the configuration structure used to instantiate a
// new Azure management client.
type Config struct {
	ManagementURL string

	SubscriptionID string
	ClientID       string
	ClientSecret   string
	TenantID       string

	validateCredentialsOnce sync.Once
}

func (c *Config) validate() error {
	var err *multierror.Error

	if c.SubscriptionID == "" {
		err = multierror.Append(err, fmt.Errorf("Subscription ID must be configured for the AzureRM provider"))
	}
	if c.ClientID == "" {
		err = multierror.Append(err, fmt.Errorf("Client ID must be configured for the AzureRM provider"))
	}
	if c.ClientSecret == "" {
		err = multierror.Append(err, fmt.Errorf("Client Secret must be configured for the AzureRM provider"))
	}
	if c.TenantID == "" {
		err = multierror.Append(err, fmt.Errorf("Tenant ID must be configured for the AzureRM provider"))
	}

	return err.ErrorOrNil()
}

func providerConfigure(p *schema.Provider) schema.ConfigureFunc {
	return func(d *schema.ResourceData) (interface{}, error) {
		config := &Config{
			SubscriptionID: d.Get("subscription_id").(string),
			ClientID:       d.Get("client_id").(string),
			ClientSecret:   d.Get("client_secret").(string),
			TenantID:       d.Get("tenant_id").(string),
		}

		if err := config.validate(); err != nil {
			return nil, err
		}

		client, err := config.getArmClient()
		if err != nil {
			return nil, err
		}

		client.StopContext = p.StopContext()

		err = registerAzureResourceProvidersWithSubscription(client.rivieraClient)
		if err != nil {
			return nil, err
		}

		return client, nil
	}
}

func registerProviderWithSubscription(providerName string, client *riviera.Client) error {
	request := client.NewRequest()
	request.Command = riviera.RegisterResourceProvider{
		Namespace: providerName,
	}

	response, err := request.Execute()
	if err != nil {
		return fmt.Errorf("Cannot request provider registration for Azure Resource Manager: %s.", err)
	}

	if !response.IsSuccessful() {
		return fmt.Errorf("Credentials for accessing the Azure Resource Manager API are likely " +
			"to be incorrect, or\n  the service principal does not have permission to use " +
			"the Azure Service Management\n  API.")
	}

	return nil
}

var providerRegistrationOnce sync.Once

// registerAzureResourceProvidersWithSubscription uses the providers client to register
// all Azure resource providers which the Terraform provider may require (regardless of
// whether they are actually used by the configuration or not). It was confirmed by Microsoft
// that this is the approach their own internal tools also take.
func registerAzureResourceProvidersWithSubscription(client *riviera.Client) error {
	var err error
	providerRegistrationOnce.Do(func() {
		// We register Microsoft.Compute during client initialization
		providers := []string{"Microsoft.Network", "Microsoft.Cdn", "Microsoft.Storage", "Microsoft.Sql", "Microsoft.Search", "Microsoft.Resources", "Microsoft.ServiceBus", "Microsoft.KeyVault", "Microsoft.EventHub"}

		var wg sync.WaitGroup
		wg.Add(len(providers))
		for _, providerName := range providers {
			go func(p string) {
				defer wg.Done()
				if innerErr := registerProviderWithSubscription(p, client); err != nil {
					err = innerErr
				}
			}(providerName)
		}
		wg.Wait()
	})

	return err
}

// azureRMNormalizeLocation is a function which normalises human-readable region/location
// names (e.g. "West US") to the values used and returned by the Azure API (e.g. "westus").
// In state we track the API internal version as it is easier to go from the human form
// to the canonical form than the other way around.
func azureRMNormalizeLocation(location interface{}) string {
	input := location.(string)
	return strings.Replace(strings.ToLower(input), " ", "", -1)
}

// armMutexKV is the instance of MutexKV for ARM resources
var armMutexKV = mutexkv.NewMutexKV()

func azureStateRefreshFunc(resourceURI string, client *ArmClient, command riviera.APICall) resource.StateRefreshFunc {
	return func() (interface{}, string, error) {
		req := client.rivieraClient.NewRequestForURI(resourceURI)
		req.Command = command

		res, err := req.Execute()
		if err != nil {
			return nil, "", fmt.Errorf("Error executing %T command in azureStateRefreshFunc", req.Command)
		}

		var value reflect.Value
		if reflect.ValueOf(res.Parsed).Kind() == reflect.Ptr {
			value = reflect.ValueOf(res.Parsed).Elem()
		} else {
			value = reflect.ValueOf(res.Parsed)
		}

		for i := 0; i < value.NumField(); i++ { // iterates through every struct type field
			tag := value.Type().Field(i).Tag // returns the tag string
			tagValue := tag.Get("mapstructure")
			if tagValue == "provisioningState" {
				return res.Parsed, value.Field(i).Elem().String(), nil
			}
		}

		panic(fmt.Errorf("azureStateRefreshFunc called on structure %T with no mapstructure:provisioningState tag. This is a bug", res.Parsed))
	}
}

// Resource group names can be capitalised, but we store them in lowercase.
// Use a custom diff function to avoid creation of new resources.
func resourceAzurermResourceGroupNameDiffSuppress(k, old, new string, d *schema.ResourceData) bool {
	return strings.ToLower(old) == strings.ToLower(new)
}
<commit_msg>provider/azurerm: move ConfigureFunc outside of Provider literal, fixes nil reference<commit_after>package azurerm

import (
	"fmt"
	"reflect"
	"strings"

	"sync"

	"github.com/hashicorp/go-multierror"
	"github.com/hashicorp/terraform/helper/mutexkv"
	"github.com/hashicorp/terraform/helper/resource"
	"github.com/hashicorp/terraform/helper/schema"
	"github.com/hashicorp/terraform/terraform"
	riviera "github.com/jen20/riviera/azure"
)

// Provider returns a terraform.ResourceProvider.
func Provider() terraform.ResourceProvider {
	var p *schema.Provider
	p = &schema.Provider{
		Schema: map[string]*schema.Schema{
			"subscription_id": {
				Type:        schema.TypeString,
				Required:    true,
				DefaultFunc: schema.EnvDefaultFunc("ARM_SUBSCRIPTION_ID", ""),
			},

			"client_id": {
				Type:        schema.TypeString,
				Required:    true,
				DefaultFunc: schema.EnvDefaultFunc("ARM_CLIENT_ID", ""),
			},

			"client_secret": {
				Type:        schema.TypeString,
				Required:    true,
				DefaultFunc: schema.EnvDefaultFunc("ARM_CLIENT_SECRET", ""),
			},

			"tenant_id": {
				Type:        schema.TypeString,
				Required:    true,
				DefaultFunc: schema.EnvDefaultFunc("ARM_TENANT_ID", ""),
			},
		},

		DataSourcesMap: map[string]*schema.Resource{
			"azurerm_client_config": dataSourceArmClientConfig(),
		},

		ResourcesMap: map[string]*schema.Resource{
			// These resources use the Azure ARM SDK
			"azurerm_availability_set": resourceArmAvailabilitySet(),
			"azurerm_cdn_endpoint":     resourceArmCdnEndpoint(),
			"azurerm_cdn_profile":      resourceArmCdnProfile(),

			"azurerm_eventhub":           resourceArmEventHub(),
			"azurerm_eventhub_namespace": resourceArmEventHubNamespace(),

			"azurerm_lb":                      resourceArmLoadBalancer(),
			"azurerm_lb_backend_address_pool": resourceArmLoadBalancerBackendAddressPool(),
			"azurerm_lb_nat_rule":             resourceArmLoadBalancerNatRule(),
			"azurerm_lb_nat_pool":             resourceArmLoadBalancerNatPool(),
			"azurerm_lb_probe":                resourceArmLoadBalancerProbe(),
			"azurerm_lb_rule":                 resourceArmLoadBalancerRule(),

			"azurerm_key_vault":                 resourceArmKeyVault(),
			"azurerm_local_network_gateway":     resourceArmLocalNetworkGateway(),
			"azurerm_network_interface":         resourceArmNetworkInterface(),
			"azurerm_network_security_group":    resourceArmNetworkSecurityGroup(),
			"azurerm_network_security_rule":     resourceArmNetworkSecurityRule(),
			"azurerm_public_ip":                 resourceArmPublicIp(),
			"azurerm_route":                     resourceArmRoute(),
			"azurerm_route_table":               resourceArmRouteTable(),
			"azurerm_servicebus_namespace":      resourceArmServiceBusNamespace(),
			"azurerm_servicebus_subscription":   resourceArmServiceBusSubscription(),
			"azurerm_servicebus_topic":          resourceArmServiceBusTopic(),
			"azurerm_storage_account":           resourceArmStorageAccount(),
			"azurerm_storage_blob":              resourceArmStorageBlob(),
			"azurerm_storage_container":         resourceArmStorageContainer(),
			"azurerm_storage_share":             resourceArmStorageShare(),
			"azurerm_storage_queue":             resourceArmStorageQueue(),
			"azurerm_storage_table":             resourceArmStorageTable(),
			"azurerm_subnet":                    resourceArmSubnet(),
			"azurerm_template_deployment":       resourceArmTemplateDeployment(),
			"azurerm_traffic_manager_endpoint":  resourceArmTrafficManagerEndpoint(),
			"azurerm_traffic_manager_profile":   resourceArmTrafficManagerProfile(),
			"azurerm_virtual_machine_extension": resourceArmVirtualMachineExtensions(),
			"azurerm_virtual_machine":           resourceArmVirtualMachine(),
			"azurerm_virtual_machine_scale_set": resourceArmVirtualMachineScaleSet(),
			"azurerm_virtual_network":           resourceArmVirtualNetwork(),
			"azurerm_virtual_network_peering":   resourceArmVirtualNetworkPeering(),

			// These resources use the Riviera SDK
			"azurerm_dns_a_record":      resourceArmDnsARecord(),
			"azurerm_dns_aaaa_record":   resourceArmDnsAAAARecord(),
			"azurerm_dns_cname_record":  resourceArmDnsCNameRecord(),
			"azurerm_dns_mx_record":     resourceArmDnsMxRecord(),
			"azurerm_dns_ns_record":     resourceArmDnsNsRecord(),
			"azurerm_dns_srv_record":    resourceArmDnsSrvRecord(),
			"azurerm_dns_txt_record":    resourceArmDnsTxtRecord(),
			"azurerm_dns_zone":          resourceArmDnsZone(),
			"azurerm_resource_group":    resourceArmResourceGroup(),
			"azurerm_search_service":    resourceArmSearchService(),
			"azurerm_sql_database":      resourceArmSqlDatabase(),
			"azurerm_sql_firewall_rule": resourceArmSqlFirewallRule(),
			"azurerm_sql_server":        resourceArmSqlServer(),
		},
	}

	p.ConfigureFunc = providerConfigure(p)

	return p
}

// Config is the configuration structure used to instantiate a
// new Azure management client.
type Config struct {
	ManagementURL string

	SubscriptionID string
	ClientID       string
	ClientSecret   string
	TenantID       string

	validateCredentialsOnce sync.Once
}

func (c *Config) validate() error {
	var err *multierror.Error

	if c.SubscriptionID == "" {
		err = multierror.Append(err, fmt.Errorf("Subscription ID must be configured for the AzureRM provider"))
	}
	if c.ClientID == "" {
		err = multierror.Append(err, fmt.Errorf("Client ID must be configured for the AzureRM provider"))
	}
	if c.ClientSecret == "" {
		err = multierror.Append(err, fmt.Errorf("Client Secret must be configured for the AzureRM provider"))
	}
	if c.TenantID == "" {
		err = multierror.Append(err, fmt.Errorf("Tenant ID must be configured for the AzureRM provider"))
	}

	return err.ErrorOrNil()
}

func providerConfigure(p *schema.Provider) schema.ConfigureFunc {
	return func(d *schema.ResourceData) (interface{}, error) {
		config := &Config{
			SubscriptionID: d.Get("subscription_id").(string),
			ClientID:       d.Get("client_id").(string),
			ClientSecret:   d.Get("client_secret").(string),
			TenantID:       d.Get("tenant_id").(string),
		}

		if err := config.validate(); err != nil {
			return nil, err
		}

		client, err := config.getArmClient()
		if err != nil {
			return nil, err
		}

		client.StopContext = p.StopContext()

		err = registerAzureResourceProvidersWithSubscription(client.rivieraClient)
		if err != nil {
			return nil, err
		}

		return client, nil
	}
}

func registerProviderWithSubscription(providerName string, client *riviera.Client) error {
	request := client.NewRequest()
	request.Command = riviera.RegisterResourceProvider{
		Namespace: providerName,
	}

	response, err := request.Execute()
	if err != nil {
		return fmt.Errorf("Cannot request provider registration for Azure Resource Manager: %s.", err)
	}

	if !response.IsSuccessful() {
		return fmt.Errorf("Credentials for accessing the Azure Resource Manager API are likely " +
			"to be incorrect, or\n  the service principal does not have permission to use " +
			"the Azure Service Management\n  API.")
	}

	return nil
}

var providerRegistrationOnce sync.Once

// registerAzureResourceProvidersWithSubscription uses the providers client to register
// all Azure resource providers which the Terraform provider may require (regardless of
// whether they are actually used by the configuration or not). It was confirmed by Microsoft
// that this is the approach their own internal tools also take.
func registerAzureResourceProvidersWithSubscription(client *riviera.Client) error {
	var err error
	providerRegistrationOnce.Do(func() {
		// We register Microsoft.Compute during client initialization
		providers := []string{"Microsoft.Network", "Microsoft.Cdn", "Microsoft.Storage", "Microsoft.Sql", "Microsoft.Search", "Microsoft.Resources", "Microsoft.ServiceBus", "Microsoft.KeyVault", "Microsoft.EventHub"}

		var wg sync.WaitGroup
		wg.Add(len(providers))
		for _, providerName := range providers {
			go func(p string) {
				defer wg.Done()
				if innerErr := registerProviderWithSubscription(p, client); err != nil {
					err = innerErr
				}
			}(providerName)
		}
		wg.Wait()
	})

	return err
}

// azureRMNormalizeLocation is a function which normalises human-readable region/location
// names (e.g. "West US") to the values used and returned by the Azure API (e.g. "westus").
// In state we track the API internal version as it is easier to go from the human form
// to the canonical form than the other way around.
func azureRMNormalizeLocation(location interface{}) string {
	input := location.(string)
	return strings.Replace(strings.ToLower(input), " ", "", -1)
}

// armMutexKV is the instance of MutexKV for ARM resources
var armMutexKV = mutexkv.NewMutexKV()

func azureStateRefreshFunc(resourceURI string, client *ArmClient, command riviera.APICall) resource.StateRefreshFunc {
	return func() (interface{}, string, error) {
		req := client.rivieraClient.NewRequestForURI(resourceURI)
		req.Command = command

		res, err := req.Execute()
		if err != nil {
			return nil, "", fmt.Errorf("Error executing %T command in azureStateRefreshFunc", req.Command)
		}

		var value reflect.Value
		if reflect.ValueOf(res.Parsed).Kind() == reflect.Ptr {
			value = reflect.ValueOf(res.Parsed).Elem()
		} else {
			value = reflect.ValueOf(res.Parsed)
		}

		for i := 0; i < value.NumField(); i++ { // iterates through every struct type field
			tag := value.Type().Field(i).Tag // returns the tag string
			tagValue := tag.Get("mapstructure")
			if tagValue == "provisioningState" {
				return res.Parsed, value.Field(i).Elem().String(), nil
			}
		}

		panic(fmt.Errorf("azureStateRefreshFunc called on structure %T with no mapstructure:provisioningState tag. This is a bug", res.Parsed))
	}
}

// Resource group names can be capitalised, but we store them in lowercase.
// Use a custom diff function to avoid creation of new resources.
func resourceAzurermResourceGroupNameDiffSuppress(k, old, new string, d *schema.ResourceData) bool {
	return strings.ToLower(old) == strings.ToLower(new)
}
<|endoftext|>


<commit_before>package proxiedsites

import (
	"encoding/json"
	"fmt"
	"net/http"
	"sync"

	"github.com/getlantern/golog"
	"github.com/getlantern/proxiedsites"

	"github.com/getlantern/flashlight/config"
	"github.com/getlantern/flashlight/ui"
)

var (
	log = golog.LoggerFor("proxiedsites-flashlight")

	uichannel  *ui.UIChannel
	startMutex sync.Mutex
)

func Configure(cfg *proxiedsites.Config) {
	delta := proxiedsites.Configure(cfg)
	startMutex.Lock()
	if uichannel == nil {
		start()
	} else if delta != nil {
		b, err := json.Marshal(delta)
		if err != nil {
			log.Errorf("Unable to publish delta to UI: %v", err)
		}
		uichannel.Out <- b
	}
	startMutex.Unlock()
}

func start() {
	// Register the PAC handler
	url := ui.Handle("/proxy_on.pac", http.HandlerFunc(proxiedsites.ServePAC))
	log.Debugf("Serving PAC file at %v", url)

	// Establish a channel to the UI for sending and receiving updates
	uichannel = ui.NewChannel("/data", func(write func([]byte) error) error {
		b, err := json.Marshal(proxiedsites.ActiveDelta())
		if err != nil {
			return fmt.Errorf("Unable to marshal active delta to json: %v", err)
		}
		return write(b)
	})
	log.Debugf("Accepting proxiedsites websocket connections at %v", uichannel.URL)

	go read()
}

func read() {
	for b := range uichannel.In {
		delta := &proxiedsites.Delta{}
		err := json.Unmarshal(b, delta)
		if err != nil {
			log.Errorf("Unable to parse JSON update from browser: %v", err)
			continue
		}
		config.Update(func(updated *config.Config) error {
			log.Debugf("Applying update from UI")
			updated.ProxiedSites.Delta.Merge(delta)
			return nil
		})
	}
}
<commit_msg>Error handling fix<commit_after>package proxiedsites

import (
	"encoding/json"
	"fmt"
	"net/http"
	"sync"

	"github.com/getlantern/golog"
	"github.com/getlantern/proxiedsites"

	"github.com/getlantern/flashlight/config"
	"github.com/getlantern/flashlight/ui"
)

var (
	log = golog.LoggerFor("proxiedsites-flashlight")

	uichannel  *ui.UIChannel
	startMutex sync.Mutex
)

func Configure(cfg *proxiedsites.Config) {
	delta := proxiedsites.Configure(cfg)
	startMutex.Lock()
	if uichannel == nil {
		start()
	} else if delta != nil {
		b, err := json.Marshal(delta)
		if err != nil {
			log.Errorf("Unable to publish delta to UI: %v", err)
		} else {
			uichannel.Out <- b
		}
	}
	startMutex.Unlock()
}

func start() {
	// Register the PAC handler
	url := ui.Handle("/proxy_on.pac", http.HandlerFunc(proxiedsites.ServePAC))
	log.Debugf("Serving PAC file at %v", url)

	// Establish a channel to the UI for sending and receiving updates
	uichannel = ui.NewChannel("/data", func(write func([]byte) error) error {
		b, err := json.Marshal(proxiedsites.ActiveDelta())
		if err != nil {
			return fmt.Errorf("Unable to marshal active delta to json: %v", err)
		}
		return write(b)
	})
	log.Debugf("Accepting proxiedsites websocket connections at %v", uichannel.URL)

	go read()
}

func read() {
	for b := range uichannel.In {
		delta := &proxiedsites.Delta{}
		err := json.Unmarshal(b, delta)
		if err != nil {
			log.Errorf("Unable to parse JSON update from browser: %v", err)
			continue
		}
		config.Update(func(updated *config.Config) error {
			log.Debugf("Applying update from UI")
			updated.ProxiedSites.Delta.Merge(delta)
			return nil
		})
	}
}
<|endoftext|>


<commit_before>package framework

import (
	"io"
)

type Renderer interface {
	MimeType() string
	Render(Context, interface{}) ([]byte, error)
	RenderToWriter(io.Writer, Context, interface{}) error
}

type Renderable interface {
	Render(Context) ([]byte, error)
	RenderToWriter(io.Writer, Context) error
}

type Renderers []Renderer

func (r Renderers) Get(mimeType string) Renderer {
	for _, re := range r {
		if re.MimeType() == mimeType {
			return re
		}
	}
	return nil
}

func (r *Renderers) Add(nr Renderer) {
	if nr == nil {
		return
	}
	for i, re := range *r {
		if re.MimeType() == nr.MimeType() {
			(*r)[i] = nr
			return
		}
	}
	*r = append(*r, nr)
}
<commit_msg>Updated rendering interfaces<commit_after>package framework

import (
	"io"
)

type Renderer interface {
	MimeType() string
	Render(Context, interface{}) ([]byte, error)
	RenderToWriter(io.Writer, Context, interface{}) error
}

type Renderable interface {
	Render(Context) ([]byte, error)
	RenderToWriter(io.Writer, Context) error
}

type Renderers []Renderer

func (r Renderers) Get(mimeType string) Renderer {
	for _, re := range r {
		if re.MimeType() == mimeType {
			return re
		}
	}
	return nil
}

func (r *Renderers) Append(nr ...Renderer) {
	if nr == nil {
		return
	}
	for _, nre := range nr {
		found := false
		for i, re := range *r {
			if re.MimeType() == nre.MimeType() {
				(*r)[i] = nre
				found = true
				break
			}
		}
		if !found {
			*r = append(*r, nre)
		}
	}
}
<|endoftext|>