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

package tls

import (
	"crypto"
	"crypto/hmac"
	"crypto/md5"
	"crypto/sha1"
	"crypto/sha256"
	"crypto/sha512"
	"errors"
	"fmt"
	"hash"
)

// Split a premaster secret in two as specified in RFC 4346, section 5.
func splitPreMasterSecret(secret []byte) (s1, s2 []byte) {
	s1 = secret[0 : (len(secret)+1)/2]
	s2 = secret[len(secret)/2:]
	return
}

// pHash implements the P_hash function, as defined in RFC 4346, section 5.
func pHash(result, secret, seed []byte, hash func() hash.Hash) {
	h := hmac.New(hash, secret)
	h.Write(seed)
	a := h.Sum(nil)

	j := 0
	for j < len(result) {
		h.Reset()
		h.Write(a)
		h.Write(seed)
		b := h.Sum(nil)
		todo := len(b)
		if j+todo > len(result) {
			todo = len(result) - j
		}
		copy(result[j:j+todo], b)
		j += todo

		h.Reset()
		h.Write(a)
		a = h.Sum(nil)
	}
}

// prf10 implements the TLS 1.0 pseudo-random function, as defined in RFC 2246, section 5.
func prf10(result, secret, label, seed []byte) {
	hashSHA1 := sha1.New
	hashMD5 := md5.New

	labelAndSeed := make([]byte, len(label)+len(seed))
	copy(labelAndSeed, label)
	copy(labelAndSeed[len(label):], seed)

	s1, s2 := splitPreMasterSecret(secret)
	pHash(result, s1, labelAndSeed, hashMD5)
	result2 := make([]byte, len(result))
	pHash(result2, s2, labelAndSeed, hashSHA1)

	for i, b := range result2 {
		result[i] ^= b
	}
}

// prf12 implements the TLS 1.2 pseudo-random function, as defined in RFC 5246, section 5.
func prf12(hashFunc func() hash.Hash) func(result, secret, label, seed []byte) {
	return func(result, secret, label, seed []byte) {
		labelAndSeed := make([]byte, len(label)+len(seed))
		copy(labelAndSeed, label)
		copy(labelAndSeed[len(label):], seed)

		pHash(result, secret, labelAndSeed, hashFunc)
	}
}

// prf30 implements the SSL 3.0 pseudo-random function, as defined in
// www.mozilla.org/projects/security/pki/nss/ssl/draft302.txt section 6.
func prf30(result, secret, label, seed []byte) {
	hashSHA1 := sha1.New()
	hashMD5 := md5.New()

	done := 0
	i := 0
	// RFC 5246 section 6.3 says that the largest PRF output needed is 128
	// bytes. Since no more ciphersuites will be added to SSLv3, this will
	// remain true. Each iteration gives us 16 bytes so 10 iterations will
	// be sufficient.
	var b [11]byte
	for done < len(result) {
		for j := 0; j <= i; j++ {
			b[j] = 'A' + byte(i)
		}

		hashSHA1.Reset()
		hashSHA1.Write(b[:i+1])
		hashSHA1.Write(secret)
		hashSHA1.Write(seed)
		digest := hashSHA1.Sum(nil)

		hashMD5.Reset()
		hashMD5.Write(secret)
		hashMD5.Write(digest)

		done += copy(result[done:], hashMD5.Sum(nil))
		i++
	}
}

const (
	tlsRandomLength      = 32 // Length of a random nonce in TLS 1.1.
	masterSecretLength   = 48 // Length of a master secret in TLS 1.1.
	finishedVerifyLength = 12 // Length of verify_data in a Finished message.
)

var masterSecretLabel = []byte("master secret")
var keyExpansionLabel = []byte("key expansion")
var clientFinishedLabel = []byte("client finished")
var serverFinishedLabel = []byte("server finished")

func prfAndHashForVersion(version uint16, suite *cipherSuite) (func(result, secret, label, seed []byte), crypto.Hash) {
	switch version {
	case VersionSSL30:
		return prf30, crypto.Hash(0)
	case VersionTLS10, VersionTLS11:
		return prf10, crypto.Hash(0)
	case VersionTLS12:
		if suite.flags&suiteSHA384 != 0 {
			return prf12(sha512.New384), crypto.SHA384
		}
		return prf12(sha256.New), crypto.SHA256
	default:
		panic("unknown version")
	}
}

func prfForVersion(version uint16, suite *cipherSuite) func(result, secret, label, seed []byte) {
	prf, _ := prfAndHashForVersion(version, suite)
	return prf
}

// masterFromPreMasterSecret generates the master secret from the pre-master
// secret. See http://tools.ietf.org/html/rfc5246#section-8.1
func masterFromPreMasterSecret(version uint16, suite *cipherSuite, preMasterSecret, clientRandom, serverRandom []byte) []byte {
	seed := make([]byte, 0, len(clientRandom)+len(serverRandom))
	seed = append(seed, clientRandom...)
	seed = append(seed, serverRandom...)

	masterSecret := make([]byte, masterSecretLength)
	prfForVersion(version, suite)(masterSecret, preMasterSecret, masterSecretLabel, seed)
	return masterSecret
}

// keysFromMasterSecret generates the connection keys from the master
// secret, given the lengths of the MAC key, cipher key and IV, as defined in
// RFC 2246, section 6.3.
func keysFromMasterSecret(version uint16, suite *cipherSuite, masterSecret, clientRandom, serverRandom []byte, macLen, keyLen, ivLen int) (clientMAC, serverMAC, clientKey, serverKey, clientIV, serverIV []byte) {
	seed := make([]byte, 0, len(serverRandom)+len(clientRandom))
	seed = append(seed, serverRandom...)
	seed = append(seed, clientRandom...)

	n := 2*macLen + 2*keyLen + 2*ivLen
	keyMaterial := make([]byte, n)
	prfForVersion(version, suite)(keyMaterial, masterSecret, keyExpansionLabel, seed)
	clientMAC = keyMaterial[:macLen]
	keyMaterial = keyMaterial[macLen:]
	serverMAC = keyMaterial[:macLen]
	keyMaterial = keyMaterial[macLen:]
	clientKey = keyMaterial[:keyLen]
	keyMaterial = keyMaterial[keyLen:]
	serverKey = keyMaterial[:keyLen]
	keyMaterial = keyMaterial[keyLen:]
	clientIV = keyMaterial[:ivLen]
	keyMaterial = keyMaterial[ivLen:]
	serverIV = keyMaterial[:ivLen]
	return
}

// lookupTLSHash looks up the corresponding crypto.Hash for a given
// hash from a TLS SignatureScheme.
func lookupTLSHash(signatureAlgorithm SignatureScheme) (crypto.Hash, error) {
	switch signatureAlgorithm {
	case PKCS1WithSHA1, ECDSAWithSHA1:
		return crypto.SHA1, nil
	case PKCS1WithSHA256, PSSWithSHA256, ECDSAWithP256AndSHA256:
		return crypto.SHA256, nil
	case PKCS1WithSHA384, PSSWithSHA384, ECDSAWithP384AndSHA384:
		return crypto.SHA384, nil
	default:
		return 0, fmt.Errorf("tls: unsupported signature algorithm: %#04x", signatureAlgorithm)
	}
}

func newFinishedHash(version uint16, cipherSuite *cipherSuite) finishedHash {
	var buffer []byte
	if version == VersionSSL30 || version >= VersionTLS12 {
		buffer = []byte{}
	}

	prf, hash := prfAndHashForVersion(version, cipherSuite)
	if hash != 0 {
		return finishedHash{hash.New(), hash.New(), nil, nil, buffer, version, prf}
	}

	return finishedHash{sha1.New(), sha1.New(), md5.New(), md5.New(), buffer, version, prf}
}

// A finishedHash calculates the hash of a set of handshake messages suitable
// for including in a Finished message.
type finishedHash struct {
	client hash.Hash
	server hash.Hash

	// Prior to TLS 1.2, an additional MD5 hash is required.
	clientMD5 hash.Hash
	serverMD5 hash.Hash

	// In TLS 1.2, a full buffer is sadly required.
	buffer []byte

	version uint16
	prf     func(result, secret, label, seed []byte)
}

func (h *finishedHash) Write(msg []byte) (n int, err error) {
	h.client.Write(msg)
	h.server.Write(msg)

	if h.version < VersionTLS12 {
		h.clientMD5.Write(msg)
		h.serverMD5.Write(msg)
	}

	if h.buffer != nil {
		h.buffer = append(h.buffer, msg...)
	}

	return len(msg), nil
}

func (h finishedHash) Sum() []byte {
	if h.version >= VersionTLS12 {
		return h.client.Sum(nil)
	}

	out := make([]byte, 0, md5.Size+sha1.Size)
	out = h.clientMD5.Sum(out)
	return h.client.Sum(out)
}

// finishedSum30 calculates the contents of the verify_data member of a SSLv3
// Finished message given the MD5 and SHA1 hashes of a set of handshake
// messages.
func finishedSum30(md5, sha1 hash.Hash, masterSecret []byte, magic []byte) []byte {
	md5.Write(magic)
	md5.Write(masterSecret)
	md5.Write(ssl30Pad1[:])
	md5Digest := md5.Sum(nil)

	md5.Reset()
	md5.Write(masterSecret)
	md5.Write(ssl30Pad2[:])
	md5.Write(md5Digest)
	md5Digest = md5.Sum(nil)

	sha1.Write(magic)
	sha1.Write(masterSecret)
	sha1.Write(ssl30Pad1[:40])
	sha1Digest := sha1.Sum(nil)

	sha1.Reset()
	sha1.Write(masterSecret)
	sha1.Write(ssl30Pad2[:40])
	sha1.Write(sha1Digest)
	sha1Digest = sha1.Sum(nil)

	ret := make([]byte, len(md5Digest)+len(sha1Digest))
	copy(ret, md5Digest)
	copy(ret[len(md5Digest):], sha1Digest)
	return ret
}

var ssl3ClientFinishedMagic = [4]byte{0x43, 0x4c, 0x4e, 0x54}
var ssl3ServerFinishedMagic = [4]byte{0x53, 0x52, 0x56, 0x52}

// clientSum returns the contents of the verify_data member of a client's
// Finished message.
func (h finishedHash) clientSum(masterSecret []byte) []byte {
	if h.version == VersionSSL30 {
		return finishedSum30(h.clientMD5, h.client, masterSecret, ssl3ClientFinishedMagic[:])
	}

	out := make([]byte, finishedVerifyLength)
	h.prf(out, masterSecret, clientFinishedLabel, h.Sum())
	return out
}

// serverSum returns the contents of the verify_data member of a server's
// Finished message.
func (h finishedHash) serverSum(masterSecret []byte) []byte {
	if h.version == VersionSSL30 {
		return finishedSum30(h.serverMD5, h.server, masterSecret, ssl3ServerFinishedMagic[:])
	}

	out := make([]byte, finishedVerifyLength)
	h.prf(out, masterSecret, serverFinishedLabel, h.Sum())
	return out
}

// selectClientCertSignatureAlgorithm returns a SignatureScheme to sign a
// client's CertificateVerify with, or an error if none can be found.
func (h finishedHash) selectClientCertSignatureAlgorithm(serverList []SignatureScheme, sigType uint8) (SignatureScheme, error) {
	for _, v := range serverList {
		if signatureFromSignatureScheme(v) == sigType && isSupportedSignatureAlgorithm(v, supportedSignatureAlgorithms) {
			return v, nil
		}
	}
	return 0, errors.New("tls: no supported signature algorithm found for signing client certificate")
}

// hashForClientCertificate returns a digest, hash function, and TLS 1.2 hash
// id suitable for signing by a TLS client certificate.
func (h finishedHash) hashForClientCertificate(sigType uint8, signatureAlgorithm SignatureScheme, masterSecret []byte) ([]byte, crypto.Hash, error) {
	if (h.version == VersionSSL30 || h.version >= VersionTLS12) && h.buffer == nil {
		panic("a handshake hash for a client-certificate was requested after discarding the handshake buffer")
	}

	if h.version == VersionSSL30 {
		if sigType != signatureRSA {
			return nil, 0, errors.New("tls: unsupported signature type for client certificate")
		}

		md5Hash := md5.New()
		md5Hash.Write(h.buffer)
		sha1Hash := sha1.New()
		sha1Hash.Write(h.buffer)
		return finishedSum30(md5Hash, sha1Hash, masterSecret, nil), crypto.MD5SHA1, nil
	}
	if h.version >= VersionTLS12 {
		hashAlg, err := lookupTLSHash(signatureAlgorithm)
		if err != nil {
			return nil, 0, err
		}
		hash := hashAlg.New()
		hash.Write(h.buffer)
		return hash.Sum(nil), hashAlg, nil
	}

	if sigType == signatureECDSA {
		return h.server.Sum(nil), crypto.SHA1, nil
	}

	return h.Sum(), crypto.MD5SHA1, nil
}

// discardHandshakeBuffer is called when there is no more need to
// buffer the entirety of the handshake messages.
func (h *finishedHash) discardHandshakeBuffer() {
	h.buffer = nil
}
<commit_msg>crypto/tls: remove bookkeeping code from pHash function<commit_after>// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package tls

import (
	"crypto"
	"crypto/hmac"
	"crypto/md5"
	"crypto/sha1"
	"crypto/sha256"
	"crypto/sha512"
	"errors"
	"fmt"
	"hash"
)

// Split a premaster secret in two as specified in RFC 4346, section 5.
func splitPreMasterSecret(secret []byte) (s1, s2 []byte) {
	s1 = secret[0 : (len(secret)+1)/2]
	s2 = secret[len(secret)/2:]
	return
}

// pHash implements the P_hash function, as defined in RFC 4346, section 5.
func pHash(result, secret, seed []byte, hash func() hash.Hash) {
	h := hmac.New(hash, secret)
	h.Write(seed)
	a := h.Sum(nil)

	j := 0
	for j < len(result) {
		h.Reset()
		h.Write(a)
		h.Write(seed)
		b := h.Sum(nil)
		copy(result[j:], b)
		j += len(b)

		h.Reset()
		h.Write(a)
		a = h.Sum(nil)
	}
}

// prf10 implements the TLS 1.0 pseudo-random function, as defined in RFC 2246, section 5.
func prf10(result, secret, label, seed []byte) {
	hashSHA1 := sha1.New
	hashMD5 := md5.New

	labelAndSeed := make([]byte, len(label)+len(seed))
	copy(labelAndSeed, label)
	copy(labelAndSeed[len(label):], seed)

	s1, s2 := splitPreMasterSecret(secret)
	pHash(result, s1, labelAndSeed, hashMD5)
	result2 := make([]byte, len(result))
	pHash(result2, s2, labelAndSeed, hashSHA1)

	for i, b := range result2 {
		result[i] ^= b
	}
}

// prf12 implements the TLS 1.2 pseudo-random function, as defined in RFC 5246, section 5.
func prf12(hashFunc func() hash.Hash) func(result, secret, label, seed []byte) {
	return func(result, secret, label, seed []byte) {
		labelAndSeed := make([]byte, len(label)+len(seed))
		copy(labelAndSeed, label)
		copy(labelAndSeed[len(label):], seed)

		pHash(result, secret, labelAndSeed, hashFunc)
	}
}

