<commit_before>/*
Copyright 2018 The Knative Authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package handler

import (
	"errors"
	"fmt"
	"net/http"
	"net/http/httputil"
	"net/url"
	"time"

	"go.opencensus.io/plugin/ochttp"
	"go.opencensus.io/trace"
	"go.uber.org/zap"

	"github.com/knative/pkg/logging/logkey"
	"github.com/knative/serving/pkg/activator"
	"github.com/knative/serving/pkg/activator/util"
	"github.com/knative/serving/pkg/apis/networking"
	"github.com/knative/serving/pkg/apis/serving"
	"github.com/knative/serving/pkg/apis/serving/v1alpha1"
	netlisters "github.com/knative/serving/pkg/client/listers/networking/v1alpha1"
	servinglisters "github.com/knative/serving/pkg/client/listers/serving/v1alpha1"
	pkghttp "github.com/knative/serving/pkg/http"
	"github.com/knative/serving/pkg/network"
	"github.com/knative/serving/pkg/network/prober"
	"github.com/knative/serving/pkg/queue"

	k8serrors "k8s.io/apimachinery/pkg/api/errors"
	"k8s.io/apimachinery/pkg/util/wait"
	corev1listers "k8s.io/client-go/listers/core/v1"
)

// activationHandler will wait for an active endpoint for a revision
// to be available before proxing the request
type activationHandler struct {
	logger    *zap.SugaredLogger
	transport http.RoundTripper
	reporter  activator.StatsReporter
	throttler *activator.Throttler

	probeTimeout time.Duration

	revisionLister servinglisters.RevisionLister
	serviceLister  corev1listers.ServiceLister
	sksLister      netlisters.ServerlessServiceLister
}

// The default time we'll try to probe the revision for activation.
const defaulTimeout = 2 * time.Minute

// New constructs a new http.Handler that deals with revision activation.
func New(l *zap.SugaredLogger, r activator.StatsReporter, t *activator.Throttler,
	rl servinglisters.RevisionLister, sl corev1listers.ServiceLister,
	sksL netlisters.ServerlessServiceLister) http.Handler {

	// In activator we collect metrics, so we're wrapping
	// the Roundtripper the prober would use inside annotating transport.
	prober.TransportFactory = func() http.RoundTripper {
		return &ochttp.Transport{
			Base: network.NewAutoTransport(),
		}
	}
	return &activationHandler{
		logger:         l,
		transport:      network.AutoTransport,
		reporter:       r,
		throttler:      t,
		revisionLister: rl,
		sksLister:      sksL,
		serviceLister:  sl,
		probeTimeout:   defaulTimeout,
	}
}

func withOrigProto(or *http.Request) prober.ProbeOption {
	return func(r *http.Request) *http.Request {
		r.Proto = or.Proto
		r.ProtoMajor = or.ProtoMajor
		r.ProtoMinor = or.ProtoMinor
		return r
	}
}

func (a *activationHandler) probeEndpoint(logger *zap.SugaredLogger, r *http.Request, target *url.URL) (bool, int) {
	var (
		attempts int
		st       = time.Now()
	)

	reqCtx, probeSpan := trace.StartSpan(r.Context(), "probe")
	defer func() {
		probeSpan.End()
		a.logger.Infof("Probing %s took %d attempts and %v time", target.String(), attempts, time.Since(st))
	}()

	err := wait.PollImmediate(100*time.Millisecond, a.probeTimeout, func() (bool, error) {
		attempts++
		ret, err := prober.Do(reqCtx, target.String(), queue.Name, withOrigProto(r))
		if err != nil {
			logger.Warnw("Pod probe failed", zap.Error(err))
			return false, nil
		}
		if !ret {
			logger.Warn("Pod probe unsuccessful")
			return false, nil
		}
		return true, nil
	})
	return (err == nil), attempts
}

func (a *activationHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	namespace := pkghttp.LastHeaderValue(r.Header, activator.RevisionHeaderNamespace)
	name := pkghttp.LastHeaderValue(r.Header, activator.RevisionHeaderName)
	start := time.Now()
	revID := activator.RevisionID{Namespace: namespace, Name: name}

	logger := a.logger.With(zap.String(logkey.Key, revID.String()))

	revision, err := a.revisionLister.Revisions(namespace).Get(name)
	if err != nil {
		logger.Errorw("Error while getting revision", zap.Error(err))
		sendError(err, w)
		return
	}

	// SKS name matches that of revision.
	sks, err := a.sksLister.ServerlessServices(namespace).Get(name)
	if err != nil {
		logger.Errorw("Error while getting SKS", zap.Error(err))
		sendError(err, w)
		return
	}
	host, err := a.serviceHostName(revision, sks.Status.PrivateServiceName)
	if err != nil {
		logger.Errorw("Error while getting hostname", zap.Error(err))
		sendError(err, w)
		return
	}

	target := &url.URL{
		Scheme: "http",
		Host:   host,
	}

	err = a.throttler.Try(revID, func() {
		var (
			httpStatus int
		)

		success, attempts := a.probeEndpoint(logger, r, target)
		if success {
			// Once we see a successful probe, send traffic.
			attempts++
			reqCtx, proxySpan := trace.StartSpan(r.Context(), "proxy")
			httpStatus = a.proxyRequest(w, r.WithContext(reqCtx), target)
			proxySpan.End()
		} else {
			httpStatus = http.StatusInternalServerError
			w.WriteHeader(httpStatus)
		}

		// Report the metrics
		duration := time.Since(start)

		var configurationName string
		var serviceName string
		if revision.Labels != nil {
			configurationName = revision.Labels[serving.ConfigurationLabelKey]
			serviceName = revision.Labels[serving.ServiceLabelKey]
		}

		a.reporter.ReportRequestCount(namespace, serviceName, configurationName, name, httpStatus, attempts, 1.0)
		a.reporter.ReportResponseTime(namespace, serviceName, configurationName, name, httpStatus, duration)
	})
	if err != nil {
		if err == activator.ErrActivatorOverload {
			http.Error(w, activator.ErrActivatorOverload.Error(), http.StatusServiceUnavailable)
		} else {
			w.WriteHeader(http.StatusInternalServerError)
			logger.Errorw("Error processing request in the activator", zap.Error(err))
		}
	}
}

func (a *activationHandler) proxyRequest(w http.ResponseWriter, r *http.Request, target *url.URL) int {
	network.RewriteHostIn(r)
	recorder := pkghttp.NewResponseRecorder(w, http.StatusOK)
	proxy := httputil.NewSingleHostReverseProxy(target)
	proxy.Transport = &ochttp.Transport{
		Base: a.transport,
	}
	proxy.FlushInterval = -1

	r.Header.Set(network.ProxyHeaderName, activator.Name)

	util.SetupHeaderPruning(proxy)

	proxy.ServeHTTP(recorder, r)
	return recorder.ResponseCode
}

// serviceHostName obtains the hostname of the underlying service and the correct
// port to send requests to.
func (a *activationHandler) serviceHostName(rev *v1alpha1.Revision, serviceName string) (string, error) {
	svc, err := a.serviceLister.Services(rev.Namespace).Get(serviceName)
	if err != nil {
		return "", err
	}

	// Search for the appropriate port
	port := -1
	for _, p := range svc.Spec.Ports {
		if p.Name == networking.ServicePortName(rev.GetProtocol()) {
			port = int(p.Port)
			break
		}
	}
	if port == -1 {
		return "", errors.New("revision needs external HTTP port")
	}

	serviceFQDN := network.GetServiceHostname(serviceName, rev.Namespace)

	return fmt.Sprintf("%s:%d", serviceFQDN, port), nil
}

func sendError(err error, w http.ResponseWriter) {
	msg := fmt.Sprintf("Error getting active endpoint: %v", err)
	if k8serrors.IsNotFound(err) {
		http.Error(w, msg, http.StatusNotFound)
		return
	}
	http.Error(w, msg, http.StatusInternalServerError)
}
<commit_msg>Log probe timing stat at debug (#4104)<commit_after>/*
Copyright 2018 The Knative Authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package handler

import (
	"errors"
	"fmt"
	"net/http"
	"net/http/httputil"
	"net/url"
	"time"

	"go.opencensus.io/plugin/ochttp"
	"go.opencensus.io/trace"
	"go.uber.org/zap"

	"github.com/knative/pkg/logging/logkey"
	"github.com/knative/serving/pkg/activator"
	"github.com/knative/serving/pkg/activator/util"
	"github.com/knative/serving/pkg/apis/networking"
	"github.com/knative/serving/pkg/apis/serving"
	"github.com/knative/serving/pkg/apis/serving/v1alpha1"
	netlisters "github.com/knative/serving/pkg/client/listers/networking/v1alpha1"
	servinglisters "github.com/knative/serving/pkg/client/listers/serving/v1alpha1"
	pkghttp "github.com/knative/serving/pkg/http"
	"github.com/knative/serving/pkg/network"
	"github.com/knative/serving/pkg/network/prober"
	"github.com/knative/serving/pkg/queue"

	k8serrors "k8s.io/apimachinery/pkg/api/errors"
	"k8s.io/apimachinery/pkg/util/wait"
	corev1listers "k8s.io/client-go/listers/core/v1"
)

// activationHandler will wait for an active endpoint for a revision
// to be available before proxing the request
type activationHandler struct {
	logger    *zap.SugaredLogger
	transport http.RoundTripper
	reporter  activator.StatsReporter
	throttler *activator.Throttler

	probeTimeout time.Duration

	revisionLister servinglisters.RevisionLister
	serviceLister  corev1listers.ServiceLister
	sksLister      netlisters.ServerlessServiceLister
}

// The default time we'll try to probe the revision for activation.
const defaulTimeout = 2 * time.Minute

// New constructs a new http.Handler that deals with revision activation.
func New(l *zap.SugaredLogger, r activator.StatsReporter, t *activator.Throttler,
	rl servinglisters.RevisionLister, sl corev1listers.ServiceLister,
	sksL netlisters.ServerlessServiceLister) http.Handler {

	// In activator we collect metrics, so we're wrapping
	// the Roundtripper the prober would use inside annotating transport.
	prober.TransportFactory = func() http.RoundTripper {
		return &ochttp.Transport{
			Base: network.NewAutoTransport(),
		}
	}
	return &activationHandler{
		logger:         l,
		transport:      network.AutoTransport,
		reporter:       r,
		throttler:      t,
		revisionLister: rl,
		sksLister:      sksL,
		serviceLister:  sl,
		probeTimeout:   defaulTimeout,
	}
}

func withOrigProto(or *http.Request) prober.ProbeOption {
	return func(r *http.Request) *http.Request {
		r.Proto = or.Proto
		r.ProtoMajor = or.ProtoMajor
		r.ProtoMinor = or.ProtoMinor
		return r
	}
}

func (a *activationHandler) probeEndpoint(logger *zap.SugaredLogger, r *http.Request, target *url.URL) (bool, int) {
	var (
		attempts int
		st       = time.Now()
	)

	reqCtx, probeSpan := trace.StartSpan(r.Context(), "probe")
	defer func() {
		probeSpan.End()
		a.logger.Debugf("Probing %s took %d attempts and %v time", target.String(), attempts, time.Since(st))
	}()

	err := wait.PollImmediate(100*time.Millisecond, a.probeTimeout, func() (bool, error) {
		attempts++
		ret, err := prober.Do(reqCtx, target.String(), queue.Name, withOrigProto(r))
		if err != nil {
			logger.Warnw("Pod probe failed", zap.Error(err))
			return false, nil
		}
		if !ret {
			logger.Warn("Pod probe unsuccessful")
			return false, nil
		}
		return true, nil
	})
	return (err == nil), attempts
}

func (a *activationHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	namespace := pkghttp.LastHeaderValue(r.Header, activator.RevisionHeaderNamespace)
	name := pkghttp.LastHeaderValue(r.Header, activator.RevisionHeaderName)
	start := time.Now()
	revID := activator.RevisionID{Namespace: namespace, Name: name}

	logger := a.logger.With(zap.String(logkey.Key, revID.String()))

	revision, err := a.revisionLister.Revisions(namespace).Get(name)
	if err != nil {
		logger.Errorw("Error while getting revision", zap.Error(err))
		sendError(err, w)
		return
	}

	// SKS name matches that of revision.
	sks, err := a.sksLister.ServerlessServices(namespace).Get(name)
	if err != nil {
		logger.Errorw("Error while getting SKS", zap.Error(err))
		sendError(err, w)
		return
	}
	host, err := a.serviceHostName(revision, sks.Status.PrivateServiceName)
	if err != nil {
		logger.Errorw("Error while getting hostname", zap.Error(err))
		sendError(err, w)
		return
	}

	target := &url.URL{
		Scheme: "http",
		Host:   host,
	}

	err = a.throttler.Try(revID, func() {
		var (
			httpStatus int
		)

		success, attempts := a.probeEndpoint(logger, r, target)
		if success {
			// Once we see a successful probe, send traffic.
			attempts++
			reqCtx, proxySpan := trace.StartSpan(r.Context(), "proxy")
			httpStatus = a.proxyRequest(w, r.WithContext(reqCtx), target)
			proxySpan.End()
		} else {
			httpStatus = http.StatusInternalServerError
			w.WriteHeader(httpStatus)
		}

		// Report the metrics
		duration := time.Since(start)

		var configurationName string
		var serviceName string
		if revision.Labels != nil {
			configurationName = revision.Labels[serving.ConfigurationLabelKey]
			serviceName = revision.Labels[serving.ServiceLabelKey]
		}

		a.reporter.ReportRequestCount(namespace, serviceName, configurationName, name, httpStatus, attempts, 1.0)
		a.reporter.ReportResponseTime(namespace, serviceName, configurationName, name, httpStatus, duration)
	})
	if err != nil {
		if err == activator.ErrActivatorOverload {
			http.Error(w, activator.ErrActivatorOverload.Error(), http.StatusServiceUnavailable)
		} else {
			w.WriteHeader(http.StatusInternalServerError)
			logger.Errorw("Error processing request in the activator", zap.Error(err))
		}
	}
}

func (a *activationHandler) proxyRequest(w http.ResponseWriter, r *http.Request, target *url.URL) int {
	network.RewriteHostIn(r)
	recorder := pkghttp.NewResponseRecorder(w, http.StatusOK)
	proxy := httputil.NewSingleHostReverseProxy(target)
	proxy.Transport = &ochttp.Transport{
		Base: a.transport,
	}
	proxy.FlushInterval = -1

	r.Header.Set(network.ProxyHeaderName, activator.Name)

	util.SetupHeaderPruning(proxy)

	proxy.ServeHTTP(recorder, r)
	return recorder.ResponseCode
}

// serviceHostName obtains the hostname of the underlying service and the correct
// port to send requests to.
func (a *activationHandler) serviceHostName(rev *v1alpha1.Revision, serviceName string) (string, error) {
	svc, err := a.serviceLister.Services(rev.Namespace).Get(serviceName)
	if err != nil {
		return "", err
	}

	// Search for the appropriate port
	port := -1
	for _, p := range svc.Spec.Ports {
		if p.Name == networking.ServicePortName(rev.GetProtocol()) {
			port = int(p.Port)
			break
		}
	}
	if port == -1 {
		return "", errors.New("revision needs external HTTP port")
	}

	serviceFQDN := network.GetServiceHostname(serviceName, rev.Namespace)

	return fmt.Sprintf("%s:%d", serviceFQDN, port), nil
}

func sendError(err error, w http.ResponseWriter) {
	msg := fmt.Sprintf("Error getting active endpoint: %v", err)
	if k8serrors.IsNotFound(err) {
		http.Error(w, msg, http.StatusNotFound)
		return
	}
	http.Error(w, msg, http.StatusInternalServerError)
}
<|endoftext|>


<commit_before>package data

import (
	cmn "github.com/RxnWeaver/rxnweaver/common"
)

// Atom represents a chemical atom.
//
// It has various physical and chemical properties, apart from the
// transient information attached to it during its participation in
// reactions.
type Atom struct {
	mol    *Molecule // Containing molecule of this atom.
	atNum  uint8     // Atomic number of this atom's element.
	symbol string    // Symbol, in case of a different isotope.
	iId    uint16    // Serial input ID of this atom.
	nId    uint16    // Normalised ID of this atom.

	X float32 // X-coordinate of this atom.
	Y float32 // Y-coordinate of this atom.
	Z float32 // Z-coordinate of this atom.

	numH    uint8 // Number of implicit + explicit H atoms attached to this atom.
	charge  int8  // Residual net charge of this atom.
	valence int8  // Current valence configuration of this atom.

	pHash uint64 // A pseudo-hash of this atom, using some attributes.
	sHash uint64 // A pseudo-hash of this atom, using some attributes.

	bonds          [cmn.MaxBonds]uint8 // Expanded list of bonds of this atom.
	nbrs           [cmn.MaxBonds]uint8 // List of distinct neighbours of this atom.
	numSingleBonds uint8               // Number of single bonds this atom has.
	numDoubleBonds uint8               // Number of double bonds this atom has.
	numTripleBonds uint8               // Number of triple bonds this atom has.

	rings [cmn.MaxRings]uint8 // List of rings this atom participates in.
	// Does this atom participate in at least one aromatic ring?
	isInAroRing bool
	// Is this atom a bridgehead of a bicyclic system of rings?
	isBridgeHead bool
	// Is this atom the sole common atom of all of its rings?
	isSpiro bool

	// The functional groups substituted on this atom.  They are listed in
	// descending order of importance.  The first is the primary feature.
	features [cmn.MaxFeatures]uint8
}

// newAtom constructs and initialises a new atom of the given element
// type, and belonging to the given molecule.
func newAtom(mol *Molecule, atNum uint8) *Atom {
	atom := new(Atom)
	atom.mol = mol
	atom.atNum = atNum
	atom.valence = cmn.PeriodicTable[cmn.ElemSyms[atNum]].Valence

	return atom
}

// AtomicNumber answers the atomic number of this atom.
func (a *Atom) AtomicNumber() uint8 {
	return a.atNum
}

// Parent answers the parent molecule of this atom.
func (a *Atom) Parent() *Molecule {
	return a.mol
}

// numPiElectrons answers the number of delocalised pi electrons
// contributed by this atom.  This number is important for calculating
// the aromaticity of the rings this atom participates in.
func (a *Atom) numPiElectrons() int {
	mol := a.mol
	wtSum := 100*int16(a.numDoubleBonds) + 10*int16(a.numSingleBonds) + int16(a.charge)

	switch a.atNum {
	case 6:
		switch wtSum {
		case 19:
			return 2
		case 110:
			return 1
		case 120:
			var b *Bond
			for _, bid := range a.bonds {
				b = mol.bonds[bid-1]
				if b.bType == cmn.BondTypeDouble {
					break
				}
			}
			if len(b.rings) > 0 {
				return 1
			}
			return 0
		default:
			return 0
		}

	case 7:
		switch wtSum {
		case 20:
			return 2
		case 30:
			return 2
		case 110:
			return 1
		case 121:
			return 1
		default:
			return 0
		}

	case 8:
		switch wtSum {
		case 20:
			return 2
		case 111:
			return 1
		default:
			return 0
		}

	case 16:
		switch wtSum {
		case 20:
			return 2
		case 111:
			return 1
		case 120:
			var b *Bond
			for _, bid := range a.bonds {
				b = mol.bonds[bid-1]
				if b.bType == cmn.BondTypeDouble {
					break
				}
			}
			oa, _ := b.otherAtom(a.iId)
			if mol.atomWithIid(oa).atNum == 8 && len(a.rings) == 0 {
				return 2
			}
			return 0
		case 220:
			c := 0
			for _, bid := range a.bonds {
				b := mol.bonds[bid-1]
				if b.bType == cmn.BondTypeDouble {
					oa, _ := b.otherAtom(a.iId)
					if len(mol.atomWithIid(oa).rings) == 0 {
						c++
					}
				}
			}
			if c > 1 {
				return -1
			}
			return 0
		default:
			return 0
		}
	}

	return 0
}
<commit_msg>Fix a bug in pi electrons calculation<commit_after>package data

import (
	cmn "github.com/RxnWeaver/rxnweaver/common"
)

// Atom represents a chemical atom.
//
// It has various physical and chemical properties, apart from the
// transient information attached to it during its participation in
// reactions.
type Atom struct {
	mol    *Molecule // Containing molecule of this atom.
	atNum  uint8     // Atomic number of this atom's element.
	symbol string    // Symbol, in case of a different isotope.
	iId    uint16    // Serial input ID of this atom.
	nId    uint16    // Normalised ID of this atom.

	X float32 // X-coordinate of this atom.
	Y float32 // Y-coordinate of this atom.
	Z float32 // Z-coordinate of this atom.

	numH    uint8 // Number of implicit + explicit H atoms attached to this atom.
	charge  int8  // Residual net charge of this atom.
	valence int8  // Current valence configuration of this atom.

	pHash uint64 // A pseudo-hash of this atom, using some attributes.
	sHash uint64 // A pseudo-hash of this atom, using some attributes.

	bonds          [cmn.MaxBonds]uint8 // Expanded list of bonds of this atom.
	nbrs           [cmn.MaxBonds]uint8 // List of distinct neighbours of this atom.
	numSingleBonds uint8               // Number of single bonds this atom has.
	numDoubleBonds uint8               // Number of double bonds this atom has.
	numTripleBonds uint8               // Number of triple bonds this atom has.

	rings [cmn.MaxRings]uint8 // List of rings this atom participates in.
	// Does this atom participate in at least one aromatic ring?
	isInAroRing bool
	// Is this atom a bridgehead of a bicyclic system of rings?
	isBridgeHead bool
	// Is this atom the sole common atom of all of its rings?
	isSpiro bool

	// The functional groups substituted on this atom.  They are listed in
	// descending order of importance.  The first is the primary feature.
	features [cmn.MaxFeatures]uint8
}

// newAtom constructs and initialises a new atom of the given element
// type, and belonging to the given molecule.
func newAtom(mol *Molecule, atNum uint8) *Atom {
	atom := new(Atom)
	atom.mol = mol
	atom.atNum = atNum
	atom.valence = cmn.PeriodicTable[cmn.ElemSyms[atNum]].Valence

	return atom
}

// AtomicNumber answers the atomic number of this atom.
func (a *Atom) AtomicNumber() uint8 {
	return a.atNum
}

// Parent answers the parent molecule of this atom.
func (a *Atom) Parent() *Molecule {
	return a.mol
}

// numPiElectrons answers the number of delocalised pi electrons
// contributed by this atom.  This number is important for calculating
// the aromaticity of the rings this atom participates in.
func (a *Atom) numPiElectrons() int {
	mol := a.mol
	wtSum := 100*int16(a.numDoubleBonds) + 10*int16(a.numSingleBonds) + int16(a.charge)

	switch a.atNum {
	case 6:
		switch wtSum {
		case 19:
			return 2
		case 110:
			return 1
		case 120:
			var b *Bond
			for _, bid := range a.bonds {
				b = mol.bonds[bid-1]
				if b.bType == cmn.BondTypeDouble {
					break
				}
			}
			if len(b.rings) > 0 {
				return 1
			}
			return 0
		default:
			return 0
		}

	case 7:
		switch wtSum {
		case 20:
			return 2
		case 30:
			return 2
		case 110:
			return 1
		case 121:
			return 1
		default:
			return 0
		}

	case 8:
		switch wtSum {
		case 20:
			return 2
		case 111:
			return 1
		default:
			return 0
		}

	case 16:
		switch wtSum {
		case 20:
			return 2
		case 111:
			return 1
		case 120:
			var b *Bond
			for _, bid := range a.bonds {
				b = mol.bonds[bid-1]
				if b.bType == cmn.BondTypeDouble {
					break
				}
			}
			oaid, _ := b.otherAtom(a.iId)
			oa := mol.atomWithIid(oaid)
			if oa.atNum == 8 && len(oa.rings) == 0 {
				return 2
			}
			return 0
		case 220:
			c := 0
			for _, bid := range a.bonds {
				b := mol.bonds[bid-1]
				if b.bType == cmn.BondTypeDouble {
					oaid, _ := b.otherAtom(a.iId)
					if len(mol.atomWithIid(oaid).rings) == 0 {
						c++
					}
				}
			}
			if c > 1 {
				return -1
			}
			return 0
		default:
			return 0
		}
	}

	return 0
}
<|endoftext|>


<commit_before>// Copyright 2015-present Oursky Ltd.
//
// 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 pq

import (
	"testing"

	"github.com/skygeario/skygear-server/pkg/server/skydb"
	. "github.com/smartystreets/goconvey/convey"
)

func TestRoleCRUD(t *testing.T) {
	var c *conn

	Convey("Conn", t, func() {
		c = getTestConn(t)
		defer cleanupConn(t, c)

		Convey("add roles to a user", func() {
			userinfo := skydb.UserInfo{
				ID:       "userid",
				Username: "john.doe",
				Email:    "john.doe@example.com",
			}
			err := c.CreateUser(&userinfo)
			So(err, ShouldBeNil)
			userinfo.Roles = []string{
				"admin",
				"writer",
			}
			err = c.UpdateUserRoles(&userinfo)
			So(err, ShouldBeNil)

			var role string
			err = c.QueryRowx("SELECT id FROM _role WHERE id = 'admin'").
				Scan(&role)
			So(err, ShouldBeNil)
			So(role, ShouldEqual, "admin")

			err = c.QueryRowx("SELECT id FROM _role WHERE id = 'writer'").
				Scan(&role)
			So(err, ShouldBeNil)
			So(role, ShouldEqual, "writer")

			rows, err := c.Queryx("SELECT role_id FROM _user_role WHERE user_id = 'userid'")
			So(err, ShouldBeNil)
			c := 0
			roles := []string{}
			for rows.Next() {
				c++
				rows.Scan(&role)
				roles = append(roles, role)
			}
			So(c, ShouldEqual, 2)
			So(roles, ShouldResemble, userinfo.Roles)
		})

		Convey("clear roles of a user keep the role definition", func() {
			userinfo := skydb.UserInfo{
				ID: "userid",
				Roles: []string{
					"admin",
					"writer",
				},
			}
			err := c.CreateUser(&userinfo)
			So(err, ShouldBeNil)
			userinfo.Roles = nil
			err = c.UpdateUserRoles(&userinfo)
			So(err, ShouldBeNil)

			var role string
			err = c.QueryRowx("SELECT id FROM _role WHERE id = 'admin'").
				Scan(&role)
			So(err, ShouldBeNil)
			So(role, ShouldEqual, "admin")

			err = c.QueryRowx("SELECT id FROM _role WHERE id = 'writer'").
				Scan(&role)
			So(err, ShouldBeNil)
			So(role, ShouldEqual, "writer")

			rows, err := c.Queryx("SELECT role_id FROM _user_role WHERE user_id = 'userid'")
			So(err, ShouldBeNil)
			c := 0
			for rows.Next() {
				c++
			}
			So(c, ShouldEqual, 0)
		})
	})
}

func TestRoleAssignRevoke(t *testing.T) {
	var c *conn
	Convey("AssignRoles", t, func() {
		c = getTestConn(t)
		defer cleanupConn(t, c)

		Convey("assign roles to user without roles", func() {
			userinfo := skydb.UserInfo{
				ID:       "userid",
				Username: "john.doe",
				Email:    "john.doe@example.com",
			}
			err := c.CreateUser(&userinfo)
			roles := []string{
				"admin",
				"user",
			}
			err = c.AssignRoles([]string{
				"userid",
			}, roles)
			rows, err := c.Queryx("SELECT role_id FROM _user_role WHERE user_id = 'userid'")
			So(err, ShouldBeNil)
			c := 0
			result := []string{}
			var role string
			for rows.Next() {
				c++
				rows.Scan(&role)
				result = append(result, role)
			}
			So(c, ShouldEqual, 2)
			So(result, ShouldResemble, roles)
		})

		Convey("assign roles to users with existing roles", func() {
			userinfo := skydb.UserInfo{
				ID: "userid",
				Roles: []string{
					"admin",
				},
			}
			err := c.CreateUser(&userinfo)
			So(err, ShouldBeNil)
			userinfo = skydb.UserInfo{
				ID: "userid2",
				Roles: []string{
					"user",
				},
			}
			err = c.CreateUser(&userinfo)
			So(err, ShouldBeNil)

			roles := []string{
				"admin",
				"user",
			}
			err = c.AssignRoles([]string{
				"userid",
				"userid2",
			}, roles)
			So(err, ShouldBeNil)
			rows, err := c.Queryx(
				"SELECT * FROM _user_role WHERE user_id IN ( 'userid', 'userid2' )")
			So(err, ShouldBeNil)
			c := 0
			for rows.Next() {
				c++
			}
			So(c, ShouldEqual, 4)
		})
	})

	Convey("RevokeRoles", t, func() {
		c = getTestConn(t)
		defer cleanupConn(t, c)
		Convey("revoke roles from users with a role", func() {
			userinfo := skydb.UserInfo{
				ID: "userid",
				Roles: []string{
					"admin",
					"user",
				},
			}
			err := c.CreateUser(&userinfo)
			userinfo = skydb.UserInfo{
				ID: "userid2",
				Roles: []string{
					"user",
				},
			}

			roles := []string{
				"admin",
				"user",
			}
			err = c.RevokeRoles([]string{
				"userid",
				"userid2",
			}, roles)
			rows, err := c.Queryx(
				"SELECT role_id FROM _user_role WHERE user_id IN ( 'userid', 'userid2' )")
			So(err, ShouldBeNil)
			c := 0
			for rows.Next() {
				c++
			}
			So(c, ShouldEqual, 0)
		})

		Convey("revoke roles from users without a role", func() {
			userinfo := skydb.UserInfo{
				ID: "userid",
			}
			err := c.CreateUser(&userinfo)
			userinfo = skydb.UserInfo{
				ID: "userid2",
			}

			roles := []string{
				"admin",
				"user",
			}
			err = c.RevokeRoles([]string{
				"userid",
				"userid2",
			}, roles)
			rows, err := c.Queryx(
				"SELECT role_id FROM _user_role WHERE user_id IN ( 'userid', 'userid2' )")
			So(err, ShouldBeNil)
			c := 0
			for rows.Next() {
				c++
			}
			So(c, ShouldEqual, 0)
		})

	})
}

func TestRoleType(t *testing.T) {
	var c *conn

	Convey("SetAdminRoles", t, func() {
		c = getTestConn(t)
		defer cleanupConn(t, c)

		Convey("set role is_admin to true", func() {
			err := c.SetAdminRoles([]string{
				"god",
				"buddha",
			})
			So(err, ShouldBeNil)
			rows, err := c.Queryx("SELECT id FROM _role WHERE is_admin = TRUE")
			So(err, ShouldBeNil)
			c := 0
			var role string
			roles := []string{}
			for rows.Next() {
				c++
				rows.Scan(&role)
				roles = append(roles, role)
			}
			So(c, ShouldEqual, 2)
			So(roles, ShouldResemble, []string{
				"god",
				"buddha",
			})
		})

		Convey("get all admin roles", func() {
			So(c.SetAdminRoles([]string{"god", "buddha"}), ShouldBeNil)
			adminRoles, err := c.GetAdminRoles()
			So(err, ShouldBeNil)
			So(adminRoles, ShouldResemble, []string{
				"god",
				"buddha",
			})
		})

		Convey("reset role is_admin to false on new admin role set", func() {
			err := c.SetAdminRoles([]string{
				"god",
				"buddha",
			})
			So(err, ShouldBeNil)
			err = c.SetAdminRoles([]string{
				"man",
			})
			So(err, ShouldBeNil)

			var role string
			err = c.QueryRowx("SELECT id FROM _role WHERE is_admin = TRUE").
				Scan(&role)
			So(err, ShouldBeNil)
			So(role, ShouldEqual, "man")
		})
	})

	Convey("SetDefaultRoles", t, func() {
		c = getTestConn(t)
		defer cleanupConn(t, c)

		Convey("set role by_default to true", func() {
			err := c.SetDefaultRoles([]string{
				"human",
				"chinese",
			})
			So(err, ShouldBeNil)
			rows, err := c.Queryx("SELECT id FROM _role WHERE by_default = TRUE")
			So(err, ShouldBeNil)
			c := 0
			var role string
			roles := []string{}
			for rows.Next() {
				c++
				rows.Scan(&role)
				roles = append(roles, role)
			}
			So(c, ShouldEqual, 2)
			So(roles, ShouldResemble, []string{
				"human",
				"chinese",
			})
		})

		Convey("get all admin roles", func() {
			So(c.SetDefaultRoles([]string{"human", "chinese"}), ShouldBeNil)
			defaultRoles, err := c.GetDefaultRoles()
			So(err, ShouldBeNil)
			So(defaultRoles, ShouldResemble, []string{
				"human",
				"chinese",
			})
		})

		Convey("reset role by_default to false on new default role set", func() {
			err := c.SetDefaultRoles([]string{
				"human",
				"chinese",
			})
			So(err, ShouldBeNil)
			err = c.SetDefaultRoles([]string{
				"free man",
			})
			So(err, ShouldBeNil)

			var role string
			err = c.QueryRowx("SELECT id FROM _role WHERE by_default = TRUE").
				Scan(&role)
			So(err, ShouldBeNil)
			So(role, ShouldEqual, "free man")
		})
	})
}
<commit_msg>Prevent redeclaring var to different type<commit_after>// Copyright 2015-present Oursky Ltd.
//
// 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 pq

import (
	"testing"

	"github.com/skygeario/skygear-server/pkg/server/skydb"
	. "github.com/smartystreets/goconvey/convey"
)

func TestRoleCRUD(t *testing.T) {
	var c *conn

	Convey("Conn", t, func() {
		c = getTestConn(t)
		defer cleanupConn(t, c)

		Convey("add roles to a user", func() {
			userinfo := skydb.UserInfo{
				ID:       "userid",
				Username: "john.doe",
				Email:    "john.doe@example.com",
			}
			err := c.CreateUser(&userinfo)
			So(err, ShouldBeNil)
			userinfo.Roles = []string{
				"admin",
				"writer",
			}
			err = c.UpdateUserRoles(&userinfo)
			So(err, ShouldBeNil)

			var role string
			err = c.QueryRowx("SELECT id FROM _role WHERE id = 'admin'").
				Scan(&role)
			So(err, ShouldBeNil)
			So(role, ShouldEqual, "admin")

			err = c.QueryRowx("SELECT id FROM _role WHERE id = 'writer'").
				Scan(&role)
			So(err, ShouldBeNil)
			So(role, ShouldEqual, "writer")

			rows, err := c.Queryx("SELECT role_id FROM _user_role WHERE user_id = 'userid'")
			So(err, ShouldBeNil)
			roles := []string{}
			for rows.Next() {
				rows.Scan(&role)
				roles = append(roles, role)
			}
			So(roles, ShouldResemble, userinfo.Roles)
		})

		Convey("clear roles of a user keep the role definition", func() {
			userinfo := skydb.UserInfo{
				ID: "userid",
				Roles: []string{
					"admin",
					"writer",
				},
			}
			err := c.CreateUser(&userinfo)
			So(err, ShouldBeNil)
			userinfo.Roles = nil
			err = c.UpdateUserRoles(&userinfo)
			So(err, ShouldBeNil)

			var role string
			err = c.QueryRowx("SELECT id FROM _role WHERE id = 'admin'").
				Scan(&role)
			So(err, ShouldBeNil)
			So(role, ShouldEqual, "admin")

			err = c.QueryRowx("SELECT id FROM _role WHERE id = 'writer'").
				Scan(&role)
			So(err, ShouldBeNil)
			So(role, ShouldEqual, "writer")

			rows, err := c.Queryx("SELECT role_id FROM _user_role WHERE user_id = 'userid'")
			So(err, ShouldBeNil)
			So(rows.Next(), ShouldBeFalse)
		})
	})
}

func TestRoleAssignRevoke(t *testing.T) {
	var c *conn
	Convey("AssignRoles", t, func() {
		c = getTestConn(t)
		defer cleanupConn(t, c)

		Convey("assign roles to user without roles", func() {
			userinfo := skydb.UserInfo{
				ID:       "userid",
				Username: "john.doe",
				Email:    "john.doe@example.com",
			}
			err := c.CreateUser(&userinfo)
			roles := []string{
				"admin",
				"user",
			}
			err = c.AssignRoles([]string{
				"userid",
			}, roles)
			rows, err := c.Queryx("SELECT role_id FROM _user_role WHERE user_id = 'userid'")
			So(err, ShouldBeNil)
			result := []string{}
			var role string
			for rows.Next() {
				rows.Scan(&role)
				result = append(result, role)
			}
			So(result, ShouldResemble, roles)
		})

		Convey("assign roles to users with existing roles", func() {
			userinfo := skydb.UserInfo{
				ID: "userid",
				Roles: []string{
					"admin",
				},
			}
			err := c.CreateUser(&userinfo)
			So(err, ShouldBeNil)
			userinfo = skydb.UserInfo{
				ID: "userid2",
				Roles: []string{
					"user",
				},
			}
			err = c.CreateUser(&userinfo)
			So(err, ShouldBeNil)

			roles := []string{
				"admin",
				"user",
			}
			err = c.AssignRoles([]string{
				"userid",
				"userid2",
			}, roles)
			So(err, ShouldBeNil)
			rows, err := c.Queryx(
				"SELECT * FROM _user_role WHERE user_id IN ( 'userid', 'userid2' )")
			So(err, ShouldBeNil)
			count := 0
			for rows.Next() {
				count++
			}
			So(count, ShouldEqual, 4)
		})
	})

	Convey("RevokeRoles", t, func() {
		c = getTestConn(t)
		defer cleanupConn(t, c)
		Convey("revoke roles from users with a role", func() {
			userinfo := skydb.UserInfo{
				ID: "userid",
				Roles: []string{
					"admin",
					"user",
				},
			}
			err := c.CreateUser(&userinfo)
			userinfo = skydb.UserInfo{
				ID: "userid2",
				Roles: []string{
					"user",
				},
			}

			roles := []string{
				"admin",
				"user",
			}
			err = c.RevokeRoles([]string{
				"userid",
				"userid2",
			}, roles)
			rows, err := c.Queryx(
				"SELECT role_id FROM _user_role WHERE user_id IN ( 'userid', 'userid2' )")
			So(err, ShouldBeNil)
			So(rows.Next(), ShouldBeFalse)
		})

		Convey("revoke roles from users without a role", func() {
			userinfo := skydb.UserInfo{
				ID: "userid",
			}
			err := c.CreateUser(&userinfo)
			userinfo = skydb.UserInfo{
				ID: "userid2",
			}

			roles := []string{
				"admin",
				"user",
			}
			err = c.RevokeRoles([]string{
				"userid",
				"userid2",
			}, roles)
			rows, err := c.Queryx(
				"SELECT role_id FROM _user_role WHERE user_id IN ( 'userid', 'userid2' )")
			So(err, ShouldBeNil)
			So(rows.Next(), ShouldBeFalse)
		})

	})
}

func TestRoleType(t *testing.T) {
	var c *conn

	Convey("SetAdminRoles", t, func() {
		c = getTestConn(t)
		defer cleanupConn(t, c)

		Convey("set role is_admin to true", func() {
			err := c.SetAdminRoles([]string{
				"god",
				"buddha",
			})
			So(err, ShouldBeNil)
			rows, err := c.Queryx("SELECT id FROM _role WHERE is_admin = TRUE")
			So(err, ShouldBeNil)
			var role string
			roles := []string{}
			for rows.Next() {
				rows.Scan(&role)
				roles = append(roles, role)
			}
			So(roles, ShouldResemble, []string{
				"god",
				"buddha",
			})
		})

		Convey("get all admin roles", func() {
			So(c.SetAdminRoles([]string{"god", "buddha"}), ShouldBeNil)
			adminRoles, err := c.GetAdminRoles()
			So(err, ShouldBeNil)
			So(adminRoles, ShouldResemble, []string{
				"god",
				"buddha",
			})
		})

		Convey("reset role is_admin to false on new admin role set", func() {
			err := c.SetAdminRoles([]string{
				"god",
				"buddha",
			})
			So(err, ShouldBeNil)
			err = c.SetAdminRoles([]string{
				"man",
			})
			So(err, ShouldBeNil)

			var role string
			err = c.QueryRowx("SELECT id FROM _role WHERE is_admin = TRUE").
				Scan(&role)
			So(err, ShouldBeNil)
			So(role, ShouldEqual, "man")
		})
	})

	Convey("SetDefaultRoles", t, func() {
		c = getTestConn(t)
		defer cleanupConn(t, c)

		Convey("set role by_default to true", func() {
			err := c.SetDefaultRoles([]string{
				"human",
				"chinese",
			})
			So(err, ShouldBeNil)
			rows, err := c.Queryx("SELECT id FROM _role WHERE by_default = TRUE")
			So(err, ShouldBeNil)
			var role string
			roles := []string{}
			for rows.Next() {
				rows.Scan(&role)
				roles = append(roles, role)
			}
			So(roles, ShouldResemble, []string{
				"human",
				"chinese",
			})
		})

		Convey("get all admin roles", func() {
			So(c.SetDefaultRoles([]string{"human", "chinese"}), ShouldBeNil)
			defaultRoles, err := c.GetDefaultRoles()
			So(err, ShouldBeNil)
			So(defaultRoles, ShouldResemble, []string{
				"human",
				"chinese",
			})
		})

		Convey("reset role by_default to false on new default role set", func() {
			err := c.SetDefaultRoles([]string{
				"human",
				"chinese",
			})
			So(err, ShouldBeNil)
			err = c.SetDefaultRoles([]string{
				"free man",
			})
			So(err, ShouldBeNil)

			var role string
			err = c.QueryRowx("SELECT id FROM _role WHERE by_default = TRUE").
				Scan(&role)
			So(err, ShouldBeNil)
			So(role, ShouldEqual, "free man")
		})
	})
}
<|endoftext|>


<commit_before>package windows

import (
  "fmt"
  "github.com/mattn/go-gtk/gtk"
)

type GhMainWindow struct {
  GtkWindow *gtk.GtkWindow
}

func (w *GhMainWindow) build() {
  w.GtkWindow.Connect("destroy", gtk.MainQuit)

  w.GtkWindow.SetTitle("ghighlights")
  w.GtkWindow.Connect("destroy", gtk.MainQuit)

  mainVBox := gtk.VBox(false, 1)

  scrolledTextViewWindow := gtk.ScrolledWindow(nil, nil)
  scrolledTextViewWindow.SetPolicy(gtk.GTK_POLICY_AUTOMATIC, gtk.GTK_POLICY_AUTOMATIC)

  textView := gtk.TextView()
  textView.SetSizeRequest(600, 100)
  scrolledTextViewWindow.Add(textView)

  scrolledTextViewWindow.SetSizeRequest(600, 100)
  mainVBox.Add(scrolledTextViewWindow)

  readingHBox := gtk.HBox(false, 1)

  readingsComboBox := gtk.ComboBoxNewText()
  readingsComboBox.AppendText("Die Zeit, die Zeit")
  readingsComboBox.AppendText("Eating Animals")
  readingsComboBox.AppendText("Paul Miller - Offline")
  readingsComboBox.AppendText("The Picture of Dorian Gray")
  readingsComboBox.AppendText("Wer bin ich - und wenn ja wie viele?")
  readingsComboBox.AppendText("Do No Harm")
  readingsComboBox.AppendText("Foucault's pendulum")
  readingsComboBox.AppendText("One man's wilderness")
  readingsComboBox.AppendText("For Whom the Bell Tolls")
  readingsComboBox.SetActive(0)
  readingsComboBox.Connect("changed", func() {
    fmt.Println("Changed reading to: ", readingsComboBox.GetActiveText())
  })
  readingHBox.Add(readingsComboBox)

  mainVBox.Add(readingHBox)

  addHighlightButton := gtk.ButtonWithLabel("Add highlight")
  addHighlightButton.Clicked(func() {
    fmt.Println("Add highlight")
  })
  mainVBox.Add(addHighlightButton)

  w.GtkWindow.Add(mainVBox)
  return
}

func MainWindow() *GhMainWindow {
  mainWindow := &GhMainWindow{gtk.Window(gtk.GTK_WINDOW_TOPLEVEL)}
  mainWindow.build()
  return mainWindow
}

<commit_msg>Add readings to combobox through Readings model<commit_after>package windows

import (
  "fmt"
  "github.com/mattn/go-gtk/gtk"
  "ghighlighter/models"
)

type GhMainWindow struct {
  GtkWindow *gtk.GtkWindow
}

func (w *GhMainWindow) build() {
  w.GtkWindow.Connect("destroy", gtk.MainQuit)

  w.GtkWindow.SetTitle("ghighlights")
  w.GtkWindow.Connect("destroy", gtk.MainQuit)

  mainVBox := gtk.VBox(false, 1)

  scrolledTextViewWindow := gtk.ScrolledWindow(nil, nil)
  scrolledTextViewWindow.SetPolicy(gtk.GTK_POLICY_AUTOMATIC, gtk.GTK_POLICY_AUTOMATIC)

  textView := gtk.TextView()
  textView.SetSizeRequest(600, 100)
  scrolledTextViewWindow.Add(textView)

  scrolledTextViewWindow.SetSizeRequest(600, 100)
  mainVBox.Add(scrolledTextViewWindow)

  readingHBox := gtk.HBox(false, 1)

  readingsComboBox := gtk.ComboBoxText()
  readings := models.Readings()
  readingsItems := readings.GetAll()
  for _, reading := range readingsItems {
    readingsComboBox.AppendText(reading.Title)
  }
  readingsComboBox.SetActive(0)
  readingsComboBox.Connect("changed", func() {
    fmt.Println("Changed reading to: ", readingsComboBox.GetActiveText())
  })
  readingHBox.Add(readingsComboBox)

  mainVBox.Add(readingHBox)

  addHighlightButton := gtk.ButtonWithLabel("Add highlight")
  addHighlightButton.Clicked(func() {
    fmt.Println("Add highlight")
  })
  mainVBox.Add(addHighlightButton)

  w.GtkWindow.Add(mainVBox)
  return
}

func MainWindow() *GhMainWindow {
  mainWindow := &GhMainWindow{gtk.Window(gtk.GTK_WINDOW_TOPLEVEL)}
  mainWindow.build()
  return mainWindow
}

<|endoftext|>


<commit_before>// Import this in all *_test.go files to initialize ~/.tendermint_test.

package tendermint_test

import (
	"os"
	"path"
	"strings"

	. "github.com/tendermint/go-common"
	cfg "github.com/tendermint/go-config"
)

func init() {
	// Creates ~/.tendermint_test
	EnsureDir(os.Getenv("HOME")+"/.tendermint_test", 0700)
}

func ResetConfig(path string) {
	rootDir := os.Getenv("HOME") + "/.tendermint_test/" + path
	cfg.ApplyConfig(GetConfig(rootDir))
}

func initTMRoot(rootDir string) {
	// Remove ~/.tendermint_test_bak
	if FileExists(rootDir + "_bak") {
		err := os.RemoveAll(rootDir + "_bak")
		if err != nil {
			PanicSanity(err.Error())
		}
	}
	// Move ~/.tendermint_test to ~/.tendermint_test_bak
	if FileExists(rootDir) {
		err := os.Rename(rootDir, rootDir+"_bak")
		if err != nil {
			PanicSanity(err.Error())
		}
	}
	// Create new dir
	EnsureDir(rootDir, 0700)

	configFilePath := path.Join(rootDir, "config.toml")
	genesisFilePath := path.Join(rootDir, "genesis.json")
	privFilePath := path.Join(rootDir, "priv_validator.json")

	// Write default config file if missing.
	if !FileExists(configFilePath) {
		// Ask user for moniker
		// moniker := cfg.Prompt("Type hostname: ", "anonymous")
		MustWriteFile(configFilePath, []byte(defaultConfig("anonymous")), 0644)
	}
	if !FileExists(genesisFilePath) {
		MustWriteFile(genesisFilePath, []byte(defaultGenesis), 0644)
	}
	// we always overwrite the priv val
	MustWriteFile(privFilePath, []byte(defaultPrivValidator), 0644)
}

func GetConfig(rootDir string) cfg.Config {
	initTMRoot(rootDir)

	configFilePath := path.Join(rootDir, "config.toml")
	mapConfig, err := cfg.ReadMapConfigFromFile(configFilePath)
	if err != nil {
		Exit(Fmt("Could not read config: %v", err))
	}

	// Set defaults or panic
	if mapConfig.IsSet("chain_id") {
		Exit("Cannot set 'chain_id' via config.toml")
	}
	mapConfig.SetDefault("chain_id", "tendermint_test")
	mapConfig.SetDefault("genesis_file", rootDir+"/genesis.json")
	mapConfig.SetDefault("proxy_app", "dummy")
	mapConfig.SetDefault("moniker", "anonymous")
	mapConfig.SetDefault("node_laddr", "0.0.0.0:36656")
	mapConfig.SetDefault("fast_sync", false)
	mapConfig.SetDefault("skip_upnp", true)
	mapConfig.SetDefault("addrbook_file", rootDir+"/addrbook.json")
	mapConfig.SetDefault("priv_validator_file", rootDir+"/priv_validator.json")
	mapConfig.SetDefault("db_backend", "memdb")
	mapConfig.SetDefault("db_dir", rootDir+"/data")
	mapConfig.SetDefault("log_level", "debug")
	mapConfig.SetDefault("rpc_laddr", "0.0.0.0:36657")
	mapConfig.SetDefault("prof_laddr", "")
	mapConfig.SetDefault("revision_file", rootDir+"/revision")
	mapConfig.SetDefault("cswal", rootDir+"/data/cswal")
	mapConfig.SetDefault("cswal_light", false)

	mapConfig.SetDefault("block_size", 10000)
	mapConfig.SetDefault("timeout_propose", 100)
	mapConfig.SetDefault("timeout_propose_delta", 1)
	mapConfig.SetDefault("timeout_prevote", 1)
	mapConfig.SetDefault("timeout_prevote_delta", 1)
	mapConfig.SetDefault("timeout_precommit", 1)
	mapConfig.SetDefault("timeout_precommit_delta", 1)
	mapConfig.SetDefault("timeout_commit", 1)
	mapConfig.SetDefault("mempool_recheck", true)
	mapConfig.SetDefault("mempool_broadcast", true)

	return mapConfig
}

var defaultConfigTmpl = `# This is a TOML config file.
# For more information, see https://github.com/toml-lang/toml

proxy_app = "dummy"
moniker = "__MONIKER__"
node_laddr = "0.0.0.0:36656"
seeds = ""
fast_sync = false
db_backend = "memdb"
log_level = "debug"
rpc_laddr = "0.0.0.0:36657"
`

func defaultConfig(moniker string) (defaultConfig string) {
	defaultConfig = strings.Replace(defaultConfigTmpl, "__MONIKER__", moniker, -1)
	return
}

var defaultGenesis = `{
  "genesis_time": "0001-01-01T00:00:00.000Z",
  "chain_id": "tendermint_test",
  "validators": [
    {
      "pub_key": [
        1,
        "3B3069C422E19688B45CBFAE7BB009FC0FA1B1EA86593519318B7214853803C8"
      ],
      "amount": 10,
      "name": ""
    }
  ],
  "app_hash": ""
}`

var defaultPrivValidator = `{
  "address": "C12729D1CAC0E791FF12882E11A8A57620509722",
  "pub_key": [
    1,
    "3B3069C422E19688B45CBFAE7BB009FC0FA1B1EA86593519318B7214853803C8"
  ],
  "priv_key": [
    1,
    "27F82582AEFAE7AB151CFB01C48BB6C1A0DA78F9BDDA979A9F70A84D074EB07D3B3069C422E19688B45CBFAE7BB009FC0FA1B1EA86593519318B7214853803C8"
  ],
  "last_height": 0,
  "last_round": 0,
  "last_step": 0
}`
<commit_msg>Revert "Fix tendermint_test config -- Address() spec has changed"<commit_after>// Import this in all *_test.go files to initialize ~/.tendermint_test.

package tendermint_test

import (
	"os"
	"path"
	"strings"

	. "github.com/tendermint/go-common"
	cfg "github.com/tendermint/go-config"
)

func init() {
	// Creates ~/.tendermint_test
	EnsureDir(os.Getenv("HOME")+"/.tendermint_test", 0700)
}

func ResetConfig(path string) {
	rootDir := os.Getenv("HOME") + "/.tendermint_test/" + path
	cfg.ApplyConfig(GetConfig(rootDir))
}

func initTMRoot(rootDir string) {
	// Remove ~/.tendermint_test_bak
	if FileExists(rootDir + "_bak") {
		err := os.RemoveAll(rootDir + "_bak")
		if err != nil {
			PanicSanity(err.Error())
		}
	}
	// Move ~/.tendermint_test to ~/.tendermint_test_bak
	if FileExists(rootDir) {
		err := os.Rename(rootDir, rootDir+"_bak")
		if err != nil {
			PanicSanity(err.Error())
		}
	}
	// Create new dir
	EnsureDir(rootDir, 0700)

	configFilePath := path.Join(rootDir, "config.toml")
	genesisFilePath := path.Join(rootDir, "genesis.json")
	privFilePath := path.Join(rootDir, "priv_validator.json")

	// Write default config file if missing.
	if !FileExists(configFilePath) {
		// Ask user for moniker
		// moniker := cfg.Prompt("Type hostname: ", "anonymous")
		MustWriteFile(configFilePath, []byte(defaultConfig("anonymous")), 0644)
	}
	if !FileExists(genesisFilePath) {
		MustWriteFile(genesisFilePath, []byte(defaultGenesis), 0644)
	}
	// we always overwrite the priv val
	MustWriteFile(privFilePath, []byte(defaultPrivValidator), 0644)
}

func GetConfig(rootDir string) cfg.Config {
	initTMRoot(rootDir)

	configFilePath := path.Join(rootDir, "config.toml")
	mapConfig, err := cfg.ReadMapConfigFromFile(configFilePath)
	if err != nil {
		Exit(Fmt("Could not read config: %v", err))
	}

	// Set defaults or panic
	if mapConfig.IsSet("chain_id") {
		Exit("Cannot set 'chain_id' via config.toml")
	}
	mapConfig.SetDefault("chain_id", "tendermint_test")
	mapConfig.SetDefault("genesis_file", rootDir+"/genesis.json")
	mapConfig.SetDefault("proxy_app", "dummy")
	mapConfig.SetDefault("moniker", "anonymous")
	mapConfig.SetDefault("node_laddr", "0.0.0.0:36656")
	mapConfig.SetDefault("fast_sync", false)
	mapConfig.SetDefault("skip_upnp", true)
	mapConfig.SetDefault("addrbook_file", rootDir+"/addrbook.json")
	mapConfig.SetDefault("priv_validator_file", rootDir+"/priv_validator.json")
	mapConfig.SetDefault("db_backend", "memdb")
	mapConfig.SetDefault("db_dir", rootDir+"/data")
	mapConfig.SetDefault("log_level", "debug")
	mapConfig.SetDefault("rpc_laddr", "0.0.0.0:36657")
	mapConfig.SetDefault("prof_laddr", "")
	mapConfig.SetDefault("revision_file", rootDir+"/revision")
	mapConfig.SetDefault("cswal", rootDir+"/data/cswal")
	mapConfig.SetDefault("cswal_light", false)

	mapConfig.SetDefault("block_size", 10000)
	mapConfig.SetDefault("timeout_propose", 100)
	mapConfig.SetDefault("timeout_propose_delta", 1)
	mapConfig.SetDefault("timeout_prevote", 1)
	mapConfig.SetDefault("timeout_prevote_delta", 1)
	mapConfig.SetDefault("timeout_precommit", 1)
	mapConfig.SetDefault("timeout_precommit_delta", 1)
	mapConfig.SetDefault("timeout_commit", 1)
	mapConfig.SetDefault("mempool_recheck", true)
	mapConfig.SetDefault("mempool_broadcast", true)

	return mapConfig
}

var defaultConfigTmpl = `# This is a TOML config file.
# For more information, see https://github.com/toml-lang/toml

proxy_app = "dummy"
moniker = "__MONIKER__"
node_laddr = "0.0.0.0:36656"
seeds = ""
fast_sync = false
db_backend = "memdb"
log_level = "debug"
rpc_laddr = "0.0.0.0:36657"
`

func defaultConfig(moniker string) (defaultConfig string) {
	defaultConfig = strings.Replace(defaultConfigTmpl, "__MONIKER__", moniker, -1)
	return
}

var defaultGenesis = `{
  "genesis_time": "0001-01-01T00:00:00.000Z",
  "chain_id": "tendermint_test",
  "validators": [
    {
      "pub_key": [
        1,
        "3B3069C422E19688B45CBFAE7BB009FC0FA1B1EA86593519318B7214853803C8"
      ],
      "amount": 10,
      "name": ""
    }
  ],
  "app_hash": ""
}`

var defaultPrivValidator = `{
  "address": "D028C9981F7A87F3093672BF0D5B0E2A1B3ED456",
  "pub_key": [
    1,
    "3B3069C422E19688B45CBFAE7BB009FC0FA1B1EA86593519318B7214853803C8"
  ],
  "priv_key": [
    1,
    "27F82582AEFAE7AB151CFB01C48BB6C1A0DA78F9BDDA979A9F70A84D074EB07D3B3069C422E19688B45CBFAE7BB009FC0FA1B1EA86593519318B7214853803C8"
  ],
  "last_height": 0,
  "last_round": 0,
  "last_step": 0
}`
<|endoftext|>


<commit_before>package GoSDK

import (
	"encoding/json"
	"fmt"
	"net/url"
)

const (
	_DATA_PREAMBLE      = "/api/v/1/data/"
	_DATA_NAME_PREAMBLE = "/api/v/1/collection/"
)

//Inserts data into the platform. The interface is either a map[string]interface{} representing a row, or a []map[string]interface{} representing many rows.
func (u *UserClient) InsertData(collection_id string, data interface{}) error {
	_, err := insertdata(u, collection_id, data)
	return err
}

//Inserts data into the platform. The interface is either a map[string]interface{} representing a row, or a []map[string]interface{} representing many rows.
func (d *DevClient) InsertData(collection_id string, data interface{}) error {
	_, err := insertdata(d, collection_id, data)
	return err
}

//CreateData is an alias for InsertData, but returns a response value, it should be a slice of strings representing the item ids (if not using an external datastore)
func (d *DevClient) CreateData(collection_id string, data interface{}) ([]interface{}, error) {
	resp, err := insertdata(d, collection_id, data)
	if err != nil {
		return nil, err
	}
	return resp, nil
}

//CreateData is an alias for InsertData, but returns a response value, it should be a slice of strings representing the item ids (if not using an external datastore)
func (u *UserClient) CreateData(collection_id string, data interface{}) ([]interface{}, error) {
	resp, err := insertdata(u, collection_id, data)
	if err != nil {
		return nil, err
	}
	return resp, nil
}

func insertdata(c cbClient, collection_id string, data interface{}) ([]interface{}, error) {
	creds, err := c.credentials()
	if err != nil {
		return nil, err
	}
	resp, err := post(_DATA_PREAMBLE+collection_id, data, creds, nil)
	if err != nil {
		return nil, fmt.Errorf("Error inserting: %v", err)
	}
	if resp.StatusCode != 200 {
		return nil, fmt.Errorf("Error inserting: %v", resp.Body)
	}
	return resp.Body.([]interface{}), nil
}

//GetData performs a query against a collection. The query object is discussed elsewhere. If the query object is nil, then it will return all of the data.
//The return value is a key-value of the types. Note that due to the transport mechanism being JSON, ints will be turned into float64s.
func (u *UserClient) GetData(collection_id string, query *Query) (map[string]interface{}, error) {
	return getdata(u, collection_id, query)
}

//GetDataByName performs a query against a collection, using the collection's name, rather than the ID. The query object is discussed elsewhere. If the query object is nil, then it will return all of the data.
//The return value is a key-value of the types. Note that due to the transport mechanism being JSON, ints will be turned into float64s.
func (u *UserClient) GetDataByName(collectionName string, query *Query) (map[string]interface{}, error) {
	return getDataByName(u, u.SystemKey, collectionName, query)
}

//GetDataByName performs a query against a collection, using the collection's name, rather than the ID. The query object is discussed elsewhere. If the query object is nil, then it will return all of the data.
//The return value is a key-value of the types. Note that due to the transport mechanism being JSON, ints will be turned into float64s.

func (d *DevClient) GetDataByName(collectionName string, query *Query) (map[string]interface{}, error) {
	return nil, fmt.Errorf("Developer cannot call this yet")
}

//GetData performs a query against a collection. The query object is discussed elsewhere. If the query object is nil, then it will return all of the data.
//The return value is a key-value of the types. Note that due to the transport mechanism being JSON, ints will be turned into float64s.
func (d *DevClient) GetData(collection_id string, query *Query) (map[string]interface{}, error) {
	return getdata(d, collection_id, query)
}

func getDataByName(c cbClient, sysKey string, collectionName string, query *Query) (map[string]interface{}, error) {
	creds, err := c.credentials()
	if err != nil {
		return nil, err
	}
	var qry map[string]string
	if query != nil {
		query_map := query.serialize()
		query_bytes, err := json.Marshal(query_map)
		if err != nil {
			return nil, err
		}
		qry = map[string]string{
			"query": url.QueryEscape(string(query_bytes)),
		}
	} else {
		qry = nil
	}
	resp, err := get(_DATA_NAME_PREAMBLE+sysKey+"/"+collectionName, qry, creds, nil)
	if err != nil {
		return nil, fmt.Errorf("Error getting data: %v", err)
	}
	if resp.StatusCode != 200 {
		return nil, fmt.Errorf("Error getting data: %v", resp.Body)
	}
	return resp.Body.(map[string]interface{}), nil
}

func getdata(c cbClient, collection_id string, query *Query) (map[string]interface{}, error) {
	creds, err := c.credentials()
	if err != nil {
		return nil, err
	}
	var qry map[string]string
	if query != nil {
		query_map := query.serialize()
		query_bytes, err := json.Marshal(query_map)
		if err != nil {
			return nil, err
		}
		qry = map[string]string{
			"query": url.QueryEscape(string(query_bytes)),
		}
	} else {
		qry = nil
	}
	resp, err := get(_DATA_PREAMBLE+collection_id, qry, creds, nil)
	if err != nil {
		return nil, fmt.Errorf("Error getting data: %v", err)
	}
	if resp.StatusCode != 200 {
		return nil, fmt.Errorf("Error getting data: %v", resp.Body)
	}
	return resp.Body.(map[string]interface{}), nil
}

//UpdateData mutates the values in extant rows, selecting them via a query. If the query is nil, it updates all rows
//changes should be a map of the names of the columns, and the value you want them updated to
func (u *UserClient) UpdateData(collection_id string, query *Query, changes map[string]interface{}) error {
	err := updatedata(u, collection_id, query, changes)
	return err
}

//UpdateData mutates the values in extant rows, selecting them via a query. If the query is nil, it updates all rows
//changes should be a map of the names of the columns, and the value you want them updated to
func (d *DevClient) UpdateData(collection_id string, query *Query, changes map[string]interface{}) error {
	err := updatedata(d, collection_id, query, changes)
	return err
}

func updatedata(c cbClient, collection_id string, query *Query, changes map[string]interface{}) error {
	qry := query.serialize()
	body := map[string]interface{}{
		"query": qry,
		"$set":  changes,
	}
	creds, err := c.credentials()
	if err != nil {
		return err
	}
	resp, err := put(_DATA_PREAMBLE+collection_id, body, creds, nil)
	if err != nil {
		return fmt.Errorf("Error updating data: %v", err)
	}
	if resp.StatusCode != 200 {
		return fmt.Errorf("Error updating data: %v", resp.Body)
	}
	return nil
}

//DeleteData removes data from a collection according to what matches the query. If the query is nil, then all data will be removed.
func (u *UserClient) DeleteData(collection_id string, query *Query) error {
	return deletedata(u, collection_id, query)
}

//DeleteData removes data from a collection according to what matches the query. If the query is nil, then all data will be removed.
func (d *DevClient) DeleteData(collection_id string, query *Query) error {
	return deletedata(d, collection_id, query)
}

func deletedata(c cbClient, collection_id string, query *Query) error {
	creds, err := c.credentials()
	if err != nil {
		return err
	}
	var qry map[string]string
	if query != nil {
		query_map := query.serialize()
		query_bytes, err := json.Marshal(query_map)
		if err != nil {
			return err
		}
		qry = map[string]string{
			"query": url.QueryEscape(string(query_bytes)),
		}
	} else {
		qry = nil
	}
	resp, err := delete(_DATA_PREAMBLE+collection_id, qry, creds, nil)
	if err != nil {
		return fmt.Errorf("Error deleting data: %v", err)
	}
	if resp.StatusCode != 200 {
		return fmt.Errorf("Error deleting data: %v", resp.Body)
	}
	return nil
}

//GetColumns gets a slice of map[string]interface{} of the column names and values.
//As map[string]interface{}{"ColumnName":"name","ColumnType":"typename in string", "PK":bool}
func (d *DevClient) GetColumns(collection_id string) ([]interface{}, error) {
	return getColumns(d, collection_id)
}

//GetColumns gets a slice of map[string]interface{} of the column names and values.
//As map[string]interface{}{"ColumnName":"name","ColumnType":"typename in string", "PK":bool}
func (u *UserClient) GetColumns(collection_id string) ([]interface{}, error) {
	return getColumns(u, collection_id)
}

func getColumns(c cbClient, collection_id string) ([]interface{}, error) {
	creds, err := c.credentials()
	if err != nil {
		return nil, err
	}

	resp, err := get(_DATA_PREAMBLE+collection_id+"/columns", nil, creds, nil)
	if err != nil {
		return nil, fmt.Errorf("Error getting collection columns: %v", err)
	}
	if resp.StatusCode != 200 {
		return nil, fmt.Errorf("Error getting collection columns: %v", resp.Body)
	}
	return resp.Body.([]interface{}), nil
}

//GetDataByKeyAndName is unimplemented
func (d *DevClient) GetDataByKeyAndName(string, string, *Query) (map[string]interface{}, error) {
	return nil, fmt.Errorf("Unimplemented")
}

//GetDataByKeyAndName is unimplemented
func (d *UserClient) GetDataByKeyAndName(string, string, *Query) (map[string]interface{}, error) {
	return nil, fmt.Errorf("Unimplemented")

}
<commit_msg>add functions for dancenter support<commit_after>package GoSDK

import (
	"encoding/json"
	"fmt"
	"net/url"
)

const (
	_DATA_PREAMBLE      = "/api/v/1/data/"
	_DATA_NAME_PREAMBLE = "/api/v/1/collection/"
)

//Inserts data into the platform. The interface is either a map[string]interface{} representing a row, or a []map[string]interface{} representing many rows.
func (u *UserClient) InsertData(collection_id string, data interface{}) error {
	_, err := insertdata(u, collection_id, data)
	return err
}

//Inserts data into the platform. The interface is either a map[string]interface{} representing a row, or a []map[string]interface{} representing many rows.
func (d *DevClient) InsertData(collection_id string, data interface{}) error {
	_, err := insertdata(d, collection_id, data)
	return err
}

//CreateData is an alias for InsertData, but returns a response value, it should be a slice of strings representing the item ids (if not using an external datastore)
func (d *DevClient) CreateData(collection_id string, data interface{}) ([]interface{}, error) {
	resp, err := insertdata(d, collection_id, data)
	if err != nil {
		return nil, err
	}
	return resp, nil
}

//CreateData is an alias for InsertData, but returns a response value, it should be a slice of strings representing the item ids (if not using an external datastore)
func (u *UserClient) CreateData(collection_id string, data interface{}) ([]interface{}, error) {
	resp, err := insertdata(u, collection_id, data)
	if err != nil {
		return nil, err
	}
	return resp, nil
}

func insertdata(c cbClient, collection_id string, data interface{}) ([]interface{}, error) {
	creds, err := c.credentials()
	if err != nil {
		return nil, err
	}
	resp, err := post(_DATA_PREAMBLE+collection_id, data, creds, nil)
	if err != nil {
		return nil, fmt.Errorf("Error inserting: %v", err)
	}
	if resp.StatusCode != 200 {
		return nil, fmt.Errorf("Error inserting: %v", resp.Body)
	}
	return resp.Body.([]interface{}), nil
}

//GetData performs a query against a collection. The query object is discussed elsewhere. If the query object is nil, then it will return all of the data.
//The return value is a key-value of the types. Note that due to the transport mechanism being JSON, ints will be turned into float64s.
func (u *UserClient) GetData(collection_id string, query *Query) (map[string]interface{}, error) {
	return getdata(u, collection_id, query)
}

//GetDataByName performs a query against a collection, using the collection's name, rather than the ID. The query object is discussed elsewhere. If the query object is nil, then it will return all of the data.
//The return value is a key-value of the types. Note that due to the transport mechanism being JSON, ints will be turned into float64s.
func (u *UserClient) GetDataByName(collectionName string, query *Query) (map[string]interface{}, error) {
	return getDataByName(u, u.SystemKey, collectionName, query)
}

//GetDataByName performs a query against a collection, using the collection's name, rather than the ID. The query object is discussed elsewhere. If the query object is nil, then it will return all of the data.
//The return value is a key-value of the types. Note that due to the transport mechanism being JSON, ints will be turned into float64s.

func (d *DevClient) GetDataByName(collectionName string, query *Query) (map[string]interface{}, error) {
	return nil, fmt.Errorf("Developer cannot call this yet")
}

//GetData performs a query against a collection. The query object is discussed elsewhere. If the query object is nil, then it will return all of the data.
//The return value is a key-value of the types. Note that due to the transport mechanism being JSON, ints will be turned into float64s.
func (d *DevClient) GetData(collection_id string, query *Query) (map[string]interface{}, error) {
	return getdata(d, collection_id, query)
}

func (d *DevClient) GetDataTotal(collection_id string, query *Query) (map[string]interface{}, error) {
	return getdatatotal(d, collection_id, query)
}

func getDataByName(c cbClient, sysKey string, collectionName string, query *Query) (map[string]interface{}, error) {
	creds, err := c.credentials()
	if err != nil {
		return nil, err
	}
	var qry map[string]string
	if query != nil {
		query_map := query.serialize()
		query_bytes, err := json.Marshal(query_map)
		if err != nil {
			return nil, err
		}
		qry = map[string]string{
			"query": url.QueryEscape(string(query_bytes)),
		}
	} else {
		qry = nil
	}
	resp, err := get(_DATA_NAME_PREAMBLE+sysKey+"/"+collectionName, qry, creds, nil)
	if err != nil {
		return nil, fmt.Errorf("Error getting data: %v", err)
	}
	if resp.StatusCode != 200 {
		return nil, fmt.Errorf("Error getting data: %v", resp.Body)
	}
	return resp.Body.(map[string]interface{}), nil
}

func getdata(c cbClient, collection_id string, query *Query) (map[string]interface{}, error) {
	creds, err := c.credentials()
	if err != nil {
		return nil, err
	}
	var qry map[string]string
	if query != nil {
		query_map := query.serialize()
		query_bytes, err := json.Marshal(query_map)
		if err != nil {
			return nil, err
		}
		qry = map[string]string{
			"query": url.QueryEscape(string(query_bytes)),
		}
	} else {
		qry = nil
	}
	resp, err := get(_DATA_PREAMBLE+collection_id, qry, creds, nil)
	if err != nil {
		return nil, fmt.Errorf("Error getting data: %v", err)
	}
	if resp.StatusCode != 200 {
		return nil, fmt.Errorf("Error getting data: %v", resp.Body)
	}
	return resp.Body.(map[string]interface{}), nil
}

func getdatatotal(c cbClient, collection_id string, query *Query) (map[string]interface{}, error) {
	creds, err := c.credentials()
	if err != nil {
		return nil, err
	}
	var qry map[string]string
	if query != nil {
		query_map := query.serialize()
		query_bytes, err := json.Marshal(query_map)
		if err != nil {
			return nil, err
		}
		qry = map[string]string{
			"query": url.QueryEscape(string(query_bytes)),
		}
	} else {
		qry = nil
	}
	resp, err := get(_DATA_PREAMBLE+collection_id+"/count", qry, creds, nil)
	if err != nil {
		return nil, fmt.Errorf("Error getting data: %v", err)
	}
	if resp.StatusCode != 200 {
		return nil, fmt.Errorf("Error getting data: %v", resp.Body)
	}
	return resp.Body.(map[string]interface{}), nil
}

//UpdateData mutates the values in extant rows, selecting them via a query. If the query is nil, it updates all rows
//changes should be a map of the names of the columns, and the value you want them updated to

func (u *UserClient) UpdateData(collection_id string, query *Query, changes map[string]interface{}) error {
	err := updatedata(u, collection_id, query, changes)
	return err
}

//UpdateData mutates the values in extant rows, selecting them via a query. If the query is nil, it updates all rows
//changes should be a map of the names of the columns, and the value you want them updated to
func (d *DevClient) UpdateData(collection_id string, query *Query, changes map[string]interface{}) error {
	err := updatedata(d, collection_id, query, changes)
	return err
}

func updatedata(c cbClient, collection_id string, query *Query, changes map[string]interface{}) error {
	qry := query.serialize()
	body := map[string]interface{}{
		"query": qry,
		"$set":  changes,
	}
	creds, err := c.credentials()
	if err != nil {
		return err
	}
	resp, err := put(_DATA_PREAMBLE+collection_id, body, creds, nil)
	if err != nil {
		return fmt.Errorf("Error updating data: %v", err)
	}
	if resp.StatusCode != 200 {
		return fmt.Errorf("Error updating data: %v", resp.Body)
	}
	return nil
}

//DeleteData removes data from a collection according to what matches the query. If the query is nil, then all data will be removed.
func (u *UserClient) DeleteData(collection_id string, query *Query) error {
	return deletedata(u, collection_id, query)
}

//DeleteData removes data from a collection according to what matches the query. If the query is nil, then all data will be removed.
func (d *DevClient) DeleteData(collection_id string, query *Query) error {
	return deletedata(d, collection_id, query)
}

func deletedata(c cbClient, collection_id string, query *Query) error {
	creds, err := c.credentials()
	if err != nil {
		return err
	}
	var qry map[string]string
	if query != nil {
		query_map := query.serialize()
		query_bytes, err := json.Marshal(query_map)
		if err != nil {
			return err
		}
		qry = map[string]string{
			"query": url.QueryEscape(string(query_bytes)),
		}
	} else {
		qry = nil
	}
	resp, err := delete(_DATA_PREAMBLE+collection_id, qry, creds, nil)
	if err != nil {
		return fmt.Errorf("Error deleting data: %v", err)
	}
	if resp.StatusCode != 200 {
		return fmt.Errorf("Error deleting data: %v", resp.Body)
	}
	return nil
}

//GetColumns gets a slice of map[string]interface{} of the column names and values.
//As map[string]interface{}{"ColumnName":"name","ColumnType":"typename in string", "PK":bool}
func (d *DevClient) GetColumns(collection_id string) ([]interface{}, error) {
	return getColumns(d, collection_id)
}

//GetColumns gets a slice of map[string]interface{} of the column names and values.
//As map[string]interface{}{"ColumnName":"name","ColumnType":"typename in string", "PK":bool}
func (u *UserClient) GetColumns(collection_id string) ([]interface{}, error) {
	return getColumns(u, collection_id)
}

func getColumns(c cbClient, collection_id string) ([]interface{}, error) {
	creds, err := c.credentials()
	if err != nil {
		return nil, err
	}

	resp, err := get(_DATA_PREAMBLE+collection_id+"/columns", nil, creds, nil)
	if err != nil {
		return nil, fmt.Errorf("Error getting collection columns: %v", err)
	}
	if resp.StatusCode != 200 {
		return nil, fmt.Errorf("Error getting collection columns: %v", resp.Body)
	}
	return resp.Body.([]interface{}), nil
}

//GetDataByKeyAndName is unimplemented
func (d *DevClient) GetDataByKeyAndName(string, string, *Query) (map[string]interface{}, error) {
	return nil, fmt.Errorf("Unimplemented")
}

//GetDataByKeyAndName is unimplemented
func (d *UserClient) GetDataByKeyAndName(string, string, *Query) (map[string]interface{}, error) {
	return nil, fmt.Errorf("Unimplemented")

}
<|endoftext|>


<commit_before>package GoSDK

import (
	"encoding/json"
	"fmt"
	"net/url"
)

const (
	_DATA_PREAMBLE      = "/api/v/1/data/"
	_DATA_NAME_PREAMBLE = "/api/v/1/collection/"
)

//Inserts data into the platform. The interface is either a map[string]interface{} representing a row, or a []map[string]interface{} representing many rows.
func (u *UserClient) InsertData(collection_id string, data interface{}) error {
	_, err := insertdata(u, collection_id, data)
	return err
}

//Inserts data into the platform. The interface is either a map[string]interface{} representing a row, or a []map[string]interface{} representing many rows.
func (d *DevClient) InsertData(collection_id string, data interface{}) error {
	_, err := insertdata(d, collection_id, data)
	return err
}

//CreateData is an alias for InsertData, but returns a response value, it should be a slice of strings representing the item ids (if not using an external datastore)
func (d *DevClient) CreateData(collection_id string, data interface{}) ([]interface{}, error) {
	resp, err := insertdata(d, collection_id, data)
	if err != nil {
		return nil, err
	}
	return resp, nil
}

//CreateData is an alias for InsertData, but returns a response value, it should be a slice of strings representing the item ids (if not using an external datastore)
func (u *UserClient) CreateData(collection_id string, data interface{}) ([]interface{}, error) {
	resp, err := insertdata(u, collection_id, data)
	if err != nil {
		return nil, err
	}
	return resp, nil
}

func insertdata(c cbClient, collection_id string, data interface{}) ([]interface{}, error) {
	creds, err := c.credentials()
	if err != nil {
		return nil, err
	}
	resp, err := post(_DATA_PREAMBLE+collection_id, data, creds, nil)
	if err != nil {
		return nil, fmt.Errorf("Error inserting: %v", err)
	}
	if resp.StatusCode != 200 {
		return nil, fmt.Errorf("Error inserting: %v", resp.Body)
	}
	return resp.Body.([]interface{}), nil
}

//GetData performs a query against a collection. The query object is discussed elsewhere. If the query object is nil, then it will return all of the data.
//The return value is a key-value of the types. Note that due to the transport mechanism being JSON, ints will be turned into float64s.
func (u *UserClient) GetData(collection_id string, query *Query) (map[string]interface{}, error) {
	return getdata(u, collection_id, query)
}

//GetDataByName performs a query against a collection, using the collection's name, rather than the ID. The query object is discussed elsewhere. If the query object is nil, then it will return all of the data.
//The return value is a key-value of the types. Note that due to the transport mechanism being JSON, ints will be turned into float64s.
func (u *UserClient) GetDataByName(collectionName string, query *Query) (map[string]interface{}, error) {
	return getDataByName(u, u.SystemKey, collectionName, query)
}

//GetDataByName performs a query against a collection, using the collection's name, rather than the ID. The query object is discussed elsewhere. If the query object is nil, then it will return all of the data.
//The return value is a key-value of the types. Note that due to the transport mechanism being JSON, ints will be turned into float64s.

func (d *DevClient) GetDataByName(collectionName string, query *Query) (map[string]interface{}, error) {
	return nil, fmt.Errorf("Developer cannot call this yet")
}

//GetData performs a query against a collection. The query object is discussed elsewhere. If the query object is nil, then it will return all of the data.
//The return value is a key-value of the types. Note that due to the transport mechanism being JSON, ints will be turned into float64s.
func (d *DevClient) GetData(collection_id string, query *Query) (map[string]interface{}, error) {
	return getdata(d, collection_id, query)
}

<<<<<<< HEAD
func (d *UserClient) GetDataTotal(collection_id string, query *Query) (map[string]interface{}, error) {
	return getdatatotal(d, collection_id, query)
=======
func (u *UserClient) GetItemCount(collection_id string) (int, error) {
	return getItemCount(u, collection_id)
}

func (d *DevClient) GetItemCount(collection_id string) (int, error) {
	return getItemCount(d, collection_id)
}

func getItemCount(c cbClient, collection_id string) (int, error) {
	creds, err := c.credentials()
	if err != nil {
		return -1, err
	}
	resp, err := get(_DATA_PREAMBLE+collection_id+"/count", nil, creds, nil)
	if err != nil {
		return -1, fmt.Errorf("Error getting count: %v", err)
	}
	if resp.StatusCode != 200 {
		return -1, fmt.Errorf("Error getting count: %v", resp.Body)
	}
	bod := resp.Body.(map[string]interface{})
	theCount := int(bod["count"].(float64))
	return theCount, nil
>>>>>>> 2875f30784df9cd37801a04fde74889c310d392f
}

func getDataByName(c cbClient, sysKey string, collectionName string, query *Query) (map[string]interface{}, error) {
	creds, err := c.credentials()
	if err != nil {
		return nil, err
	}
	var qry map[string]string
	if query != nil {
		query_map := query.serialize()
		query_bytes, err := json.Marshal(query_map)
		if err != nil {
			return nil, err
		}
		qry = map[string]string{
			"query": url.QueryEscape(string(query_bytes)),
		}
	} else {
		qry = nil
	}
	resp, err := get(_DATA_NAME_PREAMBLE+sysKey+"/"+collectionName, qry, creds, nil)
	if err != nil {
		return nil, fmt.Errorf("Error getting data: %v", err)
	}
	if resp.StatusCode != 200 {
		return nil, fmt.Errorf("Error getting data: %v", resp.Body)
	}
	return resp.Body.(map[string]interface{}), nil
}

func getdata(c cbClient, collection_id string, query *Query) (map[string]interface{}, error) {
	creds, err := c.credentials()
	if err != nil {
		return nil, err
	}
	var qry map[string]string
	if query != nil {
		query_map := query.serialize()
		query_bytes, err := json.Marshal(query_map)
		if err != nil {
			return nil, err
		}
		qry = map[string]string{
			"query": url.QueryEscape(string(query_bytes)),
		}
	} else {
		qry = nil
	}
	resp, err := get(_DATA_PREAMBLE+collection_id, qry, creds, nil)
	if err != nil {
		return nil, fmt.Errorf("Error getting data: %v", err)
	}
	if resp.StatusCode != 200 {
		return nil, fmt.Errorf("Error getting data: %v", resp.Body)
	}
	return resp.Body.(map[string]interface{}), nil
}

func getdatatotal(c cbClient, collection_id string, query *Query) (map[string]interface{}, error) {

	creds, err := c.credentials()
	if err != nil {
		return nil, err
	}
	var qry map[string]string
	if query != nil {
		query_map := query.serialize()
		query_bytes, err := json.Marshal(query_map)
		if err != nil {
			return nil, err
		}
		qry = map[string]string{
			"query": url.QueryEscape(string(query_bytes)),
		}
	} else {
		qry = nil
	}
	resp, err := get(_DATA_PREAMBLE+collection_id+"/count", qry, creds, nil)
	if err != nil {
		return nil, fmt.Errorf("Error getting data: %v", err)
	}
	if resp.StatusCode != 200 {
		return nil, fmt.Errorf("Error getting data: %v", resp.Body)
	}
	return resp.Body.(map[string]interface{}), nil
}

//UpdateData mutates the values in extant rows, selecting them via a query. If the query is nil, it updates all rows
//changes should be a map of the names of the columns, and the value you want them updated to

func (u *UserClient) UpdateData(collection_id string, query *Query, changes map[string]interface{}) error {
	err := updatedata(u, collection_id, query, changes)
	return err
}

//UpdateData mutates the values in extant rows, selecting them via a query. If the query is nil, it updates all rows
//changes should be a map of the names of the columns, and the value you want them updated to
func (d *DevClient) UpdateData(collection_id string, query *Query, changes map[string]interface{}) error {
	err := updatedata(d, collection_id, query, changes)
	return err
}

func updatedata(c cbClient, collection_id string, query *Query, changes map[string]interface{}) error {
	qry := query.serialize()
	body := map[string]interface{}{
		"query": qry,
		"$set":  changes,
	}
	creds, err := c.credentials()
	if err != nil {
		return err
	}
	resp, err := put(_DATA_PREAMBLE+collection_id, body, creds, nil)
	if err != nil {
		return fmt.Errorf("Error updating data: %v", err)
	}
	if resp.StatusCode != 200 {
		return fmt.Errorf("Error updating data: %v", resp.Body)
	}
	return nil
}

//DeleteData removes data from a collection according to what matches the query. If the query is nil, then all data will be removed.
func (u *UserClient) DeleteData(collection_id string, query *Query) error {
	return deletedata(u, collection_id, query)
}

//DeleteData removes data from a collection according to what matches the query. If the query is nil, then all data will be removed.
func (d *DevClient) DeleteData(collection_id string, query *Query) error {
	return deletedata(d, collection_id, query)
}

func deletedata(c cbClient, collection_id string, query *Query) error {
	creds, err := c.credentials()
	if err != nil {
		return err
	}
	var qry map[string]string
	if query != nil {
		query_map := query.serialize()
		query_bytes, err := json.Marshal(query_map)
		if err != nil {
			return err
		}
		qry = map[string]string{
			"query": url.QueryEscape(string(query_bytes)),
		}
	} else {
		qry = nil
	}
	resp, err := delete(_DATA_PREAMBLE+collection_id, qry, creds, nil)
	if err != nil {
		return fmt.Errorf("Error deleting data: %v", err)
	}
	if resp.StatusCode != 200 {
		return fmt.Errorf("Error deleting data: %v", resp.Body)
	}
	return nil
}

//GetColumns gets a slice of map[string]interface{} of the column names and values.
//As map[string]interface{}{"ColumnName":"name","ColumnType":"typename in string", "PK":bool}
func (d *DevClient) GetColumns(collectionId, systemKey, systemSecret string) ([]interface{}, error) {
	return getColumns(d, collectionId, systemKey, systemSecret)
}

//GetColumns gets a slice of map[string]interface{} of the column names and values.
//As map[string]interface{}{"ColumnName":"name","ColumnType":"typename in string", "PK":bool}
func (u *UserClient) GetColumns(collection_id string) ([]interface{}, error) {
	return getColumns(u, collection_id, "", "")
}

func getColumns(c cbClient, collection_id, systemKey, systemSecret string) ([]interface{}, error) {
	creds, err := c.credentials()
	if err != nil {
		return nil, err
	}

	var headers map[string][]string = nil
	if systemKey != "" {
		headers = map[string][]string{
			"Clearblade-Systemkey":    []string{systemKey},
			"Clearblade-Systemsecret": []string{systemSecret},
		}
	}

	resp, err := get(_DATA_PREAMBLE+collection_id+"/columns", nil, creds, headers)
	if err != nil {
		return nil, fmt.Errorf("Error getting collection columns: %v", err)
	}
	if resp.StatusCode != 200 {
		return nil, fmt.Errorf("Error getting collection columns: %v", resp.Body)
	}
	return resp.Body.([]interface{}), nil
}

//GetDataByKeyAndName is unimplemented
func (d *DevClient) GetDataByKeyAndName(string, string, *Query) (map[string]interface{}, error) {
	return nil, fmt.Errorf("Unimplemented")
}

//GetDataByKeyAndName is unimplemented
func (d *UserClient) GetDataByKeyAndName(string, string, *Query) (map[string]interface{}, error) {
	return nil, fmt.Errorf("Unimplemented")

}
<commit_msg> changes made for PR and merge conflicts<commit_after>package GoSDK

import (
	"encoding/json"
	"fmt"
	"net/url"
)

const (
	_DATA_PREAMBLE      = "/api/v/1/data/"
	_DATA_NAME_PREAMBLE = "/api/v/1/collection/"
)

//Inserts data into the platform. The interface is either a map[string]interface{} representing a row, or a []map[string]interface{} representing many rows.
func (u *UserClient) InsertData(collection_id string, data interface{}) error {
	_, err := insertdata(u, collection_id, data)
	return err
}

//Inserts data into the platform. The interface is either a map[string]interface{} representing a row, or a []map[string]interface{} representing many rows.
func (d *DevClient) InsertData(collection_id string, data interface{}) error {
	_, err := insertdata(d, collection_id, data)
	return err
}

//CreateData is an alias for InsertData, but returns a response value, it should be a slice of strings representing the item ids (if not using an external datastore)
func (d *DevClient) CreateData(collection_id string, data interface{}) ([]interface{}, error) {
	resp, err := insertdata(d, collection_id, data)
	if err != nil {
		return nil, err
	}
	return resp, nil
}

//CreateData is an alias for InsertData, but returns a response value, it should be a slice of strings representing the item ids (if not using an external datastore)
func (u *UserClient) CreateData(collection_id string, data interface{}) ([]interface{}, error) {
	resp, err := insertdata(u, collection_id, data)
	if err != nil {
		return nil, err
	}
	return resp, nil
}

func insertdata(c cbClient, collection_id string, data interface{}) ([]interface{}, error) {
	creds, err := c.credentials()
	if err != nil {
		return nil, err
	}
	resp, err := post(_DATA_PREAMBLE+collection_id, data, creds, nil)
	if err != nil {
		return nil, fmt.Errorf("Error inserting: %v", err)
	}
	if resp.StatusCode != 200 {
		return nil, fmt.Errorf("Error inserting: %v", resp.Body)
	}
	return resp.Body.([]interface{}), nil
}

//GetData performs a query against a collection. The query object is discussed elsewhere. If the query object is nil, then it will return all of the data.
//The return value is a key-value of the types. Note that due to the transport mechanism being JSON, ints will be turned into float64s.
func (u *UserClient) GetData(collection_id string, query *Query) (map[string]interface{}, error) {
	return getdata(u, collection_id, query)
}

//GetDataByName performs a query against a collection, using the collection's name, rather than the ID. The query object is discussed elsewhere. If the query object is nil, then it will return all of the data.
//The return value is a key-value of the types. Note that due to the transport mechanism being JSON, ints will be turned into float64s.
func (u *UserClient) GetDataByName(collectionName string, query *Query) (map[string]interface{}, error) {
	return getDataByName(u, u.SystemKey, collectionName, query)
}

//GetDataByName performs a query against a collection, using the collection's name, rather than the ID. The query object is discussed elsewhere. If the query object is nil, then it will return all of the data.
//The return value is a key-value of the types. Note that due to the transport mechanism being JSON, ints will be turned into float64s.

func (d *DevClient) GetDataByName(collectionName string, query *Query) (map[string]interface{}, error) {
	return nil, fmt.Errorf("Developer cannot call this yet")
}

//GetData performs a query against a collection. The query object is discussed elsewhere. If the query object is nil, then it will return all of the data.
//The return value is a key-value of the types. Note that due to the transport mechanism being JSON, ints will be turned into float64s.
func (d *DevClient) GetData(collection_id string, query *Query) (map[string]interface{}, error) {
	return getdata(d, collection_id, query)
}

func (d *UserClient) GetDataTotal(collection_id string, query *Query) (map[string]interface{}, error) {
	return getdatatotal(d, collection_id, query)

func (u *UserClient) GetItemCount(collection_id string) (int, error) {
	return getItemCount(u, collection_id)
}

func (d *DevClient) GetItemCount(collection_id string) (int, error) {
	return getItemCount(d, collection_id)
}

func getItemCount(c cbClient, collection_id string) (int, error) {
	creds, err := c.credentials()
	if err != nil {
		return -1, err
	}
	resp, err := get(_DATA_PREAMBLE+collection_id+"/count", nil, creds, nil)
	if err != nil {
		return -1, fmt.Errorf("Error getting count: %v", err)
	}
	if resp.StatusCode != 200 {
		return -1, fmt.Errorf("Error getting count: %v", resp.Body)
	}
	bod := resp.Body.(map[string]interface{})
	theCount := int(bod["count"].(float64))
	return theCount, nil

}

func getDataByName(c cbClient, sysKey string, collectionName string, query *Query) (map[string]interface{}, error) {
	creds, err := c.credentials()
	if err != nil {
		return nil, err
	}
	var qry map[string]string
	if query != nil {
		query_map := query.serialize()
		query_bytes, err := json.Marshal(query_map)
		if err != nil {
			return nil, err
		}
		qry = map[string]string{
			"query": url.QueryEscape(string(query_bytes)),
		}
	} else {
		qry = nil
	}
	resp, err := get(_DATA_NAME_PREAMBLE+sysKey+"/"+collectionName, qry, creds, nil)
	if err != nil {
		return nil, fmt.Errorf("Error getting data: %v", err)
	}
	if resp.StatusCode != 200 {
		return nil, fmt.Errorf("Error getting data: %v", resp.Body)
	}
	return resp.Body.(map[string]interface{}), nil
}

func getdata(c cbClient, collection_id string, query *Query) (map[string]interface{}, error) {
	creds, err := c.credentials()
	if err != nil {
		return nil, err
	}
	var qry map[string]string
	if query != nil {
		query_map := query.serialize()
		query_bytes, err := json.Marshal(query_map)
		if err != nil {
			return nil, err
		}
		qry = map[string]string{
			"query": url.QueryEscape(string(query_bytes)),
		}
	} else {
		qry = nil
	}
	resp, err := get(_DATA_PREAMBLE+collection_id, qry, creds, nil)
	if err != nil {
		return nil, fmt.Errorf("Error getting data: %v", err)
	}
	if resp.StatusCode != 200 {
		return nil, fmt.Errorf("Error getting data: %v", resp.Body)
	}
	return resp.Body.(map[string]interface{}), nil
}

func getdatatotal(c cbClient, collection_id string, query *Query) (map[string]interface{}, error) {

	creds, err := c.credentials()
	if err != nil {
		return nil, err
	}
	var qry map[string]string
	if query != nil {
		query_map := query.serialize()
		query_bytes, err := json.Marshal(query_map)
		if err != nil {
			return nil, err
		}
		qry = map[string]string{
			"query": url.QueryEscape(string(query_bytes)),
		}
	} else {
		qry = nil
	}
	resp, err := get(_DATA_PREAMBLE+collection_id+"/count", qry, creds, nil)
	if err != nil {
		return nil, fmt.Errorf("Error getting data: %v", err)
	}
	if resp.StatusCode != 200 {
		return nil, fmt.Errorf("Error getting data: %v", resp.Body)
	}
	return resp.Body.(map[string]interface{}), nil
}

//UpdateData mutates the values in extant rows, selecting them via a query. If the query is nil, it updates all rows
//changes should be a map of the names of the columns, and the value you want them updated to

func (u *UserClient) UpdateData(collection_id string, query *Query, changes map[string]interface{}) error {
	err := updatedata(u, collection_id, query, changes)
	return err
}

//UpdateData mutates the values in extant rows, selecting them via a query. If the query is nil, it updates all rows
//changes should be a map of the names of the columns, and the value you want them updated to
func (d *DevClient) UpdateData(collection_id string, query *Query, changes map[string]interface{}) error {
	err := updatedata(d, collection_id, query, changes)
	return err
}

func updatedata(c cbClient, collection_id string, query *Query, changes map[string]interface{}) error {
	qry := query.serialize()
	body := map[string]interface{}{
		"query": qry,
		"$set":  changes,
	}
	creds, err := c.credentials()
	if err != nil {
		return err
	}
	resp, err := put(_DATA_PREAMBLE+collection_id, body, creds, nil)
	if err != nil {
		return fmt.Errorf("Error updating data: %v", err)
	}
	if resp.StatusCode != 200 {
		return fmt.Errorf("Error updating data: %v", resp.Body)
	}
	return nil
}

//DeleteData removes data from a collection according to what matches the query. If the query is nil, then all data will be removed.
func (u *UserClient) DeleteData(collection_id string, query *Query) error {
	return deletedata(u, collection_id, query)
}

//DeleteData removes data from a collection according to what matches the query. If the query is nil, then all data will be removed.
func (d *DevClient) DeleteData(collection_id string, query *Query) error {
	return deletedata(d, collection_id, query)
}

func deletedata(c cbClient, collection_id string, query *Query) error {
	creds, err := c.credentials()
	if err != nil {
		return err
	}
	var qry map[string]string
	if query != nil {
		query_map := query.serialize()
		query_bytes, err := json.Marshal(query_map)
		if err != nil {
			return err
		}
		qry = map[string]string{
			"query": url.QueryEscape(string(query_bytes)),
		}
	} else {
		qry = nil
	}
	resp, err := delete(_DATA_PREAMBLE+collection_id, qry, creds, nil)
	if err != nil {
		return fmt.Errorf("Error deleting data: %v", err)
	}
	if resp.StatusCode != 200 {
		return fmt.Errorf("Error deleting data: %v", resp.Body)
	}
	return nil
}

//GetColumns gets a slice of map[string]interface{} of the column names and values.
//As map[string]interface{}{"ColumnName":"name","ColumnType":"typename in string", "PK":bool}
func (d *DevClient) GetColumns(collectionId, systemKey, systemSecret string) ([]interface{}, error) {
	return getColumns(d, collectionId, systemKey, systemSecret)
}

//GetColumns gets a slice of map[string]interface{} of the column names and values.
//As map[string]interface{}{"ColumnName":"name","ColumnType":"typename in string", "PK":bool}
func (u *UserClient) GetColumns(collection_id string) ([]interface{}, error) {
	return getColumns(u, collection_id, "", "")
}

func getColumns(c cbClient, collection_id, systemKey, systemSecret string) ([]interface{}, error) {
	creds, err := c.credentials()
	if err != nil {
		return nil, err
	}

	var headers map[string][]string = nil
	if systemKey != "" {
		headers = map[string][]string{
			"Clearblade-Systemkey":    []string{systemKey},
			"Clearblade-Systemsecret": []string{systemSecret},
		}
	}

	resp, err := get(_DATA_PREAMBLE+collection_id+"/columns", nil, creds, headers)
	if err != nil {
		return nil, fmt.Errorf("Error getting collection columns: %v", err)
	}
	if resp.StatusCode != 200 {
		return nil, fmt.Errorf("Error getting collection columns: %v", resp.Body)
	}
	return resp.Body.([]interface{}), nil
}

//GetDataByKeyAndName is unimplemented
func (d *DevClient) GetDataByKeyAndName(string, string, *Query) (map[string]interface{}, error) {
	return nil, fmt.Errorf("Unimplemented")
}

//GetDataByKeyAndName is unimplemented
func (d *UserClient) GetDataByKeyAndName(string, string, *Query) (map[string]interface{}, error) {
	return nil, fmt.Errorf("Unimplemented")

}
<|endoftext|>