// prf30 implements the SSL 3.0 pseudo-random function, as defined in
// www.mozilla.org/projects/security/pki/nss/ssl/draft302.txt section 6.
func prf30(result, secret, label, seed []byte) {
	hashSHA1 := sha1.New()
	hashMD5 := md5.New()

	done := 0
	i := 0
	// RFC 5246 section 6.3 says that the largest PRF output needed is 128
	// bytes. Since no more ciphersuites will be added to SSLv3, this will
	// remain true. Each iteration gives us 16 bytes so 10 iterations will
	// be sufficient.
	var b [11]byte
	for done < len(result) {
		for j := 0; j <= i; j++ {
			b[j] = 'A' + byte(i)
		}

		hashSHA1.Reset()
		hashSHA1.Write(b[:i+1])
		hashSHA1.Write(secret)
		hashSHA1.Write(seed)
		digest := hashSHA1.Sum(nil)

		hashMD5.Reset()
		hashMD5.Write(secret)
		hashMD5.Write(digest)

		done += copy(result[done:], hashMD5.Sum(nil))
		i++
	}
}

const (
	tlsRandomLength      = 32 // Length of a random nonce in TLS 1.1.
	masterSecretLength   = 48 // Length of a master secret in TLS 1.1.
	finishedVerifyLength = 12 // Length of verify_data in a Finished message.
)

var masterSecretLabel = []byte("master secret")
var keyExpansionLabel = []byte("key expansion")
var clientFinishedLabel = []byte("client finished")
var serverFinishedLabel = []byte("server finished")

func prfAndHashForVersion(version uint16, suite *cipherSuite) (func(result, secret, label, seed []byte), crypto.Hash) {
	switch version {
	case VersionSSL30:
		return prf30, crypto.Hash(0)
	case VersionTLS10, VersionTLS11:
		return prf10, crypto.Hash(0)
	case VersionTLS12:
		if suite.flags&suiteSHA384 != 0 {
			return prf12(sha512.New384), crypto.SHA384
		}
		return prf12(sha256.New), crypto.SHA256
	default:
		panic("unknown version")
	}
}

func prfForVersion(version uint16, suite *cipherSuite) func(result, secret, label, seed []byte) {
	prf, _ := prfAndHashForVersion(version, suite)
	return prf
}

// masterFromPreMasterSecret generates the master secret from the pre-master
// secret. See http://tools.ietf.org/html/rfc5246#section-8.1
func masterFromPreMasterSecret(version uint16, suite *cipherSuite, preMasterSecret, clientRandom, serverRandom []byte) []byte {
	seed := make([]byte, 0, len(clientRandom)+len(serverRandom))
	seed = append(seed, clientRandom...)
	seed = append(seed, serverRandom...)

	masterSecret := make([]byte, masterSecretLength)
	prfForVersion(version, suite)(masterSecret, preMasterSecret, masterSecretLabel, seed)
	return masterSecret
}

// keysFromMasterSecret generates the connection keys from the master
// secret, given the lengths of the MAC key, cipher key and IV, as defined in
// RFC 2246, section 6.3.
func keysFromMasterSecret(version uint16, suite *cipherSuite, masterSecret, clientRandom, serverRandom []byte, macLen, keyLen, ivLen int) (clientMAC, serverMAC, clientKey, serverKey, clientIV, serverIV []byte) {
	seed := make([]byte, 0, len(serverRandom)+len(clientRandom))
	seed = append(seed, serverRandom...)
	seed = append(seed, clientRandom...)

	n := 2*macLen + 2*keyLen + 2*ivLen
	keyMaterial := make([]byte, n)
	prfForVersion(version, suite)(keyMaterial, masterSecret, keyExpansionLabel, seed)
	clientMAC = keyMaterial[:macLen]
	keyMaterial = keyMaterial[macLen:]
	serverMAC = keyMaterial[:macLen]
	keyMaterial = keyMaterial[macLen:]
	clientKey = keyMaterial[:keyLen]
	keyMaterial = keyMaterial[keyLen:]
	serverKey = keyMaterial[:keyLen]
	keyMaterial = keyMaterial[keyLen:]
	clientIV = keyMaterial[:ivLen]
	keyMaterial = keyMaterial[ivLen:]
	serverIV = keyMaterial[:ivLen]
	return
}

// lookupTLSHash looks up the corresponding crypto.Hash for a given
// hash from a TLS SignatureScheme.
func lookupTLSHash(signatureAlgorithm SignatureScheme) (crypto.Hash, error) {
	switch signatureAlgorithm {
	case PKCS1WithSHA1, ECDSAWithSHA1:
		return crypto.SHA1, nil
	case PKCS1WithSHA256, PSSWithSHA256, ECDSAWithP256AndSHA256:
		return crypto.SHA256, nil
	case PKCS1WithSHA384, PSSWithSHA384, ECDSAWithP384AndSHA384:
		return crypto.SHA384, nil
	default:
		return 0, fmt.Errorf("tls: unsupported signature algorithm: %#04x", signatureAlgorithm)
	}
}

func newFinishedHash(version uint16, cipherSuite *cipherSuite) finishedHash {
	var buffer []byte
	if version == VersionSSL30 || version >= VersionTLS12 {
		buffer = []byte{}
	}

	prf, hash := prfAndHashForVersion(version, cipherSuite)
	if hash != 0 {
		return finishedHash{hash.New(), hash.New(), nil, nil, buffer, version, prf}
	}

	return finishedHash{sha1.New(), sha1.New(), md5.New(), md5.New(), buffer, version, prf}
}

// A finishedHash calculates the hash of a set of handshake messages suitable
// for including in a Finished message.
type finishedHash struct {
	client hash.Hash
	server hash.Hash

	// Prior to TLS 1.2, an additional MD5 hash is required.
	clientMD5 hash.Hash
	serverMD5 hash.Hash

	// In TLS 1.2, a full buffer is sadly required.
	buffer []byte

	version uint16
	prf     func(result, secret, label, seed []byte)
}

func (h *finishedHash) Write(msg []byte) (n int, err error) {
	h.client.Write(msg)
	h.server.Write(msg)

	if h.version < VersionTLS12 {
		h.clientMD5.Write(msg)
		h.serverMD5.Write(msg)
	}

	if h.buffer != nil {
		h.buffer = append(h.buffer, msg...)
	}

	return len(msg), nil
}

func (h finishedHash) Sum() []byte {
	if h.version >= VersionTLS12 {
		return h.client.Sum(nil)
	}

	out := make([]byte, 0, md5.Size+sha1.Size)
	out = h.clientMD5.Sum(out)
	return h.client.Sum(out)
}

// finishedSum30 calculates the contents of the verify_data member of a SSLv3
// Finished message given the MD5 and SHA1 hashes of a set of handshake
// messages.
func finishedSum30(md5, sha1 hash.Hash, masterSecret []byte, magic []byte) []byte {
	md5.Write(magic)
	md5.Write(masterSecret)
	md5.Write(ssl30Pad1[:])
	md5Digest := md5.Sum(nil)

	md5.Reset()
	md5.Write(masterSecret)
	md5.Write(ssl30Pad2[:])
	md5.Write(md5Digest)
	md5Digest = md5.Sum(nil)

	sha1.Write(magic)
	sha1.Write(masterSecret)
	sha1.Write(ssl30Pad1[:40])
	sha1Digest := sha1.Sum(nil)

	sha1.Reset()
	sha1.Write(masterSecret)
	sha1.Write(ssl30Pad2[:40])
	sha1.Write(sha1Digest)
	sha1Digest = sha1.Sum(nil)

	ret := make([]byte, len(md5Digest)+len(sha1Digest))
	copy(ret, md5Digest)
	copy(ret[len(md5Digest):], sha1Digest)
	return ret
}

var ssl3ClientFinishedMagic = [4]byte{0x43, 0x4c, 0x4e, 0x54}
var ssl3ServerFinishedMagic = [4]byte{0x53, 0x52, 0x56, 0x52}

// clientSum returns the contents of the verify_data member of a client's
// Finished message.
func (h finishedHash) clientSum(masterSecret []byte) []byte {
	if h.version == VersionSSL30 {
		return finishedSum30(h.clientMD5, h.client, masterSecret, ssl3ClientFinishedMagic[:])
	}

	out := make([]byte, finishedVerifyLength)
	h.prf(out, masterSecret, clientFinishedLabel, h.Sum())
	return out
}

// serverSum returns the contents of the verify_data member of a server's
// Finished message.
func (h finishedHash) serverSum(masterSecret []byte) []byte {
	if h.version == VersionSSL30 {
		return finishedSum30(h.serverMD5, h.server, masterSecret, ssl3ServerFinishedMagic[:])
	}

	out := make([]byte, finishedVerifyLength)
	h.prf(out, masterSecret, serverFinishedLabel, h.Sum())
	return out
}

// selectClientCertSignatureAlgorithm returns a SignatureScheme to sign a
// client's CertificateVerify with, or an error if none can be found.
func (h finishedHash) selectClientCertSignatureAlgorithm(serverList []SignatureScheme, sigType uint8) (SignatureScheme, error) {
	for _, v := range serverList {
		if signatureFromSignatureScheme(v) == sigType && isSupportedSignatureAlgorithm(v, supportedSignatureAlgorithms) {
			return v, nil
		}
	}
	return 0, errors.New("tls: no supported signature algorithm found for signing client certificate")
}

// hashForClientCertificate returns a digest, hash function, and TLS 1.2 hash
// id suitable for signing by a TLS client certificate.
func (h finishedHash) hashForClientCertificate(sigType uint8, signatureAlgorithm SignatureScheme, masterSecret []byte) ([]byte, crypto.Hash, error) {
	if (h.version == VersionSSL30 || h.version >= VersionTLS12) && h.buffer == nil {
		panic("a handshake hash for a client-certificate was requested after discarding the handshake buffer")
	}

	if h.version == VersionSSL30 {
		if sigType != signatureRSA {
			return nil, 0, errors.New("tls: unsupported signature type for client certificate")
		}

		md5Hash := md5.New()
		md5Hash.Write(h.buffer)
		sha1Hash := sha1.New()
		sha1Hash.Write(h.buffer)
		return finishedSum30(md5Hash, sha1Hash, masterSecret, nil), crypto.MD5SHA1, nil
	}
	if h.version >= VersionTLS12 {
		hashAlg, err := lookupTLSHash(signatureAlgorithm)
		if err != nil {
			return nil, 0, err
		}
		hash := hashAlg.New()
		hash.Write(h.buffer)
		return hash.Sum(nil), hashAlg, nil
	}

	if sigType == signatureECDSA {
		return h.server.Sum(nil), crypto.SHA1, nil
	}

	return h.Sum(), crypto.MD5SHA1, nil
}

// discardHandshakeBuffer is called when there is no more need to
// buffer the entirety of the handshake messages.
func (h *finishedHash) discardHandshakeBuffer() {
	h.buffer = nil
}
<|endoftext|>


<commit_before>package models

import (
	"errors"
	"time"

	"gopkg.in/mgo.v2"
	"gopkg.in/mgo.v2/bson"
)

// QualityReport is a representation of a calculation of an electronic
// clinical quality measure
type QualityReport struct {
	ID              bson.ObjectId `bson:"_id" json:"id"`
	NPI             string        `bson:"npi,omitempty" json:"npi,omitempty"`
	CalculationTime time.Time     `bson:"calculation_time,omitempty" json:"calculationTime,omitempty"`
	Status          Status        `bson:"status,omitempty" json:"status,omitempty"`
	MeasureID       string        `bson:"measure_id,omitempty" json:"measureId,omitempty" validate:"nonzero"`
	SubID           string        `bson:"sub_id,omitempty" json:"subId,omitempty"`
	EffectiveDate   int32         `bson:"effective_date,omitempty" json:"effectiveDate,omitempty" validate:"nonzero"`
}

// FindQualityAndPopulateQualityReport will attempt to find a QualityReport in
// the query_cache based on the measure id, sub id and effective date passed in.
// If it finds the associated document in the database, it will return true
// and populate the other fields in the QualityReport that is passed in.
// Otherwise, it will return false, and the passed in QualityReport will remain
// unchanged.
func FindQualityAndPopulateQualityReport(db *mgo.Database, qr *QualityReport) (bool, error) {
	query := bson.M{"measure_id": qr.MeasureID, "effective_date": qr.EffectiveDate}
	if qr.SubID != "" {
		query["sub_id"] = qr.SubID
	}
	q := db.C("query_cache").Find(query)
	count, err := q.Count()
	if err != nil {
		return false, err
	}
	switch count {
	case 0:
		return false, nil
	case 1:
		err = q.One(qr)
		if err != nil {
			return false, err
		}
	default:
		return false, errors.New("Found more than one quality report for this")
	}
	return true, nil
}

func FindOrCreateQualityReport(db *mgo.Database, qr *QualityReport) error {
	exists, err := FindQualityAndPopulateQualityReport(db, qr)
	if err != nil {
		return err
	}
	if !exists {
		qr.ID = bson.NewObjectId()
		qr.Status = Status{State: "requested"}
		err = db.C("query_cache").Insert(qr)
		if err != nil {
			return err
		}
	}
	return nil
}

type Status struct {
	State string   `bson:"state,omitempty" json:"state,omitempty"`
	Log   []string `bson:"log,omitempty" json:"log,omitempty"`
}

type QualityReportResult struct {
	PopulationIDs            PopulationIDs `bson:"population_ids,omitempty" json:"populationIds,omitempty"`
	InitialPatientPopulation int32         `bson:"IPP" json:"initialPatientPopulation"`
	Denominator              int32         `bson:"DENOM,omitempty" json:"denominator,omitempty"`
	Exception                int32         `bson:"DENEXCP,omitempty" json:"exception,omitempty"`
	Exclusion                int32         `bson:"DENEX,omitempty" json:"exclusion,omitempty"`
	Numerator                int32         `bson:"NUMER,omitempty" json:"numerator,omitempty"`
	AntiNumerator            int32         `bson:"antinumerator,omitempty" json:"antinumerator,omitempty"`
	MeasurePopulation        int32         `bson:"MSRPOPL,omitempty" json:"measurePopulation,omitempty"`
	Observation              float32       `bson:"OBSERV,omitempty" json:"Observation,omitempty"`
}

type PopulationIDs struct {
	InitialPatientPopulation string `bson:"IPP,omitempty" json:"initialPatientPopulation,omitempty"`
	Denominator              string `bson:"DENOM,omitempty" json:"denominator,omitempty"`
	Exception                string `bson:"DENEXCP,omitempty" json:"exception,omitempty"`
	Exclusion                string `bson:"DENEX,omitempty" json:"exclusion,omitempty"`
	Numerator                string `bson:"NUMER,omitempty" json:"numerator,omitempty"`
	MeasurePopulation        string `bson:"MSRPOPL,omitempty" json:"measurePopulation,omitempty"`
	Observation              string `bson:"OBSERV,omitempty" json:"observation,omitempty"`
}
<commit_msg>Include results and make sure populations are there<commit_after>package models

import (
	"errors"
	"time"

	"gopkg.in/mgo.v2"
	"gopkg.in/mgo.v2/bson"
)

// QualityReport is a representation of a calculation of an electronic
// clinical quality measure
type QualityReport struct {
	ID              bson.ObjectId       `bson:"_id" json:"id"`
	NPI             string              `bson:"npi,omitempty" json:"npi,omitempty"`
	CalculationTime time.Time           `bson:"calculation_time,omitempty" json:"calculationTime,omitempty"`
	Status          Status              `bson:"status,omitempty" json:"status,omitempty"`
	MeasureID       string              `bson:"measure_id,omitempty" json:"measureId,omitempty" validate:"nonzero"`
	SubID           string              `bson:"sub_id,omitempty" json:"subId,omitempty"`
	EffectiveDate   int32               `bson:"effective_date,omitempty" json:"effectiveDate,omitempty" validate:"nonzero"`
	Result          QualityReportResult `bson:"result" json:"result"`
}

// FindQualityAndPopulateQualityReport will attempt to find a QualityReport in
// the query_cache based on the measure id, sub id and effective date passed in.
// If it finds the associated document in the database, it will return true
// and populate the other fields in the QualityReport that is passed in.
// Otherwise, it will return false, and the passed in QualityReport will remain
// unchanged.
func FindQualityAndPopulateQualityReport(db *mgo.Database, qr *QualityReport) (bool, error) {
	query := bson.M{"measure_id": qr.MeasureID, "effective_date": qr.EffectiveDate}
	if qr.SubID != "" {
		query["sub_id"] = qr.SubID
	}
	q := db.C("query_cache").Find(query)
	count, err := q.Count()
	if err != nil {
		return false, err
	}
	switch count {
	case 0:
		return false, nil
	case 1:
		err = q.One(qr)
		if err != nil {
			return false, err
		}
	default:
		return false, errors.New("Found more than one quality report for this")
	}
	return true, nil
}

func FindOrCreateQualityReport(db *mgo.Database, qr *QualityReport) error {
	exists, err := FindQualityAndPopulateQualityReport(db, qr)
	if err != nil {
		return err
	}
	if !exists {
		qr.ID = bson.NewObjectId()
		qr.Status = Status{State: "requested"}
		err = db.C("query_cache").Insert(qr)
		if err != nil {
			return err
		}
	}
	return nil
}

type Status struct {
	State string   `bson:"state,omitempty" json:"state,omitempty"`
	Log   []string `bson:"log,omitempty" json:"log,omitempty"`
}

type QualityReportResult struct {
	PopulationIDs            PopulationIDs `bson:"population_ids,omitempty" json:"populationIds,omitempty"`
	InitialPatientPopulation int32         `bson:"IPP" json:"initialPatientPopulation"`
	Denominator              int32         `bson:"DENOM,omitempty" json:"denominator"`
	Exception                int32         `bson:"DENEXCP,omitempty" json:"exception"`
	Exclusion                int32         `bson:"DENEX,omitempty" json:"exclusion"`
	Numerator                int32         `bson:"NUMER,omitempty" json:"numerator"`
	AntiNumerator            int32         `bson:"antinumerator,omitempty" json:"antinumerator"`
	MeasurePopulation        int32         `bson:"MSRPOPL,omitempty" json:"measurePopulation,omitempty"`
	Observation              float32       `bson:"OBSERV,omitempty" json:"Observation,omitempty"`
}

type PopulationIDs struct {
	InitialPatientPopulation string `bson:"IPP,omitempty" json:"initialPatientPopulation,omitempty"`
	Denominator              string `bson:"DENOM,omitempty" json:"denominator,omitempty"`
	Exception                string `bson:"DENEXCP,omitempty" json:"exception,omitempty"`
	Exclusion                string `bson:"DENEX,omitempty" json:"exclusion,omitempty"`
	Numerator                string `bson:"NUMER,omitempty" json:"numerator,omitempty"`
	MeasurePopulation        string `bson:"MSRPOPL,omitempty" json:"measurePopulation,omitempty"`
	Observation              string `bson:"OBSERV,omitempty" json:"observation,omitempty"`
}
<|endoftext|>


<commit_before>package frame

import (
	"github.com/as/frame/box"
	"image"
)

// Refresh renders the entire frame, including the underlying
// bitmap. Refresh should not be called after insertion and deletion
// unless the frame's RGBA bitmap was painted over by another
// draw operation.
func (f *Frame) Refresh() {
	cols := f.Color
	if f.p0 == f.p1 {
		ticked := f.Ticked
		if ticked {
			f.tickat(f.PointOf(f.p0), false)
		}
		f.drawsel(f.PointOf(0), 0, f.Nchars, cols.Back, cols.Text)
		if ticked {
			f.tickat(f.PointOf(f.p0), true)
		}
		return
	}
	pt := f.PointOf(0)
	pt = f.drawsel(pt, 0, f.p0, cols.Back, cols.Text)
	pt = f.drawsel(pt, f.p0, f.p1, cols.Hi.Back, cols.Hi.Text)
	f.drawsel(pt, f.p1, f.Nchars, cols.Back, cols.Text)
}

// RedrawAt renders the frame's bitmap starting at pt and working downwards.
func (f *Frame) RedrawAt(pt image.Point, text, back image.Image) {
	f.redrawRun0(&(f.Run), pt, text, back)
}

// Redraw draws the range [p0:p1] at the given pt.
func (f *Frame) Redraw(pt image.Point, p0, p1 int64, issel bool) {
	if f.Ticked {
		f.tickat(f.PointOf(f.p0), false)
	}

	if p0 == p1 {
		f.tickat(pt, issel)
		return
	}

	pal := f.Color.Palette
	if issel {
		pal = f.Color.Hi
	}
	f.drawsel(pt, p0, p1, pal.Back, pal.Text)
}

// Recolor redraws the range p0:p1 with the given palette
func (f *Frame) Recolor(pt image.Point, p0, p1 int64, cols Palette) {
	f.drawsel(pt, p0, p1, cols.Back, cols.Text)
	f.modified = true
}

func (f *Frame) redrawRun0(r *box.Run, pt image.Point, text, back image.Image) {
	nb := 0
	for ; nb < r.Nbox; nb++ {
		b := &r.Box[nb]
		pt = f.wrapMax(pt, b)
		//if !f.noredraw && b.nrune >= 0 {
		if b.Nrune >= 0 {
			f.stringBG(f.b, pt, text, image.ZP, f.Font, b.Ptr, back, image.ZP)
		}
		pt.X += b.Width
	}
}

func (f *Frame) drawRun(r *box.Run, pt image.Point) image.Point {
	n := 0
	for nb := 0; nb < r.Nbox; nb++ {
		b := &r.Box[nb]
		pt = f.wrapMin(pt, b)
		if pt.Y == f.r.Max.Y {
			r.Nchars -= r.Count(nb)
			r.Delete(nb, r.Nbox-1)
			break
		}
		if b.Nrune > 0 {
			if n = f.fits(pt, b); n == 0 {
				panic("drawRun: fits 0")
			}
			if n != b.Nrune {
				r.Split(nb, n)
				b = &r.Box[nb]
			}
			pt.X += b.Width
		} else {
			if b.BC == '\n' {
				pt = f.wrap(pt)
			} else {
				pt.X += f.plot(pt, b)
			}
		}
	}
	return pt
}

func (f *Frame) drawsel(pt image.Point, p0, p1 int64, back, text image.Image) image.Point {
	{ // doubled
		p0, p1 := int(p0), int(p1)
		q0 := 0
		trim := false

		// Step into box, start coloring it
		// How much does this lambda slow things down?
		stepFill := func(bn int) {
			qt := pt
			if pt = f.wrapMax(pt, (&f.Box[bn])); pt.Y > qt.Y {
				f.Draw(f.b, image.Rect(qt.X, qt.Y, f.r.Max.X, pt.Y), back, qt, f.op)
			}
		}
		nb := 0
		for ; nb < f.Nbox && q0+f.LenBox(nb) <= p0; nb++ {
			// region -2: skip
			q0 += f.LenBox(nb)
		}

		for ; nb < f.Nbox && q0 < p1; nb++ {
			if q0 >= p0 { // region 0 or 1 or 2
				stepFill(nb)
			}
			ptr := f.BoxBytes(nb)
			if q0 < p0 {
				// region -1: shift p right inside the selection
				ptr = ptr[p0-q0:]
				q0 = p0
			}

			trim = false
			if q1 := q0 + len(ptr); q1 >= p1 {
				// region 1: would draw too much, retract the selection
				lim := len(ptr) - (q1 - p1)
				ptr = ptr[:lim]
				trim = true
			}

			w := f.WidthBox(nb, ptr)
			f.Draw(f.b, image.Rect(pt.X, pt.Y, min(pt.X+w, f.r.Max.X), pt.Y+f.Font.Dy()), back, pt, f.op)
			if f.PlainBox(nb) {
				f.stringNBG(f.b, pt, text, image.ZP, f.Font, ptr)
			}
			pt.X += w

			if q0 += len(ptr); q0 >= p1 {
				break
			}
		}

		if p1 > p0 && nb != 0 && nb < f.Nbox && f.LenBox(nb-1) > 0 && !trim {
			stepFill(nb)
		}
		return pt
	}
}
<commit_msg>rm drawrun<commit_after>package frame

import (
	"github.com/as/frame/box"
	"image"
)

// Refresh renders the entire frame, including the underlying
// bitmap. Refresh should not be called after insertion and deletion
// unless the frame's RGBA bitmap was painted over by another
// draw operation.
func (f *Frame) Refresh() {
	cols := f.Color
	if f.p0 == f.p1 {
		ticked := f.Ticked
		if ticked {
			f.tickat(f.PointOf(f.p0), false)
		}
		f.drawsel(f.PointOf(0), 0, f.Nchars, cols.Back, cols.Text)
		if ticked {
			f.tickat(f.PointOf(f.p0), true)
		}
		return
	}
	pt := f.PointOf(0)
	pt = f.drawsel(pt, 0, f.p0, cols.Back, cols.Text)
	pt = f.drawsel(pt, f.p0, f.p1, cols.Hi.Back, cols.Hi.Text)
	f.drawsel(pt, f.p1, f.Nchars, cols.Back, cols.Text)
}

// RedrawAt renders the frame's bitmap starting at pt and working downwards.
func (f *Frame) RedrawAt(pt image.Point, text, back image.Image) {
	f.redrawRun0(&(f.Run), pt, text, back)
}

// Redraw draws the range [p0:p1] at the given pt.
func (f *Frame) Redraw(pt image.Point, p0, p1 int64, issel bool) {
	if f.Ticked {
		f.tickat(f.PointOf(f.p0), false)
	}

	if p0 == p1 {
		f.tickat(pt, issel)
		return
	}

	pal := f.Color.Palette
	if issel {
		pal = f.Color.Hi
	}
	f.drawsel(pt, p0, p1, pal.Back, pal.Text)
}

// Recolor redraws the range p0:p1 with the given palette
func (f *Frame) Recolor(pt image.Point, p0, p1 int64, cols Palette) {
	f.drawsel(pt, p0, p1, cols.Back, cols.Text)
	f.modified = true
}

func (f *Frame) redrawRun0(r *box.Run, pt image.Point, text, back image.Image) {
	nb := 0
	for ; nb < r.Nbox; nb++ {
		b := &r.Box[nb]
		pt = f.wrapMax(pt, b)
		//if !f.noredraw && b.nrune >= 0 {
		if b.Nrune >= 0 {
			f.stringBG(f.b, pt, text, image.ZP, f.Font, b.Ptr, back, image.ZP)
		}
		pt.X += b.Width
	}
}

func (f *Frame) drawsel(pt image.Point, p0, p1 int64, back, text image.Image) image.Point {
	{ // doubled
		p0, p1 := int(p0), int(p1)
		q0 := 0
		trim := false

		// Step into box, start coloring it
		// How much does this lambda slow things down?
		stepFill := func(bn int) {
			qt := pt
			if pt = f.wrapMax(pt, (&f.Box[bn])); pt.Y > qt.Y {
				f.Draw(f.b, image.Rect(qt.X, qt.Y, f.r.Max.X, pt.Y), back, qt, f.op)
			}
		}
		nb := 0
		for ; nb < f.Nbox && q0+f.LenBox(nb) <= p0; nb++ {
			// region -2: skip
			q0 += f.LenBox(nb)
		}

		for ; nb < f.Nbox && q0 < p1; nb++ {
			if q0 >= p0 { // region 0 or 1 or 2
				stepFill(nb)
			}
			ptr := f.BoxBytes(nb)
			if q0 < p0 {
				// region -1: shift p right inside the selection
				ptr = ptr[p0-q0:]
				q0 = p0
			}

			trim = false
			if q1 := q0 + len(ptr); q1 >= p1 {
				// region 1: would draw too much, retract the selection
				lim := len(ptr) - (q1 - p1)
				ptr = ptr[:lim]
				trim = true
			}

			w := f.WidthBox(nb, ptr)
			f.Draw(f.b, image.Rect(pt.X, pt.Y, min(pt.X+w, f.r.Max.X), pt.Y+f.Font.Dy()), back, pt, f.op)
			if f.PlainBox(nb) {
				f.stringNBG(f.b, pt, text, image.ZP, f.Font, ptr)
			}
			pt.X += w

			if q0 += len(ptr); q0 >= p1 {
				break
			}
		}

		if p1 > p0 && nb != 0 && nb < f.Nbox && f.LenBox(nb-1) > 0 && !trim {
			stepFill(nb)
		}
		return pt
	}
}
<|endoftext|>


<commit_before>package masterapi

import (
	"encoding/json"
	"fmt"
	"github.com/KIT-MAMID/mamid/model"
	"github.com/gorilla/mux"
	"github.com/mattn/go-sqlite3"
	"log"
	"net/http"
	"strconv"
)

type ReplicaSet struct {
	ID                              uint   `json:"id"`
	Name                            string `json:"name"`
	PersistentNodeCount             uint   `json:"persistent_node_count"`
	VolatileNodeCount               uint   `json:"volatile_node_count"`
	ConfigureAsShardingConfigServer bool   `json:"configure_as_sharding_config_server"`
}

func (m *MasterAPI) ReplicaSetIndex(w http.ResponseWriter, r *http.Request) {
	var replicasets []*model.ReplicaSet
	err := m.DB.Order("id", false).Find(&replicasets).Error
	if err != nil {
		w.WriteHeader(http.StatusInternalServerError)
		fmt.Fprint(w, err.Error())
		return
	}

	out := make([]*ReplicaSet, len(replicasets))
	for i, v := range replicasets {
		out[i] = ProjectModelReplicaSetToReplicaSet(v)
	}
	json.NewEncoder(w).Encode(out)
}

func (m *MasterAPI) ReplicaSetById(w http.ResponseWriter, r *http.Request) {
	idStr := mux.Vars(r)["replicasetId"]
	id64, err := strconv.ParseUint(idStr, 10, 0)
	if err != nil {
		w.WriteHeader(http.StatusBadRequest)
		return
	}
	id := uint(id64)

	if id == 0 {
		w.WriteHeader(http.StatusBadRequest)
		fmt.Fprintf(w, "id may not be 0")
		return
	}

	var replSet model.ReplicaSet
	res := m.DB.First(&replSet, id)

	if res.RecordNotFound() {
		w.WriteHeader(http.StatusNotFound)
		return
	}
	if err = res.Error; err != nil {
		w.WriteHeader(http.StatusInternalServerError)
		fmt.Fprint(w, err.Error())
		return
	}
	json.NewEncoder(w).Encode(ProjectModelReplicaSetToReplicaSet(&replSet))
	return
}

func (m *MasterAPI) ReplicaSetPut(w http.ResponseWriter, r *http.Request) {
	var postReplSet ReplicaSet
	err := json.NewDecoder(r.Body).Decode(&postReplSet)
	if err != nil {
		w.WriteHeader(http.StatusBadRequest)
		fmt.Fprintf(w, "cannot parse object (%s)", err.Error())
		return
	}

	// Validation

	if postReplSet.ID != 0 {
		w.WriteHeader(http.StatusBadRequest)
		fmt.Fprintf(w, "must not specify the slave ID in PUT request")
		return
	}

	modelReplSet, err := ProjectReplicaSetToModelReplicaSet(&postReplSet)
	if err != nil {
		w.WriteHeader(http.StatusBadRequest)
		fmt.Fprintf(w, err.Error())
		return
	}

	// Persist to database

	err = m.DB.Create(&modelReplSet).Error

	//Check db specific errors
	if driverErr, ok := err.(sqlite3.Error); ok {
		if driverErr.ExtendedCode == sqlite3.ErrConstraintUnique {
			w.WriteHeader(http.StatusBadRequest)
			fmt.Fprint(w, driverErr.Error())
			return
		}
	}

	if err != nil {
		w.WriteHeader(http.StatusInternalServerError)
		fmt.Fprint(w, err.Error())
		return
	}

	// Return created slave

	json.NewEncoder(w).Encode(ProjectModelReplicaSetToReplicaSet(modelReplSet))

	return
}

func (m *MasterAPI) ReplicaSetUpdate(w http.ResponseWriter, r *http.Request) {
	idStr := mux.Vars(r)["replicasetId"]
	id64, err := strconv.ParseUint(idStr, 10, 0)
	if err != nil {
		w.WriteHeader(http.StatusBadRequest)
		return
	}
	id := uint(id64)

	var postReplSet ReplicaSet
	err = json.NewDecoder(r.Body).Decode(&postReplSet)
	if err != nil {
		w.WriteHeader(http.StatusBadRequest)
		fmt.Fprintf(w, "cannot parse object (%s)", err.Error())
		return
	}

	// Validation

	if postReplSet.ID != id {
		w.WriteHeader(http.StatusBadRequest)
		fmt.Fprintf(w, "must not change the id of an object")
		return
	}

	var modelReplSet model.ReplicaSet
	dbRes := m.DB.First(&modelReplSet, id)
	if dbRes.RecordNotFound() {
		w.WriteHeader(http.StatusNotFound)
		return
	} else if err = dbRes.Error; err != nil {
		w.WriteHeader(http.StatusInternalServerError)
		fmt.Fprint(w, err.Error())
		return
	}

	replSet, err := ProjectReplicaSetToModelReplicaSet(&postReplSet)
	if err != nil {
		w.WriteHeader(http.StatusBadRequest)
		fmt.Fprint(w, err)
		return
	}

	if replSet.ConfigureAsShardingConfigServer != modelReplSet.ConfigureAsShardingConfigServer ||
		replSet.Name != modelReplSet.Name {
		w.WriteHeader(http.StatusBadRequest)
		fmt.Fprint(w, "name and configure_as_sharding_server may not be changed")
		return
	}

	// Persist to database

	err = m.DB.Save(replSet).Error

	//Check db specific errors
	if driverErr, ok := err.(sqlite3.Error); ok {
		if driverErr.ExtendedCode == sqlite3.ErrConstraintUnique {
			w.WriteHeader(http.StatusBadRequest)
			fmt.Fprint(w, driverErr.Error())
			return
		}
	}
}

func (m *MasterAPI) ReplicaSetDelete(w http.ResponseWriter, r *http.Request) {
	idStr := mux.Vars(r)["replicasetId"]
	id64, err := strconv.ParseUint(idStr, 10, 0)
	if err != nil {
		w.WriteHeader(http.StatusBadRequest)
		return
	}
	id := uint(id64)

	// Allow delete

	tx := m.DB.Begin()

	s := tx.Delete(&model.ReplicaSet{ID: id})

	if s.RowsAffected == 0 {
		tx.Rollback()
		w.WriteHeader(http.StatusNotFound)
		return
	}

	if s.Error != nil {
		tx.Rollback()
		w.WriteHeader(http.StatusInternalServerError)
		fmt.Fprint(w, err.Error())
		return
	}

	if s.RowsAffected > 1 {
		log.Printf("inconsistency: slave DELETE affected more than one row. Slave.ID = %v", id)
	}

	// Trigger cluster allocator
	// TODO having removed the replica set, the cluster allocator should mark the
	// affected mongod's desired state as deleted
	// check issue #9
	if err = m.attemptClusterAllocator(tx, w); err != nil {
		return
	}

	tx.Commit()

}

func (m *MasterAPI) ReplicaSetGetSlaves(w http.ResponseWriter, r *http.Request) {
	idStr := mux.Vars(r)["replicasetId"]
	id64, err := strconv.ParseUint(idStr, 10, 0)
	if err != nil {
		w.WriteHeader(http.StatusBadRequest)
		return
	}
	id := uint(id64)

	if id == 0 {
		w.WriteHeader(http.StatusBadRequest)
		fmt.Fprintf(w, "id may not be 0")
		return
	}

	var replSet model.ReplicaSet
	res := m.DB.First(&replSet, id)

	if res.RecordNotFound() {
		w.WriteHeader(http.StatusNotFound)
		return
	}
	if err = res.Error; err != nil {
		w.WriteHeader(http.StatusInternalServerError)
		fmt.Fprint(w, err.Error())
		return
	}

	var slaves []*model.Slave
	res = m.DB.Raw("SELECT s.* FROM slaves s JOIN mongods m ON m.parent_slave_id = s.id WHERE m.replica_set_id = ?", id).Scan(&slaves)
	if err = res.Error; err != nil {
		w.WriteHeader(http.StatusInternalServerError)
		fmt.Fprint(w, err.Error())
		return
	}

	out := make([]*Slave, len(slaves))
	for i, v := range slaves {
		out[i] = ProjectModelSlaveToSlave(v)
	}
	json.NewEncoder(w).Encode(out)
	return
}
<commit_msg>call cluster allocator from master masterapi/replicaSets<commit_after>package masterapi

import (
	"encoding/json"
	"fmt"
	"github.com/KIT-MAMID/mamid/model"
	"github.com/gorilla/mux"
	"github.com/mattn/go-sqlite3"
	"log"
	"net/http"
	"strconv"
)

type ReplicaSet struct {
	ID                              uint   `json:"id"`
	Name                            string `json:"name"`
	PersistentNodeCount             uint   `json:"persistent_node_count"`
	VolatileNodeCount               uint   `json:"volatile_node_count"`
	ConfigureAsShardingConfigServer bool   `json:"configure_as_sharding_config_server"`
}

func (m *MasterAPI) ReplicaSetIndex(w http.ResponseWriter, r *http.Request) {
	var replicasets []*model.ReplicaSet
	err := m.DB.Order("id", false).Find(&replicasets).Error
	if err != nil {
		w.WriteHeader(http.StatusInternalServerError)
		fmt.Fprint(w, err.Error())
		return
	}

	out := make([]*ReplicaSet, len(replicasets))
	for i, v := range replicasets {
		out[i] = ProjectModelReplicaSetToReplicaSet(v)
	}
	json.NewEncoder(w).Encode(out)
}

func (m *MasterAPI) ReplicaSetById(w http.ResponseWriter, r *http.Request) {
	idStr := mux.Vars(r)["replicasetId"]
	id64, err := strconv.ParseUint(idStr, 10, 0)
	if err != nil {
		w.WriteHeader(http.StatusBadRequest)
		return
	}
	id := uint(id64)

	if id == 0 {
		w.WriteHeader(http.StatusBadRequest)
		fmt.Fprintf(w, "id may not be 0")
		return
	}

	var replSet model.ReplicaSet
	res := m.DB.First(&replSet, id)

	if res.RecordNotFound() {
		w.WriteHeader(http.StatusNotFound)
		return
	}
	if err = res.Error; err != nil {
		w.WriteHeader(http.StatusInternalServerError)
		fmt.Fprint(w, err.Error())
		return
	}
	json.NewEncoder(w).Encode(ProjectModelReplicaSetToReplicaSet(&replSet))
	return
}

func (m *MasterAPI) ReplicaSetPut(w http.ResponseWriter, r *http.Request) {
	var postReplSet ReplicaSet
	err := json.NewDecoder(r.Body).Decode(&postReplSet)
	if err != nil {
		w.WriteHeader(http.StatusBadRequest)
		fmt.Fprintf(w, "cannot parse object (%s)", err.Error())
		return
	}

	// Validation

	if postReplSet.ID != 0 {
		w.WriteHeader(http.StatusBadRequest)
		fmt.Fprintf(w, "must not specify the slave ID in PUT request")
		return
	}

	modelReplSet, err := ProjectReplicaSetToModelReplicaSet(&postReplSet)
	if err != nil {
		w.WriteHeader(http.StatusBadRequest)
		fmt.Fprintf(w, err.Error())
		return
	}

	tx := m.DB.Begin()

	// Persist to database

	err = tx.Create(&modelReplSet).Error

	//Check db specific errors
	if driverErr, ok := err.(sqlite3.Error); ok && driverErr.ExtendedCode == sqlite3.ErrConstraintUnique {
		tx.Rollback()
		w.WriteHeader(http.StatusBadRequest)
		fmt.Fprint(w, driverErr.Error())
		return
	} else if err != nil {
		tx.Rollback()
		w.WriteHeader(http.StatusInternalServerError)
		fmt.Fprint(w, err.Error())
		return
	}

	// Trigger cluster allocator
	if err = m.attemptClusterAllocator(tx, w); err != nil {
		return
	}

	tx.Commit()

	// Return created slave

	json.NewEncoder(w).Encode(ProjectModelReplicaSetToReplicaSet(modelReplSet))

	return
}

func (m *MasterAPI) ReplicaSetUpdate(w http.ResponseWriter, r *http.Request) {
	idStr := mux.Vars(r)["replicasetId"]
	id64, err := strconv.ParseUint(idStr, 10, 0)
	if err != nil {
		w.WriteHeader(http.StatusBadRequest)
		return
	}
	id := uint(id64)

	var postReplSet ReplicaSet
	err = json.NewDecoder(r.Body).Decode(&postReplSet)
	if err != nil {
		w.WriteHeader(http.StatusBadRequest)
		fmt.Fprintf(w, "cannot parse object (%s)", err.Error())
		return
	}

	// Validation

	if postReplSet.ID != id {
		w.WriteHeader(http.StatusBadRequest)
		fmt.Fprintf(w, "must not change the id of an object")
		return
	}

	tx := m.DB.Begin()

	var modelReplSet model.ReplicaSet

	dbRes := tx.First(&modelReplSet, id)

	if dbRes.RecordNotFound() {
		tx.Rollback()
		w.WriteHeader(http.StatusNotFound)
		return
	} else if err = dbRes.Error; err != nil {
		tx.Rollback()
		w.WriteHeader(http.StatusInternalServerError)
		fmt.Fprint(w, err.Error())
		return
	}

	replSet, err := ProjectReplicaSetToModelReplicaSet(&postReplSet)
	if err != nil {
		tx.Rollback()
		w.WriteHeader(http.StatusBadRequest)
		fmt.Fprint(w, err)
		return
	}

	if replSet.ConfigureAsShardingConfigServer != modelReplSet.ConfigureAsShardingConfigServer ||
		replSet.Name != modelReplSet.Name {
		tx.Rollback()
		w.WriteHeader(http.StatusBadRequest)
		fmt.Fprint(w, "name and configure_as_sharding_server may not be changed")
		return
	}

	// Persist to database

	err = tx.Save(replSet).Error

	//Check db specific errors
	if driverErr, ok := err.(sqlite3.Error); ok && driverErr.ExtendedCode == sqlite3.ErrConstraintUnique {
		tx.Rollback()
		w.WriteHeader(http.StatusBadRequest)
		fmt.Fprint(w, driverErr.Error())
		return
	}

	// Trigger cluster allocator
	if err = m.attemptClusterAllocator(tx, w); err != nil {
		return
	}

	tx.Commit()
}

func (m *MasterAPI) ReplicaSetDelete(w http.ResponseWriter, r *http.Request) {
	idStr := mux.Vars(r)["replicasetId"]
	id64, err := strconv.ParseUint(idStr, 10, 0)
	if err != nil {
		w.WriteHeader(http.StatusBadRequest)
		return
	}
	id := uint(id64)

	// Allow delete

	tx := m.DB.Begin()

	s := tx.Delete(&model.ReplicaSet{ID: id})

	if s.RowsAffected == 0 {
		tx.Rollback()
		w.WriteHeader(http.StatusNotFound)
		return
	}

	if s.Error != nil {
		tx.Rollback()
		w.WriteHeader(http.StatusInternalServerError)
		fmt.Fprint(w, err.Error())
		return
	}

	if s.RowsAffected > 1 {
		log.Printf("inconsistency: slave DELETE affected more than one row. Slave.ID = %v", id)
	}

	// Trigger cluster allocator
	// TODO having removed the replica set, the cluster allocator should mark the
	// affected mongod's desired state as deleted
	// check issue #9
	if err = m.attemptClusterAllocator(tx, w); err != nil {
		return
	}

	tx.Commit()

}

func (m *MasterAPI) ReplicaSetGetSlaves(w http.ResponseWriter, r *http.Request) {
	idStr := mux.Vars(r)["replicasetId"]
	id64, err := strconv.ParseUint(idStr, 10, 0)
	if err != nil {
		w.WriteHeader(http.StatusBadRequest)
		return
	}
	id := uint(id64)

	if id == 0 {
		w.WriteHeader(http.StatusBadRequest)
		fmt.Fprintf(w, "id may not be 0")
		return
	}

	tx := m.DB.Begin()
	defer tx.Rollback()

	var replSet model.ReplicaSet
	res := tx.First(&replSet, id)

	if res.RecordNotFound() {
		w.WriteHeader(http.StatusNotFound)
		return
	}
	if err = res.Error; err != nil {
		w.WriteHeader(http.StatusInternalServerError)
		fmt.Fprint(w, err.Error())
		return
	}

	var slaves []*model.Slave
	res = tx.Raw("SELECT s.* FROM slaves s JOIN mongods m ON m.parent_slave_id = s.id WHERE m.replica_set_id = ?", id).Scan(&slaves)
	if err = res.Error; err != nil {
		w.WriteHeader(http.StatusInternalServerError)
		fmt.Fprint(w, err.Error())
		return
	}

	out := make([]*Slave, len(slaves))
	for i, v := range slaves {
		out[i] = ProjectModelSlaveToSlave(v)
	}
	json.NewEncoder(w).Encode(out)
	return
}
<|endoftext|>


<commit_before>package buffer

import (
	"errors"
	"regexp"
	"strings"
	"sync"

	"github.com/wx13/sith/file/cursor"
)

type Buffer struct {
	lines []Line
	mutex *sync.Mutex
}

func MakeBuffer(stringBuf []string) Buffer {
	lines := make([]Line, len(stringBuf))
	for row, str := range stringBuf {
		lines[row] = MakeLine(str)
	}
	return Buffer{
		lines: lines,
		mutex: &sync.Mutex{},
	}
}

func (buffer *Buffer) Lines() []Line {
	lines := buffer.DeepDup().lines
	return lines
}

// Dup creates a new buffer with the same lines.
func (buffer *Buffer) Dup() Buffer {
	buffer.mutex.Lock()
	linesCopy := make([]Line, len(buffer.lines))
	for row, line := range buffer.lines {
		linesCopy[row] = line
	}
	buffer.mutex.Unlock()
	return Buffer{
		lines: linesCopy,
		mutex: &sync.Mutex{},
	}
}

// DeepDup creates a new buffer with copies of the lines.
func (buffer *Buffer) DeepDup() Buffer {
	buffer.mutex.Lock()
	linesCopy := make([]Line, len(buffer.lines))
	for row, line := range buffer.lines {
		linesCopy[row] = line.Dup()
	}
	buffer.mutex.Unlock()
	return Buffer{
		lines: linesCopy,
		mutex: &sync.Mutex{},
	}
}

// Length returns the number of lines in the buffer.
func (buffer *Buffer) Length() int {
	if buffer.mutex == nil {
		return 0
	}
	buffer.mutex.Lock()
	n := len(buffer.lines)
	buffer.mutex.Unlock()
	return n
}

// ReplaceBuffer replaces the content (lines) with the
// content from another buffer.
func (buffer *Buffer) ReplaceBuffer(newBuffer Buffer) {

	newLen := newBuffer.Length()
	bufLen := buffer.Length()

	if newLen <= bufLen {
		buffer.mutex.Lock()
		buffer.lines = buffer.lines[:newLen]
		buffer.mutex.Unlock()
	}

	for k, line := range newBuffer.Lines() {
		if k >= bufLen {
			buffer.Append(line)
		} else {
			if buffer.GetRow(k).ToString() != line.ToString() {
				buffer.ReplaceLine(line, k)
			}
		}
	}

}

func (buffer *Buffer) Append(line ...Line) {
	buffer.mutex.Lock()
	buffer.lines = append(buffer.lines, line...)
	buffer.mutex.Unlock()
}

// MakeSplitBuffer creates a buffer from a long string by splitting
// the string at a certain length.
func MakeSplitBuffer(bigString string, lineLen int) Buffer {
	words := strings.Fields(bigString)
	lines := []Line{}
	lineStr := words[0]
	for _, word := range words[1:] {
		if lineLen > 0 && len(lineStr)+len(word) > lineLen {
			lines = append(lines, MakeLine(lineStr))
			lineStr = word
		} else {
			lineStr += " " + word
		}
	}
	lines = append(lines, MakeLine(lineStr))
	return Buffer{
		lines: lines,
		mutex: &sync.Mutex{},
	}
}

func (buffer *Buffer) InclSlice(row1, row2 int) *Buffer {
	if row2 >= buffer.Length() {
		row2 = buffer.Length() - 1
	}
	if row2 < 0 {
		row2 += buffer.Length()
	}
	buffer.mutex.Lock()
	lines := buffer.lines[row1 : row2+1]
	buffer.mutex.Unlock()
	return &Buffer{lines: lines, mutex: &sync.Mutex{}}
}

func (buffer *Buffer) RowSlice(row, startCol, endCol int) Line {
	buffer.mutex.Lock()
	line := buffer.lines[row].Slice(startCol, endCol)
	buffer.mutex.Unlock()
	return line
}

func (buffer *Buffer) StrSlab(row1, row2, col1, col2 int) []string {
	lines := buffer.Lines()[row1:row2]
	strs := make([]string, len(lines))
	for idx, line := range lines {
		strs[idx] = line.StrSlice(col1, col2)
	}
	return strs
}

// ToString concatenates the buffer into one long string.
func (buffer *Buffer) ToString(newline string) string {
	str := ""
	for _, line := range buffer.Lines() {
		str += line.ToString() + newline
	}
	return str[:len(str)-1]
}

func (buffer *Buffer) InsertAfter(row int, lines ...Line) {
	buffer.mutex.Lock()
	buffer.lines = append(buffer.lines[:row+1], append(lines, buffer.lines[row+1:]...)...)
	buffer.mutex.Unlock()
}

func (buffer *Buffer) DeleteRow(row int) {
	buffer.mutex.Lock()
	defer buffer.mutex.Unlock()
	if len(buffer.lines) == 1 {
		buffer.lines = []Line{MakeLine("")}
	} else if row == 0 {
		buffer.lines = buffer.lines[1:]
	} else if row < len(buffer.lines)-1 {
		buffer.lines = append(buffer.lines[:row], buffer.lines[row+1:]...)
	} else {
		buffer.lines = buffer.lines[:row]
	}
}

func (buffer *Buffer) ReplaceLine(line Line, row int) {
	buffer.mutex.Lock()
	buffer.lines[row] = line
	buffer.mutex.Unlock()
}

// ReplaceLines replaces the lines from minRow to maxRow with lines.
func (buffer *Buffer) ReplaceLines(lines []Line, minRow, maxRow int) {
	buffer.mutex.Lock()
	buffer.lines = append(buffer.lines[:minRow], append(lines, buffer.lines[maxRow+1:]...)...)
	buffer.mutex.Unlock()
}

// Search searches for a string within the buffer.
func (buffer *Buffer) Search(searchTerm string, cursor cursor.Cursor, loop bool) (int, int, error) {
	var col int
	col, _ = buffer.GetRow(cursor.Row()).Search(searchTerm, cursor.Col()+1, -1)
	if col >= 0 {
		return cursor.Row(), col, nil
	}
	for row := cursor.Row() + 1; row < buffer.Length(); row++ {
		col, _ = buffer.GetRow(row).Search(searchTerm, 0, -1)
		if col >= 0 {
			return row, col, nil
		}
	}
	if !loop {
		return cursor.Row(), cursor.Col(), errors.New("Not Found")
	}
	for row := 0; row < cursor.Row(); row++ {
		col, _ = buffer.GetRow(row).Search(searchTerm, 0, -1)
		if col >= 0 {
			return row, col, nil
		}
	}
	col, _ = buffer.GetRow(cursor.Row()).Search(searchTerm, 0, col)
	if col >= 0 {
		return cursor.Row(), col, nil
	}
	return cursor.Row(), cursor.Col(), errors.New("Not Found")
}

// Replace replaces occurrences of a string within a line.
func (buffer *Buffer) ReplaceWord(searchTerm, replaceTerm string, row, col int) {
	startCol, endCol := buffer.GetRow(row).Search(searchTerm, col, -1)
	strLine := buffer.GetRow(row).ToString()
	newStrLine := strLine[:startCol] + replaceTerm + strLine[endCol:]
	buffer.lines[row] = MakeLine(newStrLine)
}

func (buffer *Buffer) GetRow(row int) Line {
	buffer.mutex.Lock()
	line := buffer.lines[row]
	buffer.mutex.Unlock()
	return line
}

func (buffer *Buffer) SetRow(row int, line Line) error {
	if row >= buffer.Length() {
		return errors.New("index exceeds buffer length")
	}
	buffer.mutex.Lock()
	buffer.lines[row] = line
	buffer.mutex.Unlock()
	return nil
}

func (buffer *Buffer) RowLength(row int) int {
	return buffer.GetRow(row).Length()
}

func (buffer *Buffer) GetIndent() (string, bool) {
	spaceHisto := buffer.countLeadingSpacesAndTabs()
	tabCount := spaceHisto[0]
	nSpaces, spaceCount := buffer.scoreIndents(spaceHisto)
	clean := true
	if tabCount > 0 && spaceCount > 0 {
		clean = false
	}
	if tabCount >= spaceCount {
		return "\t", clean
	} else {
		return strings.Repeat(" ", nSpaces), clean
	}
}

func (buffer *Buffer) countLeadingSpacesAndTabs() []int {
	spaceHisto := make([]int, 33)
	re := regexp.MustCompile("^[ \t]*")
	for _, line := range buffer.Lines() {
		indentStr := re.FindString(line.ToString())
		nSpaces := strings.Count(indentStr, " ")
		nTabs := strings.Count(indentStr, "\t")
		if nSpaces > 0 && nSpaces <= 32 {
			spaceHisto[nSpaces]++
		}
		if nTabs > 0 {
			spaceHisto[0]++
		}
	}
	return spaceHisto
}

func (buffer *Buffer) scoreIndents(spaceHisto []int) (int, int) {
	count := 0
	nSpaces := 0
	for indentSize := 1; indentSize < 9; indentSize++ {
		score := 0
		for n := 1; n <= 4; n++ {
			score += spaceHisto[n*indentSize]
		}
		if score > count && spaceHisto[indentSize] > 0 {
			nSpaces = indentSize
			count = score
		}
	}
	return nSpaces, count
}

func (buffer *Buffer) Equals(buffer2 *Buffer) bool {
	if buffer.Length() != buffer2.Length() {
		return false
	}

	buffer.mutex.Lock()
	defer buffer.mutex.Unlock()
	buffer2.mutex.Lock()
	defer buffer2.mutex.Unlock()

	for idx := range buffer.lines {
		if buffer.lines[idx].ToString() != buffer2.lines[idx].ToString() {
			return false
		}
	}
	return true
}

func (buffer *Buffer) CompressPriorSpaces(row, col int) int {
	line := buffer.GetRow(row)
	line, col = line.CompressPriorSpaces(col)
	buffer.SetRow(row, line)
	return col
}
<commit_msg>never allow indent size to be one space<commit_after>package buffer

import (
	"errors"
	"regexp"
	"strings"
	"sync"

	"github.com/wx13/sith/file/cursor"
)

type Buffer struct {
	lines []Line
	mutex *sync.Mutex
}

func MakeBuffer(stringBuf []string) Buffer {
	lines := make([]Line, len(stringBuf))
	for row, str := range stringBuf {
		lines[row] = MakeLine(str)
	}
	return Buffer{
		lines: lines,
		mutex: &sync.Mutex{},
	}
}

func (buffer *Buffer) Lines() []Line {
	lines := buffer.DeepDup().lines
	return lines
}

// Dup creates a new buffer with the same lines.
func (buffer *Buffer) Dup() Buffer {
	buffer.mutex.Lock()
	linesCopy := make([]Line, len(buffer.lines))
	for row, line := range buffer.lines {
		linesCopy[row] = line
	}
	buffer.mutex.Unlock()
	return Buffer{
		lines: linesCopy,
		mutex: &sync.Mutex{},
	}
}

// DeepDup creates a new buffer with copies of the lines.
func (buffer *Buffer) DeepDup() Buffer {
	buffer.mutex.Lock()
	linesCopy := make([]Line, len(buffer.lines))
	for row, line := range buffer.lines {
		linesCopy[row] = line.Dup()
	}
	buffer.mutex.Unlock()
	return Buffer{
		lines: linesCopy,
		mutex: &sync.Mutex{},
	}
}

// Length returns the number of lines in the buffer.
func (buffer *Buffer) Length() int {
	if buffer.mutex == nil {
		return 0
	}
	buffer.mutex.Lock()
	n := len(buffer.lines)
	buffer.mutex.Unlock()
	return n
}

// ReplaceBuffer replaces the content (lines) with the
// content from another buffer.
func (buffer *Buffer) ReplaceBuffer(newBuffer Buffer) {

	newLen := newBuffer.Length()
	bufLen := buffer.Length()

	if newLen <= bufLen {
		buffer.mutex.Lock()
		buffer.lines = buffer.lines[:newLen]
		buffer.mutex.Unlock()
	}

	for k, line := range newBuffer.Lines() {
		if k >= bufLen {
			buffer.Append(line)
		} else {
			if buffer.GetRow(k).ToString() != line.ToString() {
				buffer.ReplaceLine(line, k)
			}
		}
	}

}

func (buffer *Buffer) Append(line ...Line) {
	buffer.mutex.Lock()
	buffer.lines = append(buffer.lines, line...)
	buffer.mutex.Unlock()
}

// MakeSplitBuffer creates a buffer from a long string by splitting
// the string at a certain length.
func MakeSplitBuffer(bigString string, lineLen int) Buffer {
	words := strings.Fields(bigString)
	lines := []Line{}
	lineStr := words[0]
	for _, word := range words[1:] {
		if lineLen > 0 && len(lineStr)+len(word) > lineLen {
			lines = append(lines, MakeLine(lineStr))
			lineStr = word
		} else {
			lineStr += " " + word
		}
	}
	lines = append(lines, MakeLine(lineStr))
	return Buffer{
		lines: lines,
		mutex: &sync.Mutex{},
	}
}

func (buffer *Buffer) InclSlice(row1, row2 int) *Buffer {
	if row2 >= buffer.Length() {
		row2 = buffer.Length() - 1
	}
	if row2 < 0 {
		row2 += buffer.Length()
	}
	buffer.mutex.Lock()
	lines := buffer.lines[row1 : row2+1]
	buffer.mutex.Unlock()
	return &Buffer{lines: lines, mutex: &sync.Mutex{}}
}

func (buffer *Buffer) RowSlice(row, startCol, endCol int) Line {
	buffer.mutex.Lock()
	line := buffer.lines[row].Slice(startCol, endCol)
	buffer.mutex.Unlock()
	return line
}

func (buffer *Buffer) StrSlab(row1, row2, col1, col2 int) []string {
	lines := buffer.Lines()[row1:row2]
	strs := make([]string, len(lines))
	for idx, line := range lines {
		strs[idx] = line.StrSlice(col1, col2)
	}
	return strs
}

// ToString concatenates the buffer into one long string.
func (buffer *Buffer) ToString(newline string) string {
	str := ""
	for _, line := range buffer.Lines() {
		str += line.ToString() + newline
	}
	return str[:len(str)-1]
}

func (buffer *Buffer) InsertAfter(row int, lines ...Line) {
	buffer.mutex.Lock()
	buffer.lines = append(buffer.lines[:row+1], append(lines, buffer.lines[row+1:]...)...)
	buffer.mutex.Unlock()
}

func (buffer *Buffer) DeleteRow(row int) {
	buffer.mutex.Lock()
	defer buffer.mutex.Unlock()
	if len(buffer.lines) == 1 {
		buffer.lines = []Line{MakeLine("")}
	} else if row == 0 {
		buffer.lines = buffer.lines[1:]
	} else if row < len(buffer.lines)-1 {
		buffer.lines = append(buffer.lines[:row], buffer.lines[row+1:]...)
	} else {
		buffer.lines = buffer.lines[:row]
	}
}

func (buffer *Buffer) ReplaceLine(line Line, row int) {
	buffer.mutex.Lock()
	buffer.lines[row] = line
	buffer.mutex.Unlock()
}

// ReplaceLines replaces the lines from minRow to maxRow with lines.
func (buffer *Buffer) ReplaceLines(lines []Line, minRow, maxRow int) {
	buffer.mutex.Lock()
	buffer.lines = append(buffer.lines[:minRow], append(lines, buffer.lines[maxRow+1:]...)...)
	buffer.mutex.Unlock()
}

// Search searches for a string within the buffer.
func (buffer *Buffer) Search(searchTerm string, cursor cursor.Cursor, loop bool) (int, int, error) {
	var col int
	col, _ = buffer.GetRow(cursor.Row()).Search(searchTerm, cursor.Col()+1, -1)
	if col >= 0 {
		return cursor.Row(), col, nil
	}
	for row := cursor.Row() + 1; row < buffer.Length(); row++ {
		col, _ = buffer.GetRow(row).Search(searchTerm, 0, -1)
		if col >= 0 {
			return row, col, nil
		}
	}
	if !loop {
		return cursor.Row(), cursor.Col(), errors.New("Not Found")
	}
	for row := 0; row < cursor.Row(); row++ {
		col, _ = buffer.GetRow(row).Search(searchTerm, 0, -1)
		if col >= 0 {
			return row, col, nil
		}
	}
	col, _ = buffer.GetRow(cursor.Row()).Search(searchTerm, 0, col)
	if col >= 0 {
		return cursor.Row(), col, nil
	}
	return cursor.Row(), cursor.Col(), errors.New("Not Found")
}

// Replace replaces occurrences of a string within a line.
func (buffer *Buffer) ReplaceWord(searchTerm, replaceTerm string, row, col int) {
	startCol, endCol := buffer.GetRow(row).Search(searchTerm, col, -1)
	strLine := buffer.GetRow(row).ToString()
	newStrLine := strLine[:startCol] + replaceTerm + strLine[endCol:]
	buffer.lines[row] = MakeLine(newStrLine)
}

func (buffer *Buffer) GetRow(row int) Line {
	buffer.mutex.Lock()
	line := buffer.lines[row]
	buffer.mutex.Unlock()
	return line
}

func (buffer *Buffer) SetRow(row int, line Line) error {
	if row >= buffer.Length() {
		return errors.New("index exceeds buffer length")
	}
	buffer.mutex.Lock()
	buffer.lines[row] = line
	buffer.mutex.Unlock()
	return nil
}

func (buffer *Buffer) RowLength(row int) int {
	return buffer.GetRow(row).Length()
}

func (buffer *Buffer) GetIndent() (string, bool) {
	spaceHisto := buffer.countLeadingSpacesAndTabs()
	tabCount := spaceHisto[0]
	nSpaces, spaceCount := buffer.scoreIndents(spaceHisto)
	clean := true
	if tabCount > 0 && spaceCount > 0 {
		clean = false
	}
	if tabCount >= spaceCount {
		return "\t", clean
	} else {
		return strings.Repeat(" ", nSpaces), clean
	}
}

func (buffer *Buffer) countLeadingSpacesAndTabs() []int {
	spaceHisto := make([]int, 33)
	re := regexp.MustCompile("^[ \t]*")
	for _, line := range buffer.Lines() {
		indentStr := re.FindString(line.ToString())
		nSpaces := strings.Count(indentStr, " ")
		nTabs := strings.Count(indentStr, "\t")
		if nSpaces > 0 && nSpaces <= 32 {
			spaceHisto[nSpaces]++
		}
		if nTabs > 0 {
			spaceHisto[0]++
		}
	}
	return spaceHisto
}

func (buffer *Buffer) scoreIndents(spaceHisto []int) (int, int) {
	count := 0
	nSpaces := 0
	for indentSize := 2; indentSize < 9; indentSize++ {
		score := 0
		for n := 1; n <= 4; n++ {
			score += spaceHisto[n*indentSize]
		}
		if score > count && spaceHisto[indentSize] > 0 {
			nSpaces = indentSize
			count = score
		}
	}
	return nSpaces, count
}

func (buffer *Buffer) Equals(buffer2 *Buffer) bool {
	if buffer.Length() != buffer2.Length() {
		return false
	}

	buffer.mutex.Lock()
	defer buffer.mutex.Unlock()
	buffer2.mutex.Lock()
	defer buffer2.mutex.Unlock()

	for idx := range buffer.lines {
		if buffer.lines[idx].ToString() != buffer2.lines[idx].ToString() {
			return false
		}
	}
	return true
}

func (buffer *Buffer) CompressPriorSpaces(row, col int) int {
	line := buffer.GetRow(row)
	line, col = line.CompressPriorSpaces(col)
	buffer.SetRow(row, line)
	return col
}
<|endoftext|>


<commit_before>package filter

import (
	"testing"

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

func TestCompile(t *testing.T) {
	f, err := Compile([]string{})
	assert.NoError(t, err)
	assert.Nil(t, f)

	f, err = Compile([]string{"cpu"})
	assert.NoError(t, err)
	assert.True(t, f.Match("cpu"))
	assert.False(t, f.Match("cpu0"))
	assert.False(t, f.Match("mem"))

	f, err = Compile([]string{"cpu*"})
	assert.NoError(t, err)
	assert.True(t, f.Match("cpu"))
	assert.True(t, f.Match("cpu0"))
	assert.False(t, f.Match("mem"))

	f, err = Compile([]string{"cpu", "mem"})
	assert.NoError(t, err)
	assert.True(t, f.Match("cpu"))
	assert.False(t, f.Match("cpu0"))
	assert.True(t, f.Match("mem"))

	f, err = Compile([]string{"cpu", "mem", "net*"})
	assert.NoError(t, err)
	assert.True(t, f.Match("cpu"))
	assert.False(t, f.Match("cpu0"))
	assert.True(t, f.Match("mem"))
	assert.True(t, f.Match("network"))
}

var benchbool bool

func BenchmarkFilterSingleNoGlobFalse(b *testing.B) {
	f, _ := Compile([]string{"cpu"})
	var tmp bool
	for n := 0; n < b.N; n++ {
		tmp = f.Match("network")
	}
	benchbool = tmp
}

func BenchmarkFilterSingleNoGlobTrue(b *testing.B) {
	f, _ := Compile([]string{"cpu"})
	var tmp bool
	for n := 0; n < b.N; n++ {
		tmp = f.Match("cpu")
	}
	benchbool = tmp
}

func BenchmarkFilter(b *testing.B) {
	f, _ := Compile([]string{"cpu", "mem", "net*"})
	var tmp bool
	for n := 0; n < b.N; n++ {
		tmp = f.Match("network")
	}
	benchbool = tmp
}

func BenchmarkFilterNoGlob(b *testing.B) {
	f, _ := Compile([]string{"cpu", "mem", "net"})
	var tmp bool
	for n := 0; n < b.N; n++ {
		tmp = f.Match("net")
	}
	benchbool = tmp
}

func BenchmarkFilter2(b *testing.B) {
	f, _ := Compile([]string{"aa", "bb", "c", "ad", "ar", "at", "aq",
		"aw", "az", "axxx", "ab", "cpu", "mem", "net*"})
	var tmp bool
	for n := 0; n < b.N; n++ {
		tmp = f.Match("network")
	}
	benchbool = tmp
}

func BenchmarkFilter2NoGlob(b *testing.B) {
	f, _ := Compile([]string{"aa", "bb", "c", "ad", "ar", "at", "aq",
		"aw", "az", "axxx", "ab", "cpu", "mem", "net"})
	var tmp bool
	for n := 0; n < b.N; n++ {
		tmp = f.Match("net")
	}
	benchbool = tmp
}
<commit_msg>Add test for include/exclude filter (#5193)<commit_after>package filter

import (
	"testing"

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

func TestCompile(t *testing.T) {
	f, err := Compile([]string{})
	assert.NoError(t, err)
	assert.Nil(t, f)

	f, err = Compile([]string{"cpu"})
	assert.NoError(t, err)
	assert.True(t, f.Match("cpu"))
	assert.False(t, f.Match("cpu0"))
	assert.False(t, f.Match("mem"))

	f, err = Compile([]string{"cpu*"})
	assert.NoError(t, err)
	assert.True(t, f.Match("cpu"))
	assert.True(t, f.Match("cpu0"))
	assert.False(t, f.Match("mem"))

	f, err = Compile([]string{"cpu", "mem"})
	assert.NoError(t, err)
	assert.True(t, f.Match("cpu"))
	assert.False(t, f.Match("cpu0"))
	assert.True(t, f.Match("mem"))

	f, err = Compile([]string{"cpu", "mem", "net*"})
	assert.NoError(t, err)
	assert.True(t, f.Match("cpu"))
	assert.False(t, f.Match("cpu0"))
	assert.True(t, f.Match("mem"))
	assert.True(t, f.Match("network"))
}

func TestIncludeExclude(t *testing.T) {
	tags := []string{}
	labels := []string{"best", "com_influxdata", "timeseries", "com_influxdata_telegraf", "ever"}

	filter, err := NewIncludeExcludeFilter([]string{}, []string{"com_influx*"})
	if err != nil {
		t.Fatalf("Failed to create include/exclude filter - %v", err)
	}

	for i := range labels {
		if filter.Match(labels[i]) {
			tags = append(tags, labels[i])
		}
	}

	assert.Equal(t, []string{"best", "timeseries", "ever"}, tags)
}

var benchbool bool

func BenchmarkFilterSingleNoGlobFalse(b *testing.B) {
	f, _ := Compile([]string{"cpu"})
	var tmp bool
	for n := 0; n < b.N; n++ {
		tmp = f.Match("network")
	}
	benchbool = tmp
}

func BenchmarkFilterSingleNoGlobTrue(b *testing.B) {
	f, _ := Compile([]string{"cpu"})
	var tmp bool
	for n := 0; n < b.N; n++ {
		tmp = f.Match("cpu")
	}
	benchbool = tmp
}

func BenchmarkFilter(b *testing.B) {
	f, _ := Compile([]string{"cpu", "mem", "net*"})
	var tmp bool
	for n := 0; n < b.N; n++ {
		tmp = f.Match("network")
	}
	benchbool = tmp
}

func BenchmarkFilterNoGlob(b *testing.B) {
	f, _ := Compile([]string{"cpu", "mem", "net"})
	var tmp bool
	for n := 0; n < b.N; n++ {
		tmp = f.Match("net")
	}
	benchbool = tmp
}

func BenchmarkFilter2(b *testing.B) {
	f, _ := Compile([]string{"aa", "bb", "c", "ad", "ar", "at", "aq",
		"aw", "az", "axxx", "ab", "cpu", "mem", "net*"})
	var tmp bool
	for n := 0; n < b.N; n++ {
		tmp = f.Match("network")
	}
	benchbool = tmp
}

func BenchmarkFilter2NoGlob(b *testing.B) {
	f, _ := Compile([]string{"aa", "bb", "c", "ad", "ar", "at", "aq",
		"aw", "az", "axxx", "ab", "cpu", "mem", "net"})
	var tmp bool
	for n := 0; n < b.N; n++ {
		tmp = f.Match("net")
	}
	benchbool = tmp
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"github.com/cactus/go-statsd-client/statsd"
	"io/ioutil"
	"net"
	"os"
	"strings"
	"time"
)

func dieIfError(err error) {
	if err != nil {
		fmt.Fprintf(os.Stderr, "Fatal error: %s\n", err.Error())
		os.Exit(1)
	}
}

func doEvery(d time.Duration, f func(*statsd.Client), s *statsd.Client) {
	f(s)
	for _ = range time.Tick(d) {
		f(s)
	}
}

func process_targets(s *statsd.Client) {
	content, err := ioutil.ReadFile("targets")
	if err != nil {
		fmt.Println("couldn't open targets file")
		return
	}
	targets := strings.Split(string(content), "\n")
	for _, target := range targets {
		if len(target) < 1 {
			continue
		}
		go test(target, s)
	}
}

func test(target string, s *statsd.Client) {
	tuple := strings.Split(target, ":")
	host := tuple[0]
	port := tuple[1]
	subhost := strings.Replace(host, ".", "_", -1)

	pre := time.Now()
	conn, err := net.Dial("tcp", target)
	if err != nil {
		fmt.Println("connect error", target)
		s.Inc(fmt.Sprintf("%s.%s.dial_failed", subhost, port), 1, 1)
		return
	}
	duration := time.Since(pre)
	ms := int64(duration / time.Millisecond)
	fmt.Printf("%s.%s.duration %d\n", subhost, port, ms)
	s.Timing(fmt.Sprintf("%s.%s", subhost, port), ms, 1)
	conn.Close()
}

func main() {
  var statsd_host = flag.String("statsd_host", "localhost", "Statsd Hostname")
  var statsd_port = flag.String("statsd_port", "8125", "Statsd port")
  var bucket = flag.String("bucket", "smoketcp", "Graphite bucket prefix")
  flag.Parse()

	s, err := statsd.Dial(fmt.Sprintf("%s:%s", *statsd_host, *statsd_port), fmt.Sprintf("%s", *bucket))
	dieIfError(err)
	defer s.Close()
	doEvery(time.Second, process_targets, s)
}
<commit_msg>add debug flag, to only output to stdout if set to true<commit_after>package main

import (
	"flag"
	"fmt"
	"github.com/cactus/go-statsd-client/statsd"
	"io/ioutil"
	"net"
	"os"
	"strings"
	"time"
)

func dieIfError(err error) {
	if err != nil {
		fmt.Fprintf(os.Stderr, "Fatal error: %s\n", err.Error())
		os.Exit(1)
	}
}

func doEvery(d time.Duration, f func(*statsd.Client, string, bool), s *statsd.Client, target_file string, debug bool) {
	f(s, target_file, debug)
	for _ = range time.Tick(d) {
		f(s, target_file, debug)
	}
}

func process_targets(s *statsd.Client, target_file string, debug bool) {
	content, err := ioutil.ReadFile(target_file)
	if err != nil {
    if debug {
		  fmt.Println("couldn't open targets file: %s", target_file)
    }
		return
	}
	targets := strings.Split(string(content), "\n")
	for _, target := range targets {
		if len(target) < 1 {
			continue
		}
		go test(target, s, debug)
	}
}

func test(target string, s *statsd.Client, debug bool) {
	tuple := strings.Split(target, ":")
	host := tuple[0]
	port := tuple[1]
	subhost := strings.Replace(host, ".", "_", -1)

	pre := time.Now()
	conn, err := net.Dial("tcp", target)
	if err != nil {
    if debug {
		  fmt.Println("connect error", target)
		}
    s.Inc(fmt.Sprintf("%s.%s.dial_failed", subhost, port), 1, 1)
		return
	}
	duration := time.Since(pre)
	ms := int64(duration / time.Millisecond)
  if debug {
	  fmt.Printf("%s.%s.duration %d\n", subhost, port, ms)
  }
	s.Timing(fmt.Sprintf("%s.%s", subhost, port), ms, 1)
	conn.Close()
}

func main() {
  var statsd_host = flag.String("statsd_host", "localhost", "Statsd Hostname")
  var statsd_port = flag.String("statsd_port", "8125", "Statsd port")
  var bucket = flag.String("bucket", "smoketcp", "Graphite bucket prefix")
  var target_file = flag.String("target_file", "targets", "File containing the list of targets, ex: server1:80")
  var debug = flag.Bool("debug", false, "if true, turn on debugging output")
  flag.Parse()

	s, err := statsd.Dial(fmt.Sprintf("%s:%s", *statsd_host, *statsd_port), fmt.Sprintf("%s", *bucket))
	dieIfError(err)
	defer s.Close()
	doEvery(time.Second, process_targets, s, *target_file, *debug)
}
<|endoftext|>


<commit_before>package main

import (
	"errors"
	"github.com/ethereum/eth-go/ethchain"
	"github.com/ethereum/eth-go/ethpub"
	"github.com/ethereum/eth-go/ethutil"
	"github.com/go-qml/qml"
	"github.com/howeyc/fsnotify"
	"io/ioutil"
	"log"
	"net/url"
	"os"
	"path"
	"path/filepath"
)

type HtmlApplication struct {
	win     *qml.Window
	webView qml.Object
	engine  *qml.Engine
	lib     *UiLib
	path    string
	watcher *fsnotify.Watcher
}

func NewHtmlApplication(path string, lib *UiLib) *HtmlApplication {
	engine := qml.NewEngine()

	return &HtmlApplication{engine: engine, lib: lib, path: path}

}

func (app *HtmlApplication) Create() error {
	component, err := app.engine.LoadFile(app.lib.AssetPath("qml/webapp.qml"))
	if err != nil {
		return err
	}

	if filepath.Ext(app.path) == "eth" {
		return errors.New("Ethereum package not yet supported")

		// TODO
		ethutil.OpenPackage(app.path)
	}

	win := component.CreateWindow(nil)
	win.Set("url", app.path)
	webView := win.ObjectByName("webView")

	app.win = win
	app.webView = webView

	return nil
}

func (app *HtmlApplication) RootFolder() string {
	folder, err := url.Parse(app.path)
	if err != nil {
		return ""
	}
	return path.Dir(ethutil.WindonizePath(folder.RequestURI()))
}
func (app *HtmlApplication) RecursiveFolders() []os.FileInfo {
	files, _ := ioutil.ReadDir(app.RootFolder())
	var folders []os.FileInfo
	for _, file := range files {
		if file.IsDir() {
			folders = append(folders, file)
		}
	}
	return folders
}

func (app *HtmlApplication) NewWatcher(quitChan chan bool) {
	var err error

	app.watcher, err = fsnotify.NewWatcher()
	if err != nil {
		return
	}
	err = app.watcher.Watch(app.RootFolder())
	if err != nil {
		log.Fatal(err)
	}
	for _, folder := range app.RecursiveFolders() {
		fullPath := app.RootFolder() + "/" + folder.Name()
		app.watcher.Watch(fullPath)
	}

	go func() {
	out:
		for {
			select {
			case <-quitChan:
				app.watcher.Close()
				break out
			case <-app.watcher.Event:
				//logger.Debugln("Got event:", ev)
				app.webView.Call("reload")
			case err := <-app.watcher.Error:
				// TODO: Do something here
				logger.Infoln("Watcher error:", err)
			}
		}
	}()

}

func (app *HtmlApplication) Engine() *qml.Engine {
	return app.engine
}

func (app *HtmlApplication) Window() *qml.Window {
	return app.win
}

func (app *HtmlApplication) NewBlock(block *ethchain.Block) {
	b := &ethpub.PBlock{Number: int(block.BlockInfo().Number), Hash: ethutil.Bytes2Hex(block.Hash())}
	app.webView.Call("onNewBlockCb", b)
}

func (app *HtmlApplication) ObjectChanged(stateObject *ethchain.StateObject) {
	app.webView.Call("onObjectChangeCb", ethpub.NewPStateObject(stateObject))
}

func (app *HtmlApplication) StorageChanged(storageObject *ethchain.StorageState) {
	app.webView.Call("onStorageChangeCb", ethpub.NewPStorageState(storageObject))
}

func (app *HtmlApplication) Destroy() {
	app.engine.Destroy()
}
<commit_msg>Don't silently fail on watcher creation<commit_after>package main

import (
	"errors"
	"github.com/ethereum/eth-go/ethchain"
	"github.com/ethereum/eth-go/ethpub"
	"github.com/ethereum/eth-go/ethutil"
	"github.com/go-qml/qml"
	"github.com/howeyc/fsnotify"
	"io/ioutil"
	"net/url"
	"os"
	"path"
	"path/filepath"
)

type HtmlApplication struct {
	win     *qml.Window
	webView qml.Object
	engine  *qml.Engine
	lib     *UiLib
	path    string
	watcher *fsnotify.Watcher
}

func NewHtmlApplication(path string, lib *UiLib) *HtmlApplication {
	engine := qml.NewEngine()

	return &HtmlApplication{engine: engine, lib: lib, path: path}

}

func (app *HtmlApplication) Create() error {
	component, err := app.engine.LoadFile(app.lib.AssetPath("qml/webapp.qml"))
	if err != nil {
		return err
	}

	if filepath.Ext(app.path) == "eth" {
		return errors.New("Ethereum package not yet supported")

		// TODO
		ethutil.OpenPackage(app.path)
	}

	win := component.CreateWindow(nil)
	win.Set("url", app.path)
	webView := win.ObjectByName("webView")

	app.win = win
	app.webView = webView

	return nil
}

func (app *HtmlApplication) RootFolder() string {
	folder, err := url.Parse(app.path)
	if err != nil {
		return ""
	}
	return path.Dir(ethutil.WindonizePath(folder.RequestURI()))
}
func (app *HtmlApplication) RecursiveFolders() []os.FileInfo {
	files, _ := ioutil.ReadDir(app.RootFolder())
	var folders []os.FileInfo
	for _, file := range files {
		if file.IsDir() {
			folders = append(folders, file)
		}
	}
	return folders
}

func (app *HtmlApplication) NewWatcher(quitChan chan bool) {
	var err error

	app.watcher, err = fsnotify.NewWatcher()
	if err != nil {
		logger.Infoln("Could not create new auto-reload watcher:", err)
		return
	}
	err = app.watcher.Watch(app.RootFolder())
	if err != nil {
		logger.Infoln("Could not start auto-reload watcher:", err)
		return
	}
	for _, folder := range app.RecursiveFolders() {
		fullPath := app.RootFolder() + "/" + folder.Name()
		app.watcher.Watch(fullPath)
	}

	go func() {
	out:
		for {
			select {
			case <-quitChan:
				app.watcher.Close()
				break out
			case <-app.watcher.Event:
				//logger.Debugln("Got event:", ev)
				app.webView.Call("reload")
			case err := <-app.watcher.Error:
				// TODO: Do something here
				logger.Infoln("Watcher error:", err)
			}
		}
	}()

}

func (app *HtmlApplication) Engine() *qml.Engine {
	return app.engine
}

func (app *HtmlApplication) Window() *qml.Window {
	return app.win
}

func (app *HtmlApplication) NewBlock(block *ethchain.Block) {
	b := &ethpub.PBlock{Number: int(block.BlockInfo().Number), Hash: ethutil.Bytes2Hex(block.Hash())}
	app.webView.Call("onNewBlockCb", b)
}

func (app *HtmlApplication) ObjectChanged(stateObject *ethchain.StateObject) {
	app.webView.Call("onObjectChangeCb", ethpub.NewPStateObject(stateObject))
}

func (app *HtmlApplication) StorageChanged(storageObject *ethchain.StorageState) {
	app.webView.Call("onStorageChangeCb", ethpub.NewPStorageState(storageObject))
}

func (app *HtmlApplication) Destroy() {
	app.engine.Destroy()
}
<|endoftext|>


<commit_before>package kontena

import (
	"fmt"
	"os"

	"github.com/jakubknejzlik/kontena-git-cli/model"
	"github.com/jakubknejzlik/kontena-git-cli/utils"
)

// StackList ...
func (c *Client) StackList() ([]string, error) {
	var list []string
	res, err := utils.Run("kontena stack ls -q")

	if err != nil {
		return list, err
	}

	return utils.SplitString(string(res), "\n"), nil
}

// StackListInGrid ...
func (c *Client) StackListInGrid(grid string) ([]string, error) {
	var list []string
	res, err := utils.Run(fmt.Sprintf("kontena stack ls --grid %s -q", grid))

	if err != nil {
		return list, err
	}

	return utils.SplitString(string(res), "\n"), nil
}

// StackExists ...
func (c *Client) StackExists(stack string) bool {
	stacks, err := c.StackList()
	if err != nil {
		return false
	}

	for _, _stack := range stacks {
		if _stack == stack {
			return true
		}
	}

	return false
}

// StackExistsInGrid ...
func (c *Client) StackExistsInGrid(grid, stack string) bool {
	stacks, err := c.StackListInGrid(grid)
	if err != nil {
		return false
	}

	for _, _stack := range stacks {
		if _stack == stack {
			return true
		}
	}

	return false
}

// StackInstallOrUpgrade ...
func (c *Client) StackInstallOrUpgrade(stack model.KontenaStack) error {
	if c.StackExists(stack.Name) {
		return c.StackUpgrade(stack)
	}
	return c.StackInstall(stack)
}

// StackInstallOrUpgradeInGrid ...
func (c *Client) StackInstallOrUpgradeInGrid(grid string, stack model.KontenaStack) error {
	if c.StackExistsInGrid(grid, stack.Name) {
		return c.StackUpgradeInGrid(grid, stack)
	}
	return c.StackInstallInGrid(grid, stack)
}

// StackDeploy ...
func (c *Client) StackDeploy(name string) error {
	return utils.RunInteractive(fmt.Sprintf("kontena stack deploy %s", name))
}

// StackDeployInGrid ...
func (c *Client) StackDeployInGrid(grid, name string) error {
	return utils.RunInteractive(fmt.Sprintf("kontena stack deploy --grid %s %s", grid, name))
}

// StackInstall ...
func (c *Client) StackInstall(stack model.KontenaStack) error {
	return c.stackAction("install", stack.Name, stack)
}

// StackInstallInGrid ...
func (c *Client) StackInstallInGrid(grid string, stack model.KontenaStack) error {
	return c.stackActionInGrid("install", grid, stack.Name, stack)
}

// StackUpgrade ...
func (c *Client) StackUpgrade(stack model.KontenaStack) error {
	return c.stackAction("upgrade", stack.Name, stack)
}

// StackUpgradeInGrid ...
func (c *Client) StackUpgradeInGrid(grid string, stack model.KontenaStack) error {
	return c.stackActionInGrid("upgrade", grid, stack.Name, stack)
}

// StackRemove ...
func (c *Client) StackRemove(name string) error {
	return utils.RunInteractive(fmt.Sprintf("kontena stack remove --force %s", name))
}

// StackRemoveFromGrid ...
func (c *Client) StackRemoveFromGrid(grid, name string) error {
	return utils.RunInteractive(fmt.Sprintf("kontena stack remove --grid %s --force %s", grid, name))
}

func (c *Client) stackAction(action, name string, stack model.KontenaStack) error {
	dsPath, err := stack.ExportTemporary(true)
	if err != nil {
		return err
	}

	defer os.Remove(dsPath)

	cmd := fmt.Sprintf("kontena stack upgrade --no-deploy %s %s", name, dsPath)
	if action == "install" {
		cmd = fmt.Sprintf("kontena stack install --name %s %s", name, dsPath)
	}
	return utils.RunInteractive(cmd)
}

func (c *Client) stackActionInGrid(grid, action, name string, stack model.KontenaStack) error {
	dsPath, err := stack.ExportTemporary(true)
	if err != nil {
		return err
	}

	defer os.Remove(dsPath)

	cmd := fmt.Sprintf("kontena stack upgrade --grid %s --no-deploy %s %s", grid, name, dsPath)
	if action == "install" {
		cmd = fmt.Sprintf("kontena stack install --grid %s --name %s %s", grid, name, dsPath)
	}
	return utils.RunInteractive(cmd)
}
<commit_msg>Add force to stack upgrade<commit_after>package kontena

import (
	"fmt"
	"os"

	"github.com/jakubknejzlik/kontena-git-cli/model"
	"github.com/jakubknejzlik/kontena-git-cli/utils"
)

// StackList ...
func (c *Client) StackList() ([]string, error) {
	var list []string
	res, err := utils.Run("kontena stack ls -q")

	if err != nil {
		return list, err
	}

	return utils.SplitString(string(res), "\n"), nil
}

// StackListInGrid ...
func (c *Client) StackListInGrid(grid string) ([]string, error) {
	var list []string
	res, err := utils.Run(fmt.Sprintf("kontena stack ls --grid %s -q", grid))

	if err != nil {
		return list, err
	}

	return utils.SplitString(string(res), "\n"), nil
}

// StackExists ...
func (c *Client) StackExists(stack string) bool {
	stacks, err := c.StackList()
	if err != nil {
		return false
	}

	for _, _stack := range stacks {
		if _stack == stack {
			return true
		}
	}

	return false
}

// StackExistsInGrid ...
func (c *Client) StackExistsInGrid(grid, stack string) bool {
	stacks, err := c.StackListInGrid(grid)
	if err != nil {
		return false
	}

	for _, _stack := range stacks {
		if _stack == stack {
			return true
		}
	}

	return false
}

// StackInstallOrUpgrade ...
func (c *Client) StackInstallOrUpgrade(stack model.KontenaStack) error {
	if c.StackExists(stack.Name) {
		return c.StackUpgrade(stack)
	}
	return c.StackInstall(stack)
}

// StackInstallOrUpgradeInGrid ...
func (c *Client) StackInstallOrUpgradeInGrid(grid string, stack model.KontenaStack) error {
	if c.StackExistsInGrid(grid, stack.Name) {
		return c.StackUpgradeInGrid(grid, stack)
	}
	return c.StackInstallInGrid(grid, stack)
}

// StackDeploy ...
func (c *Client) StackDeploy(name string) error {
	return utils.RunInteractive(fmt.Sprintf("kontena stack deploy %s", name))
}

// StackDeployInGrid ...
func (c *Client) StackDeployInGrid(grid, name string) error {
	return utils.RunInteractive(fmt.Sprintf("kontena stack deploy --grid %s %s", grid, name))
}

// StackInstall ...
func (c *Client) StackInstall(stack model.KontenaStack) error {
	return c.stackAction("install", stack.Name, stack)
}

// StackInstallInGrid ...
func (c *Client) StackInstallInGrid(grid string, stack model.KontenaStack) error {
	return c.stackActionInGrid("install", grid, stack.Name, stack)
}

// StackUpgrade ...
func (c *Client) StackUpgrade(stack model.KontenaStack) error {
	return c.stackAction("upgrade", stack.Name, stack)
}

// StackUpgradeInGrid ...
func (c *Client) StackUpgradeInGrid(grid string, stack model.KontenaStack) error {
	return c.stackActionInGrid("upgrade", grid, stack.Name, stack)
}

// StackRemove ...
func (c *Client) StackRemove(name string) error {
	return utils.RunInteractive(fmt.Sprintf("kontena stack remove --force %s", name))
}

// StackRemoveFromGrid ...
func (c *Client) StackRemoveFromGrid(grid, name string) error {
	return utils.RunInteractive(fmt.Sprintf("kontena stack remove --grid %s --force %s", grid, name))
}

func (c *Client) stackAction(action, name string, stack model.KontenaStack) error {
	dsPath, err := stack.ExportTemporary(true)
	if err != nil {
		return err
	}

	defer os.Remove(dsPath)

	cmd := fmt.Sprintf("kontena stack upgrade --no-deploy %s %s", name, dsPath)
	if action == "install" {
		cmd = fmt.Sprintf("kontena stack install --name %s %s", name, dsPath)
	}
	return utils.RunInteractive(cmd)
}

func (c *Client) stackActionInGrid(grid, action, name string, stack model.KontenaStack) error {
	dsPath, err := stack.ExportTemporary(true)
	if err != nil {
		return err
	}

	defer os.Remove(dsPath)

	cmd := fmt.Sprintf("kontena stack upgrade --force --grid %s --no-deploy %s %s", grid, name, dsPath)
	if action == "install" {
		cmd = fmt.Sprintf("kontena stack install --grid %s --name %s %s", grid, name, dsPath)
	}
	return utils.RunInteractive(cmd)
}
<|endoftext|>


<commit_before>package main

import (
	"context"
	"fmt"
	"io/ioutil"
	"log"
	"time"

	"github.com/mafredri/cdp"
	"github.com/mafredri/cdp/cdpcmd"
	"github.com/mafredri/cdp/devtool"
	"github.com/mafredri/cdp/rpcc"
)

func main() {
	if err := run(); err != nil {
		panic(err)
	}
}

func run() error {
	ctx, cancel := context.WithCancel(context.TODO())
	defer cancel()

	devt := devtool.New("http://localhost:9222")

	page, err := devt.Get(ctx, devtool.Page)
	if err != nil {
		return err
	}

	conn, err := rpcc.DialContext(ctx, page.WebSocketDebuggerURL)
	if err != nil {
		return err
	}

	c := cdp.NewClient(conn)

	err = c.Page.Enable(ctx)
	if err != nil {
		return err
	}

	// Navigate to GitHub, block until ready.
	loadEventFired, err := c.Page.LoadEventFired(ctx)
	if err != nil {
		return err
	}

	_, err = c.Page.Navigate(ctx, cdpcmd.NewPageNavigateArgs("https://github.com"))
	if err != nil {
		return err
	}

	_, err = loadEventFired.Recv()
	if err != nil {
		return err
	}

	screencastFrame, err := c.Page.ScreencastFrame(ctx)
	if err != nil {
		return err
	}

	go func() {
		defer screencastFrame.Close()

		frameN := 0
		for {
			ev, err := screencastFrame.Recv()
			if err != nil {
				log.Printf("Failed to receive ScreencastFrame: %v", err)
				return
			}
			log.Printf("Got frame with sessionID: %d: %+v", ev.SessionID, ev.Metadata)

			err = c.Page.ScreencastFrameAck(ctx, cdpcmd.NewPageScreencastFrameAckArgs(ev.SessionID))
			if err != nil {
				log.Printf("Failed to ack ScreencastFrame: %v", err)
				return
			}

			// Write to screencast_frame-00000N.png.
			name := fmt.Sprintf("screencast_frame-%06d.png", frameN)
			frameN++

			// Write the frame to file (without blocking).
			go func() {
				err = ioutil.WriteFile(name, ev.Data, 0644)
				if err != nil {
					log.Printf("Failed to write ScreencastFrame to %q: %v", name, err)
				}
			}()
		}
	}()

	screencastArgs := cdpcmd.NewPageStartScreencastArgs().SetEveryNthFrame(1).SetFormat("png")
	err = c.Page.StartScreencast(ctx, screencastArgs)
	if err != nil {
		return err
	}

	// Random delay for our screencast.
	time.Sleep(30 * time.Second)

	err = c.Page.StopScreencast(ctx)
	if err != nil {
		return err
	}

	return nil
}
<commit_msg>example(screencast): Use timestamp for frames<commit_after>package main

import (
	"context"
	"fmt"
	"io/ioutil"
	"log"
	"time"

	"github.com/mafredri/cdp"
	"github.com/mafredri/cdp/cdpcmd"
	"github.com/mafredri/cdp/devtool"
	"github.com/mafredri/cdp/rpcc"
)

func main() {
	if err := run(); err != nil {
		panic(err)
	}
}

func run() error {
	ctx, cancel := context.WithCancel(context.TODO())
	defer cancel()

	devt := devtool.New("http://localhost:9222")

	page, err := devt.Get(ctx, devtool.Page)
	if err != nil {
		return err
	}

	conn, err := rpcc.DialContext(ctx, page.WebSocketDebuggerURL)
	if err != nil {
		return err
	}

	c := cdp.NewClient(conn)

	err = c.Page.Enable(ctx)
	if err != nil {
		return err
	}

	// Navigate to GitHub, block until ready.
	loadEventFired, err := c.Page.LoadEventFired(ctx)
	if err != nil {
		return err
	}

	_, err = c.Page.Navigate(ctx, cdpcmd.NewPageNavigateArgs("https://github.com"))
	if err != nil {
		return err
	}

	_, err = loadEventFired.Recv()
	if err != nil {
		return err
	}

	// Start listening to ScreencastFrame events.
	screencastFrame, err := c.Page.ScreencastFrame(ctx)
	if err != nil {
		return err
	}

	go func() {
		defer screencastFrame.Close()

		for {
			ev, err := screencastFrame.Recv()
			if err != nil {
				log.Printf("Failed to receive ScreencastFrame: %v", err)
				return
			}
			log.Printf("Got frame with sessionID: %d: %+v", ev.SessionID, ev.Metadata)

			err = c.Page.ScreencastFrameAck(ctx, cdpcmd.NewPageScreencastFrameAckArgs(ev.SessionID))
			if err != nil {
				log.Printf("Failed to ack ScreencastFrame: %v", err)
				return
			}

			// Write to screencast_frame-[timestamp].png.
			name := fmt.Sprintf("screencast_frame-%d.png", ev.Metadata.Timestamp.Time().Unix())

			// Write the frame to file (without blocking).
			go func() {
				err = ioutil.WriteFile(name, ev.Data, 0644)
				if err != nil {
					log.Printf("Failed to write ScreencastFrame to %q: %v", name, err)
				}
			}()
		}
	}()

	screencastArgs := cdpcmd.NewPageStartScreencastArgs().
		SetEveryNthFrame(1).
		SetFormat("png")
	err = c.Page.StartScreencast(ctx, screencastArgs)
	if err != nil {
		return err
	}

	// Random delay for our screencast.
	time.Sleep(30 * time.Second)

	err = c.Page.StopScreencast(ctx)
	if err != nil {
		return err
	}

	return nil
}
<|endoftext|>


<commit_before>package envy

import (
	"errors"
	"fmt"
	"log"
	"os"
	"reflect"
	"strconv"
	"strings"
)

var (
	// Error used when an invalid reference is provided to the Load function
	ErrInvalidConfigType = errors.New("A struct reference is required for loading config")

	// Basic config error
	ErrConfigInvalid = errors.New("Config is invalid")
)

var logger = log.New(os.Stderr, "[goenvy] ", log.LstdFlags|log.Lshortfile)

// interface that reads config from somewhere
type EnvironmentReader interface {
	// Method reads the environment from the source
	//
	// Returns: map[string]string of environment keys to values
	Read() map[string]string
}

// Loads directly from the environment
func Load(spec interface{}) error {
	osEnv := &OsEnvironmentReader{}
	return Load(osEnv)
}

// Loads config from the provided EnvironmentReader
func LoadFromEnv(reader EnvironmentReader, configSpec interface{}) error {
	source := reader.Read()

	// Find the value of the provided configSpec
	// It must be a struct of some kind in order for the values
	// to be set.
	s := reflect.ValueOf(configSpec).Elem()
	if s.Kind() != reflect.Struct {
		return ErrInvalidConfigType
	}

	// create a list of all errors
	errors := make([]error, 0)

	// iterate over all fields in the struct
	typeOfSpec := s.Type()
	for i := 0; i < s.NumField(); i++ {
		// reference to the value of the field (used for assignment)
		fieldValue := s.Field(i)
		// reference to the type of the field
		// (used to determine the name and any relevant struct tags)
		fieldType := typeOfSpec.Field(i)

		// Only uppercase values can be set (limitation of reflection)
		if fieldValue.CanSet() {
			fieldName := fieldType.Name

			// always assume uppercase key names
			key := strings.ToUpper(fieldName)

			// string used for outputting useful error messages
			example := fieldType.Tag.Get("example")

			// retrieve the value from the source, UPCASED
			// if this value is not available, track the error and continue with
			// the other options
			value, ok := source[key]
			if !ok {
				err := fmt.Errorf("Config not found: key=%s; example=%q", key, key, example)
				errors = append(errors, err)
				continue
			}

			// populate the struct values based on what type it is
			switch fieldValue.Kind() {
			case reflect.String:
				fieldValue.SetString(value)
			case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
				intValue, err := strconv.Atoi(value)
				if err != nil {
					err := fmt.Errorf("invalid value for int name=%s, value=%s; example=%q", key, value, key, example)
					errors = append(errors, err)
					continue
				}
				fieldValue.SetInt(int64(intValue))
			case reflect.Bool:
				boolValue, err := strconv.ParseBool(value)
				if err != nil {
					err := fmt.Errorf("invalid value for bool name=%s, value=%s; example=%q", key, value, key, example)
					errors = append(errors, err)
					continue
				}
				fieldValue.SetBool(boolValue)
			}
		}
	}

	if len(errors) > 0 {
		for _, err := range errors {
			logger.Println(err)
		}
		return ErrConfigInvalid
	}

	return nil
}

// Default EnvironmentReader
type OsEnvironmentReader struct{}

// Reads values from the os.Environ slice and returns the result
// as a map[string]string
func (o *OsEnvironmentReader) Read() map[string]string {
	result := make(map[string]string)
	for _, envVar := range os.Environ() {
		parts := strings.SplitN(envVar, "=", 2)
		result[parts[0]] = parts[1]
	}

	return result
}
<commit_msg>allow for prefix (defaulted to "")<commit_after>package envy

import (
	"errors"
	"fmt"
	"log"
	"os"
	"reflect"
	"strconv"
	"strings"
)

var (
	// Error used when an invalid reference is provided to the Load function
	ErrInvalidConfigType = errors.New("A struct reference is required for loading config")

	// Basic config error
	ErrConfigInvalid = errors.New("Config is invalid")
)

var logger = log.New(os.Stderr, "[goenvy] ", log.LstdFlags|log.Lshortfile)

// interface that reads config from somewhere
type EnvironmentReader interface {
	// Method reads the environment from the source
	//
	// Returns: map[string]string of environment keys to values
	Read() map[string]string
}

// Loads directly from the environment
func Load(spec interface{}) error {
	osEnv := &OsEnvironmentReader{}
	return LoadFromEnv(osEnv, spec)
}

// Loads the config using a prefix
func LoadWithPrefix(prefix string, spec interface{}) error {
	osEnv := &OsEnvironmentReader{prefix: prefix}
	return LoadFromEnv(osEnv, spec)
}

// Loads config from the provided EnvironmentReader
func LoadFromEnv(reader EnvironmentReader, configSpec interface{}) error {
	source := reader.Read()

	// Find the value of the provided configSpec
	// It must be a struct of some kind in order for the values
	// to be set.
	s := reflect.ValueOf(configSpec).Elem()
	if s.Kind() != reflect.Struct {
		return ErrInvalidConfigType
	}

	// create a list of all errors
	errors := make([]error, 0)

	// iterate over all fields in the struct
	typeOfSpec := s.Type()
	for i := 0; i < s.NumField(); i++ {
		// reference to the value of the field (used for assignment)
		fieldValue := s.Field(i)
		// reference to the type of the field
		// (used to determine the name and any relevant struct tags)
		fieldType := typeOfSpec.Field(i)

		// Only uppercase values can be set (limitation of reflection)
		if fieldValue.CanSet() {
			fieldName := fieldType.Name

			// always assume uppercase key names
			key := strings.ToUpper(fieldName)

			// string used for outputting useful error messages
			example := fieldType.Tag.Get("example")

			// retrieve the value from the source, UPCASED
			// if this value is not available, track the error and continue with
			// the other options
			value, ok := source[key]
			if !ok {
				err := fmt.Errorf("Config not found: key=%s; example=%q", key, example)
				errors = append(errors, err)
				continue
			}

			// populate the struct values based on what type it is
			switch fieldValue.Kind() {
			case reflect.String:
				fieldValue.SetString(value)
			case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
				intValue, err := strconv.Atoi(value)
				if err != nil {
					err := fmt.Errorf("invalid value for int name=%s, value=%s; example=%q", key, value, example)
					errors = append(errors, err)
					continue
				}
				fieldValue.SetInt(int64(intValue))
			case reflect.Bool:
				boolValue, err := strconv.ParseBool(value)
				if err != nil {
					err := fmt.Errorf("invalid value for bool name=%s, value=%s; example=%q", key, value, example)
					errors = append(errors, err)
					continue
				}
				fieldValue.SetBool(boolValue)
			}
		}
	}

	if len(errors) > 0 {
		for _, err := range errors {
			logger.Println(err)
		}
		return ErrConfigInvalid
	}

	return nil
}

// Default EnvironmentReader
// Reads environment with the provided prefix, defaulted to ""
type OsEnvironmentReader struct {
	prefix string
}

// Reads values from the os.Environ slice and returns the result
// as a map[string]string
func (o *OsEnvironmentReader) Read() map[string]string {
	result := make(map[string]string)
	for _, envVar := range os.Environ() {
		if strings.HasPrefix(envVar, o.prefix) {
			parts := strings.SplitN(envVar, "=", 2)

			// remove the prefix so we don't have to use it on the provided struct
			key := strings.TrimPrefix(parts[0], o.prefix)
			value := parts[1]
			result[key] = value
		}
	}

	return result
}
<|endoftext|>