<commit_before>// Package watcher is used for watching files and directories
// for automatic recompilation and restart of app on change
// when in development mode.
package watcher

import (
	"os"
	"path/filepath"
	"sync"

	"github.com/colegion/goal/utils/log"

	"gopkg.in/fsnotify.v1"
)

// Type is a watcher type that allows registering new
// pattern - actions pairs.
type Type struct {
	mu    sync.Mutex
	files map[string]bool
}

// NewType allocates and returns a new instance of watcher Type.
func NewType() *Type {
	return &Type{
		files: map[string]bool{},
	}
}

// Listen gets a pattern and a function. The function will be executed
// when files matching the pattern will be modified.
func (t *Type) Listen(pattern string, fn func()) *fsnotify.Watcher {
	// Create a new watcher.
	w, err := fsnotify.NewWatcher()
	log.AssertNil(err)

	// Find directories matching the pattern.
	ds := glob(pattern)

	// Add the files to the watcher.
	for i := range ds {
		log.Trace.Printf(`Adding "%s" to the list of watched directories...`, ds[i])
		err := w.Add(ds[i])
		if err != nil {
			log.Warn.Println(err)
		}
	}

	// Start watching process.
	go t.NotifyOnUpdate(filepath.ToSlash(pattern), w, fn)
	return w
}

// ListenFile is equivalent of Listen but for files.
// If file is added using ListenFile and the same file
// is withing a pattern of Listen, only the first one
// will trigger restarts.
// I.e. we have the following calls:
//	w.Listen("./", fn1)
//	w.ListenFile("./goal.yml", fn2)
// If "goal.yml" file is modified fn2 will be triggered.
// fn1 may be triggered by changes in any file inside
// "./" directory except "goal.yml".
func (t *Type) ListenFile(path string, fn func()) *fsnotify.Watcher {
	// Create a new watcher.
	w, err := fsnotify.NewWatcher()
	log.AssertNil(err)

	// Clean path and replace back slashes
	// to the normal ones.
	path = filepath.ToSlash(path)

	// Watch a directory instead of file.
	// See issue #17 of fsnotify to find out more
	// why we do this.
	dir := filepath.Join(path, "../")
	w.Add(dir)

	// Start watching process.
	t.files[path] = true
	go t.NotifyOnUpdate(path, w, fn)
	return w
}

// NotifyOnUpdate starts the function every time a file change
// event is received. Start it as a goroutine.
func (t *Type) NotifyOnUpdate(pattern string, watcher *fsnotify.Watcher, fn func()) {
	for {
		select {
		case ev := <-watcher.Events:
			// Convert path to the Linux format.
			name := filepath.ToSlash(ev.Name)

			// Make sure this is the exact event type that
			// requires a restart.
			if !restartRequired(ev) {
				continue
			}

			// If this is a directory watcher, but a file that was registered
			// with ListenFile has been modified,
			// ignore this event.
			if !t.files[pattern] && t.files[name] {
				continue
			}

			// If this is a single file watcher, make sure this is
			// exactly the file that should be watched, not
			// some other.
			if t.files[pattern] && name != pattern {
				continue
			}

			// Trigger the registered functions.
			t.mu.Lock()
			fn()
			t.mu.Unlock()
		case <-watcher.Errors:
			return
		}
	}
}

// restartRequired checks whether event indicates a file
// has been modified. If so, it returns true.
func restartRequired(event fsnotify.Event) bool {
	if event.Op&fsnotify.Chmod == fsnotify.Chmod {
		return true
	}
	return false
}

// glob returns names of all directories matching pattern or nil.
// The only supported special character is an asterisk at the end.
// It means that the directory is expected to be scanned recursively.
// There is no way for fsnotify to watch individual files (see #17),
// so we support only directories.
// File system errors such as I/O reading are ignored.
func glob(pattern string) (ds []string) {
	// Make sure pattern is not empty.
	l := len(pattern)
	if l == 0 {
		return
	}

	// Check whether we should scan the directory recursively.
	recurs := pattern[l-1] == '*'
	if recurs {
		// Trim the asterisk at the end.
		pattern = pattern[:l-1]
	}

	// Make sure such path exists and it is a directory rather than a file.
	info, err := os.Stat(pattern)
	if err != nil {
		return
	}
	if !info.IsDir() {
		log.Warn.Printf(`"%s" is not a directory, skipping it.`, pattern)
		return
	}

	// If not recursive scan was expected, return the path as is.
	if !recurs {
		ds = append(ds, pattern)
		return // Return as is.
	}

	// Start searching directories recursively.
	filepath.Walk(pattern, func(path string, info os.FileInfo, err error) error {
		// Make sure there are no any errors.
		if err != nil {
			return err
		}

		// Make sure the path represents a directory.
		if !info.IsDir() {
			return nil
		}

		// Add the directory path to the list.
		ds = append(ds, path)
		return nil
	})
	return
}
<commit_msg>Update watcher to restart on any event except CHMOD<commit_after>// Package watcher is used for watching files and directories
// for automatic recompilation and restart of app on change
// when in development mode.
package watcher

import (
	"os"
	"path/filepath"
	"sync"

	"github.com/colegion/goal/utils/log"

	"gopkg.in/fsnotify.v1"
)

// Type is a watcher type that allows registering new
// pattern - actions pairs.
type Type struct {
	mu    sync.Mutex
	files map[string]bool
}

// NewType allocates and returns a new instance of watcher Type.
func NewType() *Type {
	return &Type{
		files: map[string]bool{},
	}
}

// Listen gets a pattern and a function. The function will be executed
// when files matching the pattern will be modified.
func (t *Type) Listen(pattern string, fn func()) *fsnotify.Watcher {
	// Create a new watcher.
	w, err := fsnotify.NewWatcher()
	log.AssertNil(err)

	// Find directories matching the pattern.
	ds := glob(pattern)

	// Add the files to the watcher.
	for i := range ds {
		log.Trace.Printf(`Adding "%s" to the list of watched directories...`, ds[i])
		err := w.Add(ds[i])
		if err != nil {
			log.Warn.Println(err)
		}
	}

	// Start watching process.
	go t.NotifyOnUpdate(filepath.ToSlash(pattern), w, fn)
	return w
}

// ListenFile is equivalent of Listen but for files.
// If file is added using ListenFile and the same file
// is withing a pattern of Listen, only the first one
// will trigger restarts.
// I.e. we have the following calls:
//	w.Listen("./", fn1)
//	w.ListenFile("./goal.yml", fn2)
// If "goal.yml" file is modified fn2 will be triggered.
// fn1 may be triggered by changes in any file inside
// "./" directory except "goal.yml".
func (t *Type) ListenFile(path string, fn func()) *fsnotify.Watcher {
	// Create a new watcher.
	w, err := fsnotify.NewWatcher()
	log.AssertNil(err)

	// Clean path and replace back slashes
	// to the normal ones.
	path = filepath.ToSlash(path)

	// Watch a directory instead of file.
	// See issue #17 of fsnotify to find out more
	// why we do this.
	dir := filepath.Join(path, "../")
	w.Add(dir)

	// Start watching process.
	t.files[path] = true
	go t.NotifyOnUpdate(path, w, fn)
	return w
}

// NotifyOnUpdate starts the function every time a file change
// event is received. Start it as a goroutine.
func (t *Type) NotifyOnUpdate(pattern string, watcher *fsnotify.Watcher, fn func()) {
	for {
		select {
		case ev := <-watcher.Events:
			// Convert path to the Linux format.
			name := filepath.ToSlash(ev.Name)

			// Make sure this is the exact event type that
			// requires a restart.
			if !restartRequired(ev) {
				continue
			}

			// If this is a directory watcher, but a file that was registered
			// with ListenFile has been modified,
			// ignore this event.
			if !t.files[pattern] && t.files[name] {
				continue
			}

			// If this is a single file watcher, make sure this is
			// exactly the file that should be watched, not
			// some other.
			if t.files[pattern] && name != pattern {
				continue
			}

			// Trigger the registered functions.
			t.mu.Lock()
			fn()
			t.mu.Unlock()
		case <-watcher.Errors:
			return
		}
	}
}

// restartRequired checks whether event indicates a file
// has been modified. If so, it returns true.
func restartRequired(event fsnotify.Event) bool {
	if event.Op&fsnotify.Chmod == fsnotify.Chmod {
		return false
	}
	return true
}

// glob returns names of all directories matching pattern or nil.
// The only supported special character is an asterisk at the end.
// It means that the directory is expected to be scanned recursively.
// There is no way for fsnotify to watch individual files (see #17),
// so we support only directories.
// File system errors such as I/O reading are ignored.
func glob(pattern string) (ds []string) {
	// Make sure pattern is not empty.
	l := len(pattern)
	if l == 0 {
		return
	}

	// Check whether we should scan the directory recursively.
	recurs := pattern[l-1] == '*'
	if recurs {
		// Trim the asterisk at the end.
		pattern = pattern[:l-1]
	}

	// Make sure such path exists and it is a directory rather than a file.
	info, err := os.Stat(pattern)
	if err != nil {
		return
	}
	if !info.IsDir() {
		log.Warn.Printf(`"%s" is not a directory, skipping it.`, pattern)
		return
	}

	// If not recursive scan was expected, return the path as is.
	if !recurs {
		ds = append(ds, pattern)
		return // Return as is.
	}

	// Start searching directories recursively.
	filepath.Walk(pattern, func(path string, info os.FileInfo, err error) error {
		// Make sure there are no any errors.
		if err != nil {
			return err
		}

		// Make sure the path represents a directory.
		if !info.IsDir() {
			return nil
		}

		// Add the directory path to the list.
		ds = append(ds, path)
		return nil
	})
	return
}
<|endoftext|>


<commit_before>/*--------------------------------------------------------*\
|                                                          |
|                          hprose                          |
|                                                          |
| Official WebSite: https://hprose.com                     |
|                                                          |
| io/encoding/time_encoder.go                              |
|                                                          |
| LastModified: Mar 19, 2020                               |
| Author: Ma Bingyao <andot@hprose.com>                    |
|                                                          |
\*________________________________________________________*/

package encoding

import (
	"reflect"
	"time"

	"github.com/modern-go/reflect2"
)

// TimeEncoder is the implementation of ValueEncoder for time.Time/*time.Time.
type TimeEncoder struct{}

// Encode writes the hprose encoding of v to stream
// if v is already written to stream, it will writes it as reference
func (valenc TimeEncoder) Encode(enc *Encoder, v interface{}) (err error) {
	if reflect.TypeOf(v).Kind() == reflect.Struct {
		return valenc.Write(enc, v)
	}
	if reflect2.IsNil(v) {
		return WriteNil(enc.Writer)
	}
	var ok bool
	if ok, err = enc.WriteReference(v); !ok && err == nil {
		err = valenc.Write(enc, v)
	}
	return
}

// Write writes the hprose encoding of v to stream
// if v is already written to stream, it will writes it as value
func (TimeEncoder) Write(enc *Encoder, v interface{}) (err error) {
	t := reflect.TypeOf(v)
	var dt time.Time
	if t.Kind() == reflect.Ptr {
		enc.SetReference(v)
		dt = *(v.(*time.Time))
	} else {
		enc.AddReferenceCount(1)
		dt = v.(time.Time)
	}
	return WriteTime(enc.Writer, dt)
}

func init() {
	RegisterEncoder((*time.Time)(nil), TimeEncoder{})
}
<commit_msg>Update time_encoder.go<commit_after>/*--------------------------------------------------------*\
|                                                          |
|                          hprose                          |
|                                                          |
| Official WebSite: https://hprose.com                     |
|                                                          |
| io/encoding/time_encoder.go                              |
|                                                          |
| LastModified: Mar 20, 2020                               |
| Author: Ma Bingyao <andot@hprose.com>                    |
|                                                          |
\*________________________________________________________*/

package encoding

import (
	"reflect"
	"time"

	"github.com/modern-go/reflect2"
)

// TimeEncoder is the implementation of ValueEncoder for time.Time/*time.Time.
type TimeEncoder struct{}

// Encode writes the hprose encoding of v to stream
// if v is already written to stream, it will writes it as reference
func (valenc TimeEncoder) Encode(enc *Encoder, v interface{}) (err error) {
	if reflect.TypeOf(v).Kind() == reflect.Struct {
		return valenc.Write(enc, v)
	}
	if reflect2.IsNil(v) {
		return WriteNil(enc.Writer)
	}
	var ok bool
	if ok, err = enc.WriteReference(v); !ok && err == nil {
		err = valenc.Write(enc, v)
	}
	return
}

// Write writes the hprose encoding of v to stream
// if v is already written to stream, it will writes it as value
func (TimeEncoder) Write(enc *Encoder, v interface{}) (err error) {
	t := reflect.TypeOf(v)
	if t.Kind() == reflect.Ptr {
		enc.SetReference(v)
	} else {
		enc.AddReferenceCount(1)
	}
	return WriteTime(enc.Writer, *(*time.Time)(reflect2.PtrOf(v)))
}

func init() {
	RegisterEncoder((*time.Time)(nil), TimeEncoder{})
}
<|endoftext|>


<commit_before>package main

import (
  "fmt"
  "strconv"
  "time"
)

func Reverse(s string) string {
  r := []rune(s)
  for i, j := 0, len(r)-1; i < len(r)/2; i, j = i+1, j-1 {
    r[i], r[j] = r[j], r[i]
  }
  return string(r)
}

func Palindrome(str string) bool {
  return str == Reverse(str)
}

func LargestPalindromeFromTheProductOfThreeDigitNumbers() int {
  max := 999
  min := 99
  highest_palindrome := 0

  for first_number := max; first_number > min; first_number-- {
    for second_number := max; second_number > min; second_number-- {
      result := first_number * second_number

      if result < highest_palindrome {
        continue
      }

      if Palindrome(strconv.Itoa(result)) {
        highest_palindrome = result
      }
    }
  }
  return highest_palindrome
}

func main() {
  start := time.Now()
  result := LargestPalindromeFromTheProductOfThreeDigitNumbers()
  elapsed := time.Since(start)
  fmt.Printf("=> Result: %d\n", result)
  fmt.Printf("=> Time: %.8f\n", elapsed.Seconds())
}<commit_msg>Improves Go solution for problem 4<commit_after>package main

import (
  "fmt"
  "strconv"
  "time"
)

func Palindrome(str string) bool {
  for start, end := 0, len(str) - 1; start < end; start, end = start + 1, end - 1 {
    if str[start] != str[end] {
      return false
    }
  }
  return true
}

func LargestPalindromeFromTheProductOfThreeDigitNumbers() int {
  max := 999
  min := 99
  highest_palindrome := 0

  for first_number := max; first_number > min; first_number-- {
    for second_number := max; second_number > min; second_number-- {
      result := first_number * second_number

      if result < highest_palindrome {
        continue
      }

      if Palindrome(strconv.Itoa(result)) {
        highest_palindrome = result
      }
    }
  }
  return highest_palindrome
}

func main() {
  start := time.Now()
  result := LargestPalindromeFromTheProductOfThreeDigitNumbers()
  elapsed := time.Since(start)
  fmt.Printf("=> Result: %d\n", result)
  fmt.Printf("=> Time: %.8f\n", elapsed.Seconds())
}<|endoftext|>


<commit_before>// Copyright 2014 Hajime Hoshi
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package affine

import (
	"math"
)

// GeoMDim is a dimension of a GeoM.
const GeoMDim = 3

// A GeoM represents a matrix to transform geometry when rendering an image.
//
// The initial value is identity.
type GeoM struct {
	a      float64
	b      float64
	c      float64
	d      float64
	tx     float64
	ty     float64
	inited bool
}

func (g *GeoM) Reset() {
	g.inited = false
}

func (g *GeoM) Apply(x, y float64) (x2, y2 float64) {
	if !g.inited {
		return x, y
	}
	return g.a*x + g.b*y + g.tx, g.c*x + g.d*y + g.ty
}

func (g *GeoM) Apply32(x, y float64) (x2, y2 float32) {
	if !g.inited {
		return float32(x), float32(y)
	}
	return float32(g.a*x + g.b*y + g.tx), float32(g.c*x + g.d*y + g.ty)
}

func (g *GeoM) Elements() (a, b, c, d, tx, ty float64) {
	if !g.inited {
		return 1, 0, 0, 1, 0, 0
	}
	return g.a, g.b, g.c, g.d, g.tx, g.ty
}

func (g *GeoM) init() {
	g.a = 1
	g.b = 0
	g.c = 0
	g.d = 1
	g.tx = 0
	g.ty = 0
	g.inited = true
}

// SetElement sets an element at (i, j).
func (g *GeoM) SetElement(i, j int, element float64) {
	if !g.inited {
		g.init()
	}
	switch {
	case i == 0 && j == 0:
		g.a = element
	case i == 0 && j == 1:
		g.b = element
	case i == 0 && j == 2:
		g.tx = element
	case i == 1 && j == 0:
		g.c = element
	case i == 1 && j == 1:
		g.d = element
	case i == 1 && j == 2:
		g.ty = element
	default:
		panic("affine: i or j is out of index")
	}
}

// Concat multiplies a geometry matrix with the other geometry matrix.
// This is same as muptiplying the matrix other and the matrix g in this order.
func (g *GeoM) Concat(other *GeoM) {
	if !g.inited {
		g.init()
	}
	if !other.inited {
		other.init()
	}
	a, b, c, d, tx, ty := g.a, g.b, g.c, g.d, g.tx, g.ty
	g.a = other.a*a + other.b*c
	g.b = other.a*b + other.b*d
	g.tx = other.a*tx + other.b*ty + other.tx
	g.c = other.c*a + other.d*c
	g.d = other.c*b + other.d*d
	g.ty = other.c*tx + other.d*ty + other.ty
}

// Add is deprecated.
func (g *GeoM) Add(other GeoM) {
	if !g.inited {
		g.init()
	}
	if !other.inited {
		other.init()
	}
	g.a += other.a
	g.b += other.b
	g.c += other.c
	g.d += other.d
	g.tx += other.tx
	g.ty += other.ty
}

// Scale scales the matrix by (x, y).
func (g *GeoM) Scale(x, y float64) {
	if !g.inited {
		g.a = x
		g.b = 0
		g.c = 0
		g.d = y
		g.tx = 0
		g.ty = 0
		g.inited = true
		return
	}
	g.a *= x
	g.b *= x
	g.tx *= x
	g.c *= y
	g.d *= y
	g.ty *= y
}

// Translate translates the matrix by (x, y).
func (g *GeoM) Translate(tx, ty float64) {
	if !g.inited {
		g.a = 1
		g.b = 0
		g.c = 0
		g.d = 1
		g.tx = tx
		g.ty = ty
		g.inited = true
		return
	}
	g.tx += tx
	g.ty += ty
}

// Rotate rotates the matrix by theta.
func (g *GeoM) Rotate(theta float64) {
	sin, cos := math.Sincos(theta)
	if !g.inited {
		g.a = cos
		g.b = -sin
		g.c = sin
		g.d = cos
		g.tx = 0
		g.ty = 0
		g.inited = true
		return
	}
	a, b, c, d, tx, ty := g.a, g.b, g.c, g.d, g.tx, g.ty
	g.a = cos*a - sin*c
	g.b = cos*b - sin*d
	g.tx = cos*tx - sin*ty
	g.c = sin*a + cos*c
	g.d = sin*b + cos*d
	g.ty = sin*tx + cos*ty
}
<commit_msg>affine: Reduce copying cost of GeoM<commit_after>// Copyright 2014 Hajime Hoshi
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package affine

import (
	"fmt"
	"math"
)

// GeoMDim is a dimension of a GeoM.
const GeoMDim = 3

type geoMImpl struct {
	a  float64
	b  float64
	c  float64
	d  float64
	tx float64
	ty float64
}

// A GeoM represents a matrix to transform geometry when rendering an image.
//
// The initial value is identity.
type GeoM struct {
	impl *geoMImpl
}

func (g *GeoM) Reset() {
	g.impl = nil
}

func (g *GeoM) Apply(x, y float64) (x2, y2 float64) {
	if g.impl == nil {
		return x, y
	}
	i := g.impl
	return i.a*x + i.b*y + i.tx, i.c*x + i.d*y + i.ty
}

func (g *GeoM) Apply32(x, y float64) (x2, y2 float32) {
	if g.impl == nil {
		return float32(x), float32(y)
	}
	i := g.impl
	return float32(i.a*x + i.b*y + i.tx), float32(i.c*x + i.d*y + i.ty)
}

func (g *GeoM) Elements() (a, b, c, d, tx, ty float64) {
	if g.impl == nil {
		return 1, 0, 0, 1, 0, 0
	}
	i := g.impl
	return i.a, i.b, i.c, i.d, i.tx, i.ty
}

func (g *GeoM) init() {
	g.impl = &geoMImpl{
		a:  1,
		b:  0,
		c:  0,
		d:  1,
		tx: 0,
		ty: 0,
	}
}

// SetElement sets an element at (i, j).
func (g *GeoM) SetElement(i, j int, element float64) {
	if g.impl == nil {
		g.init()
	}
	a, b, c, d, tx, ty := g.impl.a, g.impl.b, g.impl.c, g.impl.d, g.impl.tx, g.impl.ty
	switch {
	case i == 0 && j == 0:
		a = element
	case i == 0 && j == 1:
		b = element
	case i == 0 && j == 2:
		tx = element
	case i == 1 && j == 0:
		c = element
	case i == 1 && j == 1:
		d = element
	case i == 1 && j == 2:
		ty = element
	default:
		panic(fmt.Sprintf("affine: i or j is out of index: (%d, %d)", i, j))
	}
	g.impl = &geoMImpl{
		a:  a,
		b:  b,
		c:  c,
		d:  d,
		tx: tx,
		ty: ty,
	}
}

// Concat multiplies a geometry matrix with the other geometry matrix.
// This is same as muptiplying the matrix other and the matrix g in this order.
func (g *GeoM) Concat(other *GeoM) {
	if g.impl == nil {
		g.init()
	}
	if other.impl == nil {
		other.init()
	}

	i := g.impl
	oi := other.impl
	g.impl = &geoMImpl{
		a:  oi.a*i.a + oi.b*i.c,
		b:  oi.a*i.b + oi.b*i.d,
		tx: oi.a*i.tx + oi.b*i.ty + oi.tx,
		c:  oi.c*i.a + oi.d*i.c,
		d:  oi.c*i.b + oi.d*i.d,
		ty: oi.c*i.tx + oi.d*i.ty + oi.ty,
	}
}

// Add is deprecated.
func (g *GeoM) Add(other GeoM) {
	if g.impl == nil {
		g.init()
	}
	if other.impl == nil {
		other.init()
	}
	g.impl = &geoMImpl{
		a:  g.impl.a + other.impl.a,
		b:  g.impl.b + other.impl.b,
		c:  g.impl.c + other.impl.c,
		d:  g.impl.d + other.impl.d,
		tx: g.impl.tx + other.impl.tx,
		ty: g.impl.ty + other.impl.ty,
	}
}

// Scale scales the matrix by (x, y).
func (g *GeoM) Scale(x, y float64) {
	if g.impl == nil {
		g.impl = &geoMImpl{
			a:  x,
			b:  0,
			c:  0,
			d:  y,
			tx: 0,
			ty: 0,
		}
		return
	}
	g.impl = &geoMImpl{
		a:  g.impl.a * x,
		b:  g.impl.b * x,
		tx: g.impl.tx * x,
		c:  g.impl.c * y,
		d:  g.impl.d * y,
		ty: g.impl.ty * y,
	}
}

// Translate translates the matrix by (x, y).
func (g *GeoM) Translate(tx, ty float64) {
	if g.impl == nil {
		g.impl = &geoMImpl{
			a:  1,
			b:  0,
			c:  0,
			d:  1,
			tx: tx,
			ty: ty,
		}
		return
	}
	g.impl = &geoMImpl{
		a:  g.impl.a,
		b:  g.impl.b,
		c:  g.impl.c,
		d:  g.impl.d,
		tx: g.impl.tx + tx,
		ty: g.impl.ty + ty,
	}
}

// Rotate rotates the matrix by theta.
func (g *GeoM) Rotate(theta float64) {
	sin, cos := math.Sincos(theta)
	if g.impl == nil {
		g.impl = &geoMImpl{
			a:  cos,
			b:  -sin,
			c:  sin,
			d:  cos,
			tx: 0,
			ty: 0,
		}
		return
	}
	g.impl = &geoMImpl{
		a:  cos*g.impl.a - sin*g.impl.c,
		b:  cos*g.impl.b - sin*g.impl.d,
		tx: cos*g.impl.tx - sin*g.impl.ty,
		c:  sin*g.impl.a + cos*g.impl.c,
		d:  sin*g.impl.b + cos*g.impl.d,
		ty: sin*g.impl.tx + cos*g.impl.ty,
	}
}
<|endoftext|>


<commit_before>package config

import (
	"os"

	"gopkg.in/yaml.v2"
)

func ReadRawConfigFromPath(configPath string) (map[string]interface{}, error) {
	if _, err := os.Stat(configPath); err != nil {
		return nil, err
	}
	yamlBytes, err := os.ReadFile(configPath)
	if err != nil {
		return nil, err
	}
	var config map[string]interface{}
	err = yaml.UnmarshalStrict(yamlBytes, &config)
	if err != nil {
		return nil, err
	}
	return config, nil
}
<commit_msg>Add missing license header<commit_after>// Copyright 2022 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package config

import (
	"os"

	"gopkg.in/yaml.v2"
)

func ReadRawConfigFromPath(configPath string) (map[string]interface{}, error) {
	if _, err := os.Stat(configPath); err != nil {
		return nil, err
	}
	yamlBytes, err := os.ReadFile(configPath)
	if err != nil {
		return nil, err
	}
	var config map[string]interface{}
	err = yaml.UnmarshalStrict(yamlBytes, &config)
	if err != nil {
		return nil, err
	}
	return config, nil
}
<|endoftext|>


<commit_before>package internal

import . "github.com/101loops/bdd"

var _ = Describe("DSPut", func() {

	var (
		kind Kind
	)

	BeforeEach(func() {
		kind = randomKind()
		clearCache()
	})

	It("saves an entity without id", func() {
		entity := &SimpleModel{}

		keys, err := DSPut(kind, entity, false)
		Check(err, IsNil)
		Check(keys, HasLen, 1)

		genID := keys[0].IntID()
		Check(genID, IsGreaterThan, 0)
		Check(entity.ID(), Equals, genID)
		Check(entity.lifecycle, Equals, []string{"before-save", "after-save"})
	})

	It("saves multiple entities without id", func() {
		entities := []*SimpleModel{
			&SimpleModel{}, &SimpleModel{},
		}

		keys, err := DSPut(kind, entities, false)
		Check(err, IsNil)
		Check(keys, HasLen, 2)

		Check(keys[0].IntID(), IsGreaterThan, 0)
		Check(entities[0].ID(), EqualsNum, keys[0].IntID())
		Check(keys[1].IntID(), IsGreaterThan, 0)
		Check(entities[1].ID(), EqualsNum, keys[1].IntID())
	})

	It("saves an entity with id", func() {
		entity := &SimpleModel{}
		entity.SetID(42)

		keys, err := DSPut(kind, entity, true)
		Check(err, IsNil)
		Check(keys, HasLen, 1)

		Check(entity.ID(), EqualsNum, 42)
		Check(keys[0].IntID(), EqualsNum, 42)
	})

	It("saves multiple entities with id", func() {
		entities := []*SimpleModel{&SimpleModel{}, &SimpleModel{}}
		entities[0].SetID(1)
		entities[1].SetID(2)

		keys, err := DSPut(kind, entities, true)
		Check(err, IsNil)
		Check(keys, HasLen, 2)

		Check(keys[0].IntID(), EqualsNum, 1)
		Check(keys[1].IntID(), EqualsNum, 2)
	})

	// ==== ERRORS

	It("does not save nil entity", func() {
		keys, err := DSPut(kind, nil, false)

		Check(keys, IsNil)
		Check(err, NotNil).And(Contains, "must be non-nil")
	})

	It("does not save non-struct entity", func() {
		keys, err := DSPut(kind, 42, false)

		Check(keys, IsNil)
		Check(err, NotNil).And(Contains, "invalid value kind").And(Contains, "int")
	})

	It("does not save entity without ID() and 42()", func() {
		invalidMdl := &InvalidModel{}
		keys, err := DSPut(kind, invalidMdl, false)

		Check(keys, IsNil)
		Check(err, NotNil).And(Contains, "does not provide ID")
	})

	It("does not save complete entity without Id", func() {
		entity := &SimpleModel{}
		keys, err := DSPut(kind, entity, true)

		Check(keys, IsNil)
		Check(err, NotNil).And(Contains, "is incomplete")
	})

	It("does not save empty entities", func() {
		entities := []*SimpleModel{}
		keys, err := DSPut(kind, entities, false)

		Check(keys, IsNil)
		Check(err, NotNil).And(Contains, "no keys provided")
	})
})
<commit_msg>fix typo<commit_after>package internal

import . "github.com/101loops/bdd"

var _ = Describe("DSPut", func() {

	var (
		kind Kind
	)

	BeforeEach(func() {
		kind = randomKind()
		clearCache()
	})

	It("saves an entity without id", func() {
		entity := &SimpleModel{}

		keys, err := DSPut(kind, entity, false)
		Check(err, IsNil)
		Check(keys, HasLen, 1)

		genID := keys[0].IntID()
		Check(genID, IsGreaterThan, 0)
		Check(entity.ID(), Equals, genID)
		Check(entity.lifecycle, Equals, []string{"before-save", "after-save"})
	})

	It("saves multiple entities without id", func() {
		entities := []*SimpleModel{
			&SimpleModel{}, &SimpleModel{},
		}

		keys, err := DSPut(kind, entities, false)
		Check(err, IsNil)
		Check(keys, HasLen, 2)

		Check(keys[0].IntID(), IsGreaterThan, 0)
		Check(entities[0].ID(), EqualsNum, keys[0].IntID())
		Check(keys[1].IntID(), IsGreaterThan, 0)
		Check(entities[1].ID(), EqualsNum, keys[1].IntID())
	})

	It("saves an entity with id", func() {
		entity := &SimpleModel{}
		entity.SetID(42)

		keys, err := DSPut(kind, entity, true)
		Check(err, IsNil)
		Check(keys, HasLen, 1)

		Check(entity.ID(), EqualsNum, 42)
		Check(keys[0].IntID(), EqualsNum, 42)
	})

	It("saves multiple entities with id", func() {
		entities := []*SimpleModel{&SimpleModel{}, &SimpleModel{}}
		entities[0].SetID(1)
		entities[1].SetID(2)

		keys, err := DSPut(kind, entities, true)
		Check(err, IsNil)
		Check(keys, HasLen, 2)

		Check(keys[0].IntID(), EqualsNum, 1)
		Check(keys[1].IntID(), EqualsNum, 2)
	})

	// ==== ERRORS

	It("does not save nil entity", func() {
		keys, err := DSPut(kind, nil, false)

		Check(keys, IsNil)
		Check(err, NotNil).And(Contains, "must be non-nil")
	})

	It("does not save non-struct entity", func() {
		keys, err := DSPut(kind, 42, false)

		Check(keys, IsNil)
		Check(err, NotNil).And(Contains, "invalid value kind").And(Contains, "int")
	})

	It("does not save entity without ID()", func() {
		invalidMdl := &InvalidModel{}
		keys, err := DSPut(kind, invalidMdl, false)

		Check(keys, IsNil)
		Check(err, NotNil).And(Contains, "does not provide ID")
	})

	It("does not save complete entity without Id", func() {
		entity := &SimpleModel{}
		keys, err := DSPut(kind, entity, true)

		Check(keys, IsNil)
		Check(err, NotNil).And(Contains, "is incomplete")
	})

	It("does not save empty entities", func() {
		entities := []*SimpleModel{}
		keys, err := DSPut(kind, entities, false)

		Check(keys, IsNil)
		Check(err, NotNil).And(Contains, "no keys provided")
	})
})
<|endoftext|>


<commit_before>package main

import (
	"cred-alert/scanners"
	"cred-alert/scanners/file"
	"cred-alert/sniff"
	"fmt"
	"log"
	"os"
	"path/filepath"

	"github.com/jessevdk/go-flags"
	"github.com/pivotal-golang/lager"
)

type Opts struct {
	Directory string `short:"d" long:"directory" description:"the directory to scan" value-name:"DIR"`
}

func main() {
	var opts Opts

	_, err := flags.ParseArgs(&opts, os.Args)
	if err != nil {
		os.Exit(1)
	}

	logger := lager.NewLogger("cred-alert-cli")
	logger.RegisterSink(lager.NewWriterSink(os.Stderr, lager.DEBUG))

	sniffer := sniff.NewDefaultSniffer()

	if opts.Directory != "" {
		scanDirectory(logger, sniffer, opts.Directory)
	} else {
		scanFile(logger, sniffer, os.Stdin)
	}
}

func handleViolation(line scanners.Line) error {
	fmt.Printf("Line matches pattern! File: %s, Line Number: %d, Content: %s\n", line.Path, line.LineNumber, line.Content)

	return nil
}

func scanFile(logger lager.Logger, sniffer sniff.Sniffer, fileHandle *os.File) {
	scanner := file.NewFileScanner(fileHandle)
	sniffer.Sniff(logger, scanner, handleViolation)
}

func scanDirectory(logger lager.Logger, sniffer sniff.Sniffer, directoryPath string) {
	stat, err := os.Stat(directoryPath)
	if err != nil {
		log.Fatalf("Cannot read directory %s\n", directoryPath)
	}

	if !stat.IsDir() {
		log.Fatalf("%s is not a directory\n", directoryPath)
	}

	walkFunc := func(path string, info os.FileInfo, err error) error {
		fh, err := os.Open(path)
		if err != nil {
			return err
		}
		if !info.IsDir() {
			scanFile(logger, sniffer, fh)
		}
		return nil
	}

	err = filepath.Walk(directoryPath, walkFunc)
	if err != nil {
		log.Fatalf("Error traversing directory: %v", err)
	}
}
<commit_msg>Remove scanFile<commit_after>package main

import (
	"cred-alert/scanners"
	"cred-alert/scanners/file"
	"cred-alert/sniff"
	"fmt"
	"log"
	"os"
	"path/filepath"

	"github.com/jessevdk/go-flags"
	"github.com/pivotal-golang/lager"
)

type Opts struct {
	Directory string `short:"d" long:"directory" description:"the directory to scan" value-name:"DIR"`
}

func main() {
	var opts Opts

	_, err := flags.ParseArgs(&opts, os.Args)
	if err != nil {
		os.Exit(1)
	}

	logger := lager.NewLogger("cred-alert-cli")
	logger.RegisterSink(lager.NewWriterSink(os.Stderr, lager.DEBUG))

	sniffer := sniff.NewDefaultSniffer()

	if opts.Directory != "" {
		scanDirectory(logger, sniffer, opts.Directory)
	} else {
		scanner := file.NewFileScanner(os.Stdin)
		sniffer.Sniff(logger, scanner, handleViolation)
	}
}

func handleViolation(line scanners.Line) error {
	fmt.Printf("Line matches pattern! File: %s, Line Number: %d, Content: %s\n", line.Path, line.LineNumber, line.Content)

	return nil
}

func scanDirectory(logger lager.Logger, sniffer sniff.Sniffer, directoryPath string) {
	stat, err := os.Stat(directoryPath)
	if err != nil {
		log.Fatalf("Cannot read directory %s\n", directoryPath)
	}

	if !stat.IsDir() {
		log.Fatalf("%s is not a directory\n", directoryPath)
	}

	walkFunc := func(path string, info os.FileInfo, err error) error {
		fh, err := os.Open(path)
		if err != nil {
			return err
		}
		if !info.IsDir() {
			scanner := file.NewFileScanner(fh)
			sniffer.Sniff(logger, scanner, handleViolation)
		}
		return nil
	}

	err = filepath.Walk(directoryPath, walkFunc)
	if err != nil {
		log.Fatalf("Error traversing directory: %v", err)
	}
}
<|endoftext|>


<commit_before>package web

import (
	"context"
	"fmt"
	"log"
	"net/http"
	"strings"
	"time"

	"github.com/mdlayher/mdlayher.com/internal/github"
	"github.com/mdlayher/mdlayher.com/internal/httptalks"
	"github.com/mdlayher/mdlayher.com/internal/medium"

	"github.com/prometheus/client_golang/prometheus"
	"github.com/prometheus/client_golang/prometheus/promhttp"
)

// A handler is a http.Handler that serves content using a template.
type handler struct {
	static   StaticContent
	redirect http.Handler
	ghc      github.Client
	mc       medium.Client
	htc      httptalks.Client

	requestDurationSeconds *prometheus.HistogramVec
}

// NewHandler creates a http.Handler that serves content using a template.
// Additional dynamic content can be added by providing non-nil clients for
// various services.
func NewHandler(static StaticContent, ghc github.Client, mc medium.Client, htc httptalks.Client) http.Handler {
	const namespace = "mdlayher"

	h := &handler{
		static:   static,
		redirect: NewRedirectHandler(static.Domain),
		ghc:      ghc,
		mc:       mc,
		htc:      htc,

		requestDurationSeconds: prometheus.NewHistogramVec(prometheus.HistogramOpts{
			Namespace: namespace,
			Name:      "request_duration_seconds",
			Help:      "Duration of requests to external services.",
			Buckets:   prometheus.ExponentialBuckets(0.1, 2, 7),
		}, []string{"target"}),
	}

	// Don't worry about registering this multiple times during tests.
	_ = prometheus.Register(h.requestDurationSeconds)

	// Set up application routes and metrics.
	mux := http.NewServeMux()
	mux.Handle("/", prometheus.InstrumentHandler("web", h))
	mux.Handle("/metrics", promhttp.Handler())

	return mux
}

// ServeHTTP implements http.Handler.
func (h *handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	// Redirect any TLS subdomain requests to the base domain name.
	if r.TLS != nil && strings.Count(r.TLS.ServerName, ".") > 1 {
		h.redirect.ServeHTTP(w, r)
		return
	}

	// HSTS support: https://hstspreload.org/.
	w.Header().Set("Strict-Transport-Security", HSTSHeader(time.Now()))

	// Dispatch a group of futures to fetch external data, to be evaluated
	// once ready to populate the Content structure.
	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
	defer cancel()

	repoFn := h.fetchGitHub(ctx)
	postFn := h.fetchMedium(ctx)
	talkFn := h.fetchTalks(ctx)

	repos, err := repoFn()
	if err != nil {
		httpError(w, "failed to fetch github repositories: %v", err)
		return
	}

	posts, err := postFn()
	if err != nil {
		httpError(w, "failed to fetch medium posts: %v", err)
		return
	}

	talks, err := talkFn()
	if err != nil {
		httpError(w, "failed to fetch talks: %v", err)
		return
	}

	// Build content for display.
	content := Content{
		Static: h.static,
		GitHub: GitHubContent{
			Repositories: repos,
		},
		Medium: MediumContent{
			Posts: posts,
		},
		HTTPTalks: HTTPTalksContent{
			Talks: talks,
		},
	}

	if err := tmpl.Execute(w, content); err != nil {
		httpError(w, "failed to execute template: %v", err)
		return
	}
}

// NewRedirectHandler creates a http.Handler that redirects clients to the
// specified domain using TLS and no subdomain.
func NewRedirectHandler(domain string) http.Handler {
	return http.RedirectHandler(fmt.Sprintf("https://%s", domain), http.StatusMovedPermanently)
}

// httpError returns a generic HTTP 500 to a client and logs an informative
// message to the logger.
func httpError(w http.ResponseWriter, format string, a ...interface{}) {
	log.Printf(format, a...)
	http.Error(w, "internal server error", http.StatusInternalServerError)
}
<commit_msg>internal/web: serve 404 for non-root pages<commit_after>package web

import (
	"context"
	"fmt"
	"log"
	"net/http"
	"strings"
	"time"

	"github.com/mdlayher/mdlayher.com/internal/github"
	"github.com/mdlayher/mdlayher.com/internal/httptalks"
	"github.com/mdlayher/mdlayher.com/internal/medium"

	"github.com/prometheus/client_golang/prometheus"
	"github.com/prometheus/client_golang/prometheus/promhttp"
)

// A handler is a http.Handler that serves content using a template.
type handler struct {
	static   StaticContent
	redirect http.Handler
	ghc      github.Client
	mc       medium.Client
	htc      httptalks.Client

	requestDurationSeconds *prometheus.HistogramVec
}

// NewHandler creates a http.Handler that serves content using a template.
// Additional dynamic content can be added by providing non-nil clients for
// various services.
func NewHandler(static StaticContent, ghc github.Client, mc medium.Client, htc httptalks.Client) http.Handler {
	const namespace = "mdlayher"

	h := &handler{
		static:   static,
		redirect: NewRedirectHandler(static.Domain),
		ghc:      ghc,
		mc:       mc,
		htc:      htc,

		requestDurationSeconds: prometheus.NewHistogramVec(prometheus.HistogramOpts{
			Namespace: namespace,
			Name:      "request_duration_seconds",
			Help:      "Duration of requests to external services.",
			Buckets:   prometheus.ExponentialBuckets(0.1, 2, 7),
		}, []string{"target"}),
	}

	// Don't worry about registering this multiple times during tests.
	_ = prometheus.Register(h.requestDurationSeconds)

	// Set up application routes and metrics.
	mux := http.NewServeMux()
	mux.Handle("/", prometheus.InstrumentHandler("web", h))
	mux.Handle("/metrics", promhttp.Handler())

	return mux
}

// ServeHTTP implements http.Handler.
func (h *handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	// Redirect any TLS subdomain requests to the base domain name.
	if r.TLS != nil && strings.Count(r.TLS.ServerName, ".") > 1 {
		h.redirect.ServeHTTP(w, r)
		return
	}

	// Only serve a page for root.
	if r.URL.Path != "/" {
		http.NotFound(w, r)
		return
	}

	// HSTS support: https://hstspreload.org/.
	w.Header().Set("Strict-Transport-Security", HSTSHeader(time.Now()))

	// Dispatch a group of futures to fetch external data, to be evaluated
	// once ready to populate the Content structure.
	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
	defer cancel()

	repoFn := h.fetchGitHub(ctx)
	postFn := h.fetchMedium(ctx)
	talkFn := h.fetchTalks(ctx)

	repos, err := repoFn()
	if err != nil {
		httpError(w, "failed to fetch github repositories: %v", err)
		return
	}

	posts, err := postFn()
	if err != nil {
		httpError(w, "failed to fetch medium posts: %v", err)
		return
	}

	talks, err := talkFn()
	if err != nil {
		httpError(w, "failed to fetch talks: %v", err)
		return
	}

	// Build content for display.
	content := Content{
		Static: h.static,
		GitHub: GitHubContent{
			Repositories: repos,
		},
		Medium: MediumContent{
			Posts: posts,
		},
		HTTPTalks: HTTPTalksContent{
			Talks: talks,
		},
	}

	if err := tmpl.Execute(w, content); err != nil {
		httpError(w, "failed to execute template: %v", err)
		return
	}
}

// NewRedirectHandler creates a http.Handler that redirects clients to the
// specified domain using TLS and no subdomain.
func NewRedirectHandler(domain string) http.Handler {
	return http.RedirectHandler(fmt.Sprintf("https://%s", domain), http.StatusMovedPermanently)
}

// httpError returns a generic HTTP 500 to a client and logs an informative
// message to the logger.
func httpError(w http.ResponseWriter, format string, a ...interface{}) {
	log.Printf(format, a...)
	http.Error(w, "internal server error", http.StatusInternalServerError)
}
<|endoftext|>


<commit_before>// Copyright (c) 2016 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

package client

import (
	"fmt"
	"sync"
	"sync/atomic"
	"testing"
	"time"

	"github.com/m3db/m3/src/dbnode/generated/thrift/rpc"
	"github.com/m3db/m3/src/dbnode/topology"
	xclose "github.com/m3db/m3/src/x/close"

	"github.com/golang/mock/gomock"
	"github.com/stretchr/testify/assert"
)

const (
	testHostStr  = "testhost"
	testHostAddr = testHostStr + ":9000"
)

var (
	h           = topology.NewHost(testHostStr, testHostAddr)
	channelNone = &nullChannel{}
)

func newConnectionPoolTestOptions() Options {
	return newSessionTestOptions().
		SetBackgroundConnectInterval(5 * time.Millisecond).
		SetBackgroundConnectStutter(2 * time.Millisecond).
		SetBackgroundHealthCheckInterval(5 * time.Millisecond).
		SetBackgroundHealthCheckStutter(2 * time.Millisecond)
}

func TestConnectionPoolConnectsAndRetriesConnects(t *testing.T) {
	// Scenario:
	// 1. Try fill 4 connections
	// > Fail 1 on connection step, have 3 connections
	// 2. Try fill remaining connection
	// > Fail 1 on health check, have 3 connections
	// 3. Try fill remaining connection
	// > Fulfill remaining connection, have 4 connections
	// 4. Don't bother

	var (
		attempts        int32
		sleeps          int32
		rounds          int32
		sleepWgs        [4]sync.WaitGroup
		proceedSleepWgs [3]sync.WaitGroup
		doneWg          sync.WaitGroup
	)
	for i := range sleepWgs {
		sleepWgs[i].Add(1)
	}
	for i := range proceedSleepWgs {
		proceedSleepWgs[i].Add(1)
	}
	doneWg.Add(1)

	opts := newConnectionPoolTestOptions()
	opts = opts.SetMaxConnectionCount(4)
	conns := newConnectionPool(h, opts).(*connPool)
	conns.newConn = func(ch string, addr string, opts Options) (xclose.SimpleCloser, rpc.TChanNode, error) {
		attempt := int(atomic.AddInt32(&attempts, 1))
		if attempt == 1 {
			return nil, nil, fmt.Errorf("a connect error")
		}
		return channelNone, nil, nil
	}
	conns.healthCheckNewConn = func(client rpc.TChanNode, opts Options) error {
		if atomic.LoadInt32(&rounds) == 1 {
			// If second round then fail health check
			return fmt.Errorf("a health check error")
		}
		return nil
	}
	conns.healthCheck = func(client rpc.TChanNode, opts Options) error {
		return nil
	}
	conns.sleepConnect = func(t time.Duration) {
		sleep := int(atomic.AddInt32(&sleeps, 1))
		if sleep <= 4 {
			if sleep <= len(sleepWgs) {
				sleepWgs[sleep-1].Done()
			}
			if sleep <= len(proceedSleepWgs) {
				proceedSleepWgs[sleep-1].Wait()
			}
		}
		if sleep == 4 {
			doneWg.Wait()
			return // All done
		}
		atomic.AddInt32(&rounds, 1)
		time.Sleep(time.Millisecond)
	}

	assert.Equal(t, 0, conns.ConnectionCount())

	conns.Open()

	// Wait for first round, should've created all conns except first
	sleepWgs[0].Wait()
	assert.Equal(t, 3, conns.ConnectionCount())
	proceedSleepWgs[0].Done()

	// Wait for second round, all attempts should succeed but all fail health checks
	sleepWgs[1].Wait()
	assert.Equal(t, 3, conns.ConnectionCount())
	proceedSleepWgs[1].Done()

	// Wait for third round, now should succeed and all connections accounted for
	sleepWgs[2].Wait()
	assert.Equal(t, 4, conns.ConnectionCount())
	doneAll := attempts
	proceedSleepWgs[2].Done()

	// Wait for fourth roundm, now should not involve attempting to spawn connections
	sleepWgs[3].Wait()
	// Ensure no more attempts done in fnal round
	assert.Equal(t, doneAll, attempts)

	conns.Close()
	doneWg.Done()

	nextClient, err := conns.NextClient()
	assert.Nil(t, nextClient)
	assert.Equal(t, errConnectionPoolClosed, err)
}

func TestConnectionPoolHealthChecks(t *testing.T) {
	ctrl := gomock.NewController(t)
	defer ctrl.Finish()

	// Scenario:
	// 1. Fill 2 connections
	// 2. Round 1, fail conn 0 health checks
	// > Take connection out
	// 3. Round 2, fail conn 1 health checks
	// > Take connection out
	opts := newConnectionPoolTestOptions()
	opts = opts.SetMaxConnectionCount(2)
	opts = opts.SetHostConnectTimeout(10 * time.Second)
	healthCheckFailLimit := opts.BackgroundHealthCheckFailLimit()
	healthCheckFailThrottleFactor := opts.BackgroundHealthCheckFailThrottleFactor()

	var (
		newConnAttempt int32
		connectRounds  int32
		healthRounds   int32
		invokeFail     int32
		client1        = rpc.TChanNode(rpc.NewMockTChanNode(ctrl))
		client2        = rpc.TChanNode(rpc.NewMockTChanNode(ctrl))
		overrides      = []healthCheckFn{}
		overridesMut   sync.RWMutex
		pushOverride   = func(fn healthCheckFn, count int) {
			overridesMut.Lock()
			defer overridesMut.Unlock()
			for i := 0; i < count; i++ {
				overrides = append(overrides, fn)
			}
		}
		popOverride = func() healthCheckFn {
			overridesMut.Lock()
			defer overridesMut.Unlock()
			if len(overrides) == 0 {
				return nil
			}
			next := overrides[0]
			overrides = overrides[1:]
			return next
		}
		pushFailClientOverride = func(failTargetClient rpc.TChanNode) {
			var failOverride healthCheckFn
			failOverride = func(client rpc.TChanNode, opts Options) error {
				if client == failTargetClient {
					atomic.AddInt32(&invokeFail, 1)
					return fmt.Errorf("fail client")
				}
				// Not failing this client, re-enqueue
				pushOverride(failOverride, 1)
				return nil
			}
			pushOverride(failOverride, healthCheckFailLimit)
		}
		onNextSleepHealth     []func()
		onNextSleepHealthMut  sync.RWMutex
		pushOnNextSleepHealth = func(fn func()) {
			onNextSleepHealthMut.Lock()
			defer onNextSleepHealthMut.Unlock()
			onNextSleepHealth = append(onNextSleepHealth, fn)
		}
		popOnNextSleepHealth = func() func() {
			onNextSleepHealthMut.Lock()
			defer onNextSleepHealthMut.Unlock()
			if len(onNextSleepHealth) == 0 {
				return nil
			}
			next := onNextSleepHealth[0]
			onNextSleepHealth = onNextSleepHealth[1:]
			return next
		}
		failsDoneWg [2]sync.WaitGroup
		failsDone   [2]int32
	)
	for i := range failsDoneWg {
		failsDoneWg[i].Add(1)
	}

	conns := newConnectionPool(h, opts).(*connPool)
	conns.newConn = func(ch string, addr string, opts Options) (xclose.SimpleCloser, rpc.TChanNode, error) {
		attempt := atomic.AddInt32(&newConnAttempt, 1)
		if attempt == 1 {
			return channelNone, client1, nil
		} else if attempt == 2 {
			return channelNone, client2, nil
		}
		return nil, nil, fmt.Errorf("spawning only 2 connections")
	}
	conns.healthCheckNewConn = func(client rpc.TChanNode, opts Options) error {
		return nil
	}
	conns.healthCheck = func(client rpc.TChanNode, opts Options) error {
		if fn := popOverride(); fn != nil {
			return fn(client, opts)
		}
		return nil
	}
	conns.sleepConnect = func(d time.Duration) {
		atomic.AddInt32(&connectRounds, 1)
		time.Sleep(time.Millisecond)
	}
	conns.sleepHealth = func(d time.Duration) {
		atomic.AddInt32(&healthRounds, 1)
		if int(atomic.LoadInt32(&invokeFail)) == 1*healthCheckFailLimit &&
			atomic.CompareAndSwapInt32(&failsDone[0], 0, 1) {
			failsDoneWg[0].Done()
		} else if int(atomic.LoadInt32(&invokeFail)) == 2*healthCheckFailLimit &&
			atomic.CompareAndSwapInt32(&failsDone[1], 0, 1) {
			failsDoneWg[1].Done()
		}
		time.Sleep(time.Millisecond)
		if fn := popOnNextSleepHealth(); fn != nil {
			fn()
		}
	}
	conns.sleepHealthRetry = func(d time.Duration) {
		expected := healthCheckFailThrottleFactor * float64(opts.HostConnectTimeout())
		assert.Equal(t, time.Duration(expected), d)
	}

	assert.Equal(t, 0, conns.ConnectionCount())

	conns.Open()

	// Wait for first round, should've created all conns except first
	for atomic.LoadInt32(&connectRounds) < 1 {
		time.Sleep(time.Millisecond)
	}

	assert.Equal(t, 2, conns.ConnectionCount())

	// Fail client1 health check
	pushOnNextSleepHealth(func() {
		pushFailClientOverride(client1)
	})

	// Wait for health check round to take action
	failsDoneWg[0].Wait()

	// Verify only 1 connection and its client2
	assert.Equal(t, 1, conns.ConnectionCount())
	for i := 0; i < 2; i++ {
		nextClient, err := conns.NextClient()
		assert.NoError(t, err)
		assert.Equal(t, client2, nextClient)
	}

	// Fail client2 health check
	pushOnNextSleepHealth(func() {
		pushFailClientOverride(client2)
	})

	// Wait for health check round to take action
	failsDoneWg[1].Wait()
	assert.Equal(t, 0, conns.ConnectionCount())
	nextClient, err := conns.NextClient()
	assert.Nil(t, nextClient)
	assert.Equal(t, errConnectionPoolHasNoConnections, err)

	conns.Close()

	nextClient, err = conns.NextClient()
	assert.Nil(t, nextClient)
	assert.Equal(t, errConnectionPoolClosed, err)
}

type nullChannel struct{}

func (*nullChannel) Close() {}
<commit_msg>Make TestConnectionPoolHealthChecks not flaky (#1714)<commit_after>// Copyright (c) 2016 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

package client

import (
	"fmt"
	"sync"
	"sync/atomic"
	"testing"
	"time"

	"github.com/m3db/m3/src/dbnode/generated/thrift/rpc"
	"github.com/m3db/m3/src/dbnode/topology"
	xclock "github.com/m3db/m3/src/x/clock"
	xclose "github.com/m3db/m3/src/x/close"
	"github.com/stretchr/testify/require"

	"github.com/golang/mock/gomock"
)

const (
	testHostStr  = "testhost"
	testHostAddr = testHostStr + ":9000"
)

var (
	h           = topology.NewHost(testHostStr, testHostAddr)
	channelNone = &nullChannel{}
)

func newConnectionPoolTestOptions() Options {
	return newSessionTestOptions().
		SetBackgroundConnectInterval(5 * time.Millisecond).
		SetBackgroundConnectStutter(2 * time.Millisecond).
		SetBackgroundHealthCheckInterval(5 * time.Millisecond).
		SetBackgroundHealthCheckStutter(2 * time.Millisecond)
}

func TestConnectionPoolConnectsAndRetriesConnects(t *testing.T) {
	// Scenario:
	// 1. Try fill 4 connections
	// > Fail 1 on connection step, have 3 connections
	// 2. Try fill remaining connection
	// > Fail 1 on health check, have 3 connections
	// 3. Try fill remaining connection
	// > Fulfill remaining connection, have 4 connections
	// 4. Don't bother

	var (
		attempts        int32
		sleeps          int32
		rounds          int32
		sleepWgs        [4]sync.WaitGroup
		proceedSleepWgs [3]sync.WaitGroup
		doneWg          sync.WaitGroup
	)
	for i := range sleepWgs {
		sleepWgs[i].Add(1)
	}
	for i := range proceedSleepWgs {
		proceedSleepWgs[i].Add(1)
	}
	doneWg.Add(1)

	opts := newConnectionPoolTestOptions()
	opts = opts.SetMaxConnectionCount(4)
	conns := newConnectionPool(h, opts).(*connPool)
	conns.newConn = func(ch string, addr string, opts Options) (xclose.SimpleCloser, rpc.TChanNode, error) {
		attempt := int(atomic.AddInt32(&attempts, 1))
		if attempt == 1 {
			return nil, nil, fmt.Errorf("a connect error")
		}
		return channelNone, nil, nil
	}
	conns.healthCheckNewConn = func(client rpc.TChanNode, opts Options) error {
		if atomic.LoadInt32(&rounds) == 1 {
			// If second round then fail health check
			return fmt.Errorf("a health check error")
		}
		return nil
	}
	conns.healthCheck = func(client rpc.TChanNode, opts Options) error {
		return nil
	}
	conns.sleepConnect = func(t time.Duration) {
		sleep := int(atomic.AddInt32(&sleeps, 1))
		if sleep <= 4 {
			if sleep <= len(sleepWgs) {
				sleepWgs[sleep-1].Done()
			}
			if sleep <= len(proceedSleepWgs) {
				proceedSleepWgs[sleep-1].Wait()
			}
		}
		if sleep == 4 {
			doneWg.Wait()
			return // All done
		}
		atomic.AddInt32(&rounds, 1)
		time.Sleep(time.Millisecond)
	}

	require.Equal(t, 0, conns.ConnectionCount())

	conns.Open()

	// Wait for first round, should've created all conns except first
	sleepWgs[0].Wait()
	require.Equal(t, 3, conns.ConnectionCount())
	proceedSleepWgs[0].Done()

	// Wait for second round, all attempts should succeed but all fail health checks
	sleepWgs[1].Wait()
	require.Equal(t, 3, conns.ConnectionCount())
	proceedSleepWgs[1].Done()

	// Wait for third round, now should succeed and all connections accounted for
	sleepWgs[2].Wait()
	require.Equal(t, 4, conns.ConnectionCount())
	doneAll := attempts
	proceedSleepWgs[2].Done()

	// Wait for fourth roundm, now should not involve attempting to spawn connections
	sleepWgs[3].Wait()
	// Ensure no more attempts done in fnal round
	require.Equal(t, doneAll, attempts)

	conns.Close()
	doneWg.Done()

	nextClient, err := conns.NextClient()
	require.Nil(t, nextClient)
	require.Equal(t, errConnectionPoolClosed, err)
}

func TestConnectionPoolHealthChecks(t *testing.T) {
	ctrl := gomock.NewController(t)
	defer ctrl.Finish()

	// Scenario:
	// 1. Fill 2 connections
	// 2. Round 1, fail conn 0 health checks
	// > Take connection out
	// 3. Round 2, fail conn 1 health checks
	// > Take connection out
	opts := newConnectionPoolTestOptions()
	opts = opts.SetMaxConnectionCount(2)
	opts = opts.SetHostConnectTimeout(10 * time.Second)
	healthCheckFailLimit := opts.BackgroundHealthCheckFailLimit()
	healthCheckFailThrottleFactor := opts.BackgroundHealthCheckFailThrottleFactor()

	var (
		newConnAttempt int32
		connectRounds  int32
		healthRounds   int32
		invokeFail     int32
		client1        = rpc.TChanNode(rpc.NewMockTChanNode(ctrl))
		client2        = rpc.TChanNode(rpc.NewMockTChanNode(ctrl))
		overrides      = []healthCheckFn{}
		overridesMut   sync.RWMutex
		pushOverride   = func(fn healthCheckFn, count int) {
			overridesMut.Lock()
			defer overridesMut.Unlock()
			for i := 0; i < count; i++ {
				overrides = append(overrides, fn)
			}
		}
		popOverride = func() healthCheckFn {
			overridesMut.Lock()
			defer overridesMut.Unlock()
			if len(overrides) == 0 {
				return nil
			}
			next := overrides[0]
			overrides = overrides[1:]
			return next
		}
		pushFailClientOverride = func(failTargetClient rpc.TChanNode) {
			var failOverride healthCheckFn
			failOverride = func(client rpc.TChanNode, opts Options) error {
				if client == failTargetClient {
					atomic.AddInt32(&invokeFail, 1)
					return fmt.Errorf("fail client")
				}
				// Not failing this client, re-enqueue
				pushOverride(failOverride, 1)
				return nil
			}
			pushOverride(failOverride, healthCheckFailLimit)
		}
		onNextSleepHealth     []func()
		onNextSleepHealthMut  sync.RWMutex
		pushOnNextSleepHealth = func(fn func()) {
			onNextSleepHealthMut.Lock()
			defer onNextSleepHealthMut.Unlock()
			onNextSleepHealth = append(onNextSleepHealth, fn)
		}
		popOnNextSleepHealth = func() func() {
			onNextSleepHealthMut.Lock()
			defer onNextSleepHealthMut.Unlock()
			if len(onNextSleepHealth) == 0 {
				return nil
			}
			next := onNextSleepHealth[0]
			onNextSleepHealth = onNextSleepHealth[1:]
			return next
		}
		failsDoneWg [2]sync.WaitGroup
		failsDone   [2]int32
	)
	for i := range failsDoneWg {
		failsDoneWg[i].Add(1)
	}

	conns := newConnectionPool(h, opts).(*connPool)
	conns.newConn = func(ch string, addr string, opts Options) (xclose.SimpleCloser, rpc.TChanNode, error) {
		attempt := atomic.AddInt32(&newConnAttempt, 1)
		if attempt == 1 {
			return channelNone, client1, nil
		} else if attempt == 2 {
			return channelNone, client2, nil
		}
		return nil, nil, fmt.Errorf("spawning only 2 connections")
	}
	conns.healthCheckNewConn = func(client rpc.TChanNode, opts Options) error {
		return nil
	}
	conns.healthCheck = func(client rpc.TChanNode, opts Options) error {
		if fn := popOverride(); fn != nil {
			return fn(client, opts)
		}
		return nil
	}
	conns.sleepConnect = func(d time.Duration) {
		atomic.AddInt32(&connectRounds, 1)
		time.Sleep(time.Millisecond)
	}
	conns.sleepHealth = func(d time.Duration) {
		atomic.AddInt32(&healthRounds, 1)
		if int(atomic.LoadInt32(&invokeFail)) == 1*healthCheckFailLimit &&
			atomic.CompareAndSwapInt32(&failsDone[0], 0, 1) {
			failsDoneWg[0].Done()
		} else if int(atomic.LoadInt32(&invokeFail)) == 2*healthCheckFailLimit &&
			atomic.CompareAndSwapInt32(&failsDone[1], 0, 1) {
			failsDoneWg[1].Done()
		}
		time.Sleep(time.Millisecond)
		if fn := popOnNextSleepHealth(); fn != nil {
			fn()
		}
	}
	conns.sleepHealthRetry = func(d time.Duration) {
		expected := healthCheckFailThrottleFactor * float64(opts.HostConnectTimeout())
		require.Equal(t, time.Duration(expected), d)
	}

	require.Equal(t, 0, conns.ConnectionCount())

	conns.Open()

	// Wait for first round, should've created all conns except first
	for atomic.LoadInt32(&connectRounds) < 1 {
		time.Sleep(time.Millisecond)
	}

	require.Equal(t, 2, conns.ConnectionCount())

	// Fail client1 health check
	pushOnNextSleepHealth(func() {
		pushFailClientOverride(client1)
	})

	// Wait for health check round to take action
	failsDoneWg[0].Wait()

	// Verify only 1 connection and its client2
	xclock.WaitUntil(func() bool {
		// Need WaitUntil() because there is a delay between the health check failing
		// and the connection actually being removed.
		return conns.ConnectionCount() == 1
	}, 5*time.Second)
	for i := 0; i < 2; i++ {
		nextClient, err := conns.NextClient()
		require.NoError(t, err)
		require.Equal(t, client2, nextClient)
	}

	// Fail client2 health check
	pushOnNextSleepHealth(func() {
		pushFailClientOverride(client2)
	})

	// Wait for health check round to take action
	failsDoneWg[1].Wait()
	xclock.WaitUntil(func() bool {
		// Need WaitUntil() because there is a delay between the health check failing
		// and the connection actually being removed.
		return conns.ConnectionCount() == 0
	}, 5*time.Second)
	nextClient, err := conns.NextClient()
	require.Nil(t, nextClient)
	require.Equal(t, errConnectionPoolHasNoConnections, err)

	conns.Close()

	nextClient, err = conns.NextClient()
	require.Nil(t, nextClient)
	require.Equal(t, errConnectionPoolClosed, err)
}

type nullChannel struct{}

func (*nullChannel) Close() {}
<|endoftext|>


<commit_before>// This program accesses XP website and calculates the annualized return rate of
// each fund during its whole existence. You need to inform the Cookie that your
// session is using. To do so, use the inspection function of your web browser
// and see the Cookie header that is being sent after you login to XP.
package main

import (
	"bufio"
    "fmt"
	"log"
	"math"
	"os"
	"strconv"
	"strings"
)

func formatFloat(f float64) string {
	return strings.Replace(strconv.FormatFloat(f, 'f', 2, 64), ".", ",", 1)
}

func main() {
	r := bufio.NewReader(os.Stdin)
	fmt.Printf("Nome\tMínimo\tDias para resgate\tIdade em meses\tDesvio padrão\tMeses negativos\tMaior queda\tPeríodo da maior queda em meses\tRentabilidade anualizada\n")
	for true {
		line, err := r.ReadString('\n')
		if err != nil {
			break
		}
		fields := strings.Split(strings.Trim(line, "\n"), "\t")
		if fields == nil {
			break
		}
		fmt.Printf("%s", fields[0])
		fmt.Printf("\t%s", fields[1])
		cot, err := strconv.Atoi(fields[2])
		if err != nil {
			log.Fatal(err)
		}
		liq, err := strconv.Atoi(fields[3])
		if err != nil {
			log.Fatal(err)
		}
		fmt.Printf("\t%d", cot + liq)
		prod := 1.0
		sum := 0.0
		neg := 0
		var values []float64
		for i := 4; i < len(fields); i++ {
			v, err := strconv.ParseFloat(strings.Replace(fields[i], ",", ".", 1), 64)
			if err != nil {
				log.Fatal(err)
			}
			v /= 100.0
			prod *= 1.0 + v
			sum += v
			values = append(values, v)
			if (v < 0) {
				neg++
			}
		}
		mean := sum / float64(len(values))
		total := 0.0
		for _, v := range values {
			total += math.Pow(v-mean, 2)
		}
		gd := 1.0
		gds := 0
		for i := range values {
			prod := 1.0
			for j := i; j < len(values); j++ {
				prod *= 1.0 + values[j]
				if prod < gd {
					gd = prod
					gds = j - i + 1
				}
			}
		}
		fmt.Printf("\t%d\t%s\t%s%%\t%s%%\t%d\t%s%%\n", len(values), formatFloat(100.0 * math.Sqrt(total / float64(len(values)))), formatFloat(100.0 * float64(neg) / float64(len(values))), formatFloat((gd - 1.0) * 100.0), gds, formatFloat((math.Pow(prod, 1.0 / (float64(len(values)) / 12.0)) - 1.0) * 100.0))
	}
}
<commit_msg>order<commit_after>// This program accesses XP website and calculates the annualized return rate of
// each fund during its whole existence. You need to inform the Cookie that your
// session is using. To do so, use the inspection function of your web browser
// and see the Cookie header that is being sent after you login to XP.
package main

import (
	"bufio"
	"fmt"
	"log"
	"math"
	"os"
	"strconv"
	"strings"
)

func formatFloat(f float64) string {
	return strings.Replace(strconv.FormatFloat(f, 'f', 2, 64), ".", ",", 1)
}

func main() {
	r := bufio.NewReader(os.Stdin)
	fmt.Printf("Nome\tMínimo\tDias para resgate\tIdade em meses\tDesvio padrão\tMeses negativos\tMaior queda\tPeríodo da maior queda em meses\tRentabilidade anualizada\n")
	for true {
		line, err := r.ReadString('\n')
		if err != nil {
			break
		}
		fields := strings.Split(strings.Trim(line, "\n"), "\t")
		if fields == nil {
			break
		}
		fmt.Printf("%s", fields[0])
		fmt.Printf("\t%s", fields[1])
		cot, err := strconv.Atoi(fields[2])
		if err != nil {
			log.Fatal(err)
		}
		liq, err := strconv.Atoi(fields[3])
		if err != nil {
			log.Fatal(err)
		}
		fmt.Printf("\t%d", cot+liq)
		prod := 1.0
		sum := 0.0
		neg := 0
		var values []float64
		for year := (len(fields) - 4) / 12; year >= 0; year-- {
			for month := 0; month < 12; month++ {
				i := year*12 + month + 4
				if i >= len(fields) {
					break
				}
				v, err := strconv.ParseFloat(strings.Replace(fields[i], ",", ".", 1), 64)
				if err != nil {
					log.Fatal(err)
				}
				v /= 100.0
				prod *= 1.0 + v
				sum += v
				values = append(values, v)
				if v < 0 {
					neg++
				}
			}
		}
		mean := sum / float64(len(values))
		total := 0.0
		for _, v := range values {
			total += math.Pow(v-mean, 2)
		}
		gd := 1.0
		gds := 0
		for i := range values {
			prod := 1.0
			for j := i; j < len(values); j++ {
				prod *= 1.0 + values[j]
				if prod < gd {
					gd = prod
					gds = j - i + 1
				}
			}
		}
		fmt.Printf("\t%d\t%s\t%s%%\t%s%%\t%d\t%s%%\n", len(values), formatFloat(100.0*math.Sqrt(total/float64(len(values)))), formatFloat(100.0*float64(neg)/float64(len(values))), formatFloat((gd-1.0)*100.0), gds, formatFloat((math.Pow(prod, 1.0/(float64(len(values))/12.0))-1.0)*100.0))
	}
}
<|endoftext|>


<commit_before>package sprok

/*
 * Copyright 2014 Albert P. Tobey <atobey@datastax.com> @AlTobey
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import (
	"fmt"
	"log"
	"os"
	"os/exec"
	"strings"
	"syscall"
)

// Process is the configuration for running a process
type Process struct {
	Chdir  string            `json:"chdir"  yaml:"chdir"`  // cd /tmp
	Env    map[string]string `json:"env"    yaml:"env"`    // env FOO=BAR
	Argv   []string          `json:"argv"   yaml:"argv"`   // "/bin/dd" "if=/dev/zero" "count=10"
	Stdin  string            `json:"stdin"  yaml:"stdin"`  // <"/dev/null"
	Stdout string            `json:"stdout" yaml:"stdout"` // >"zero.bin"
	Stderr string            `json:"stderr" yaml:"stderr"` // 2>"errors.log"
}

// NewProcess returns a Process struct with the env map and argv allocated
// and all stdio pointed at /dev/null.
// argv is allocated with a length of 1 to hold the command.
// Use append to add arguments.
func NewProcess() Process {
	return Process{
		Env:    map[string]string{},
		Argv:   []string{},
		Chdir:  "/",
		Stdin:  "/dev/null",
		Stdout: "/dev/null",
		Stderr: "/dev/null",
	}
}

// Exec executes Argv with environment Env and file descriptors
// 1, 2, and 3 open on the files specified in Stdin, Stdout,
// and Stderr. When output files are unspecified or an empty
// string, the file descriptors are left unmodified.
// If argv[0] is stat-able (absolute or relative path), it is used as-is.
// When that fails the PATH searched using exec.LookPath().
func (p *Process) Exec() error {
	var stdin, stdout, stderr *os.File
	var err error

	// Always chdir before doing anything else, making relative paths
	// relative to the provided directory.
	err = os.Chdir(p.Chdir)
	if err != nil {
		log.Fatalf("Could not chdir to '%s': %s\n", p.Chdir, err)
	}

	// Check if it's relative to Chdir or an absolute path, either
	// way it will stat and return not-nil.
	fi, err := os.Stat(p.Argv[0])
	if err != nil {
		fpath, err := exec.LookPath(p.Argv[0])
		if err != nil {
			log.Fatalf("'%s' could not be found in PATH: %s\n", p.Argv[0], err)
		}
		p.Argv[0] = fpath
	}

	// Make sure argv[0] is an actual file before proceeding.
	fi, err = os.Stat(p.Argv[0])
	if err != nil {
		log.Fatalf("BUG: '%s' is not a valid path to a file: %s\n", p.Argv[0], err)
	}
	m := fi.Mode()
	if !m.IsRegular() {
		log.Fatalf("'%s' is not a file!\n", p.Argv[0])
	}

	// If stdin is set, remap it to the file specified on an fd opened read-only.
	if p.Stdin != "" {
		stdin, err = os.OpenFile(p.Stdin, os.O_RDONLY, 0644)
		if err != nil {
			log.Fatalf("Could not open stdin target '%s': %s\n", p.Stdin, err)
		}

		err = syscall.Dup2(int(stdin.Fd()), int(os.Stdin.Fd()))
		if err != nil {
			log.Fatalf("Failed to redirect stdin: %s\n", err)
		}
	}

	// If stdout is set, remap it to the file specified on an fd opened
	// for append and write-only, it will be created if it does not exist.
	if p.Stdout != "" {
		stdout, err = os.OpenFile(p.Stdout, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0644)
		if err != nil {
			log.Fatalf("Could not open stdout target '%s': %s\n", p.Stdout, err)
		}

		err = syscall.Dup2(int(stdout.Fd()), int(os.Stdout.Fd()))
		if err != nil {
			log.Fatalf("Failed to redirect stdout: %s\n", err)
		}
	}

	// Same deal as stdout except if stdin and stdout have the same target, in
	// which case they will share the fd like 2>&1 does.
	if p.Stderr != "" {
		// there is no reason to open the file twice if they're the same file
		if p.Stderr == p.Stdout {
			stderr = stdout // will get dup2'd to the same fd
		} else {
			stderr, err = os.OpenFile(p.Stderr, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0644)
			if err != nil {
				log.Fatalf("Could not open stderr target '%s': %s\n", p.Stderr, err)
			}
		}

		err = syscall.Dup2(int(stderr.Fd()), int(os.Stderr.Fd()))
		if err != nil {
			log.Fatalf("Failed to redirect stderr: %s\n", err)
		}
	}

	return syscall.Exec(p.Argv[0], p.Argv, p.envPairs())
}

// String returns the process settings as a Bourne shell command.
func (p *Process) String() string {
	env := strings.Join(p.envPairs(), " ")
	cmd := strings.Join(p.Argv, " ")
	// cd / && env FOO=BAR cmd -arg1 -arg2 foo < /dev/null 1>/dev/null 2>/dev/null
	return fmt.Sprintf("cd %s && env %s %s <%s 1>%s 2>%s",
		p.Chdir, env, cmd, p.Stdin, p.Stdout, p.Stderr)
}

// envPairs converts the key:value map into an array of key=val which
// is what execve(3P) uses.
func (p *Process) envPairs() []string {
	env := make([]string, len(p.Env))
	i := 0
	for key, value := range p.Env {
		env[i] = fmt.Sprintf("%s=%s", key, value)
		i++
	}
	return env
}
<commit_msg>don't default stdio to /dev/null<commit_after>package sprok

/*
 * Copyright 2014 Albert P. Tobey <atobey@datastax.com> @AlTobey
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import (
	"fmt"
	"log"
	"os"
	"os/exec"
	"strings"
	"syscall"
)

// Process is the configuration for running a process
type Process struct {
	Chdir  string            `json:"chdir"  yaml:"chdir"`  // cd /tmp
	Env    map[string]string `json:"env"    yaml:"env"`    // env FOO=BAR
	Argv   []string          `json:"argv"   yaml:"argv"`   // "/bin/dd" "if=/dev/zero" "count=10"
	Stdin  string            `json:"stdin"  yaml:"stdin"`  // <"/dev/null"
	Stdout string            `json:"stdout" yaml:"stdout"` // >"zero.bin"
	Stderr string            `json:"stderr" yaml:"stderr"` // 2>"errors.log"
}

// NewProcess returns a Process struct with the env map and argv allocated
// and all stdio pointed at /dev/null.
// argv is allocated with a length of 1 to hold the command.
// Use append to add arguments.
func NewProcess() Process {
	return Process{
		Env:    map[string]string{},
		Argv:   []string{},
		Chdir:  "/",
		Stdin:  "",
		Stdout: "",
		Stderr: "",
	}
}

// Exec executes Argv with environment Env and file descriptors
// 1, 2, and 3 open on the files specified in Stdin, Stdout,
// and Stderr. When output files are unspecified or an empty
// string, the file descriptors are left unmodified.
// If argv[0] is stat-able (absolute or relative path), it is used as-is.
// When that fails the PATH searched using exec.LookPath().
func (p *Process) Exec() error {
	var stdin, stdout, stderr *os.File
	var err error

	// Always chdir before doing anything else, making relative paths
	// relative to the provided directory.
	err = os.Chdir(p.Chdir)
	if err != nil {
		log.Fatalf("Could not chdir to '%s': %s\n", p.Chdir, err)
	}

	// Check if it's relative to Chdir or an absolute path, either
	// way it will stat and return not-nil.
	fi, err := os.Stat(p.Argv[0])
	if err != nil {
		fpath, err := exec.LookPath(p.Argv[0])
		if err != nil {
			log.Fatalf("'%s' could not be found in PATH: %s\n", p.Argv[0], err)
		}
		p.Argv[0] = fpath
	}

	// Make sure argv[0] is an actual file before proceeding.
	fi, err = os.Stat(p.Argv[0])
	if err != nil {
		log.Fatalf("BUG: '%s' is not a valid path to a file: %s\n", p.Argv[0], err)
	}
	m := fi.Mode()
	if !m.IsRegular() {
		log.Fatalf("'%s' is not a file!\n", p.Argv[0])
	}

	// If stdin is set, remap it to the file specified on an fd opened read-only.
	if p.Stdin != "" {
		stdin, err = os.OpenFile(p.Stdin, os.O_RDONLY, 0644)
		if err != nil {
			log.Fatalf("Could not open stdin target '%s': %s\n", p.Stdin, err)
		}

		err = syscall.Dup2(int(stdin.Fd()), int(os.Stdin.Fd()))
		if err != nil {
			log.Fatalf("Failed to redirect stdin: %s\n", err)
		}
	}

	// If stdout is set, remap it to the file specified on an fd opened
	// for append and write-only, it will be created if it does not exist.
	if p.Stdout != "" {
		stdout, err = os.OpenFile(p.Stdout, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0644)
		if err != nil {
			log.Fatalf("Could not open stdout target '%s': %s\n", p.Stdout, err)
		}

		err = syscall.Dup2(int(stdout.Fd()), int(os.Stdout.Fd()))
		if err != nil {
			log.Fatalf("Failed to redirect stdout: %s\n", err)
		}
	}

	// Same deal as stdout except if stdin and stdout have the same target, in
	// which case they will share the fd like 2>&1 does.
	if p.Stderr != "" {
		// there is no reason to open the file twice if they're the same file
		if p.Stderr == p.Stdout {
			stderr = stdout // will get dup2'd to the same fd
		} else {
			stderr, err = os.OpenFile(p.Stderr, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0644)
			if err != nil {
				log.Fatalf("Could not open stderr target '%s': %s\n", p.Stderr, err)
			}
		}

		err = syscall.Dup2(int(stderr.Fd()), int(os.Stderr.Fd()))
		if err != nil {
			log.Fatalf("Failed to redirect stderr: %s\n", err)
		}
	}

	return syscall.Exec(p.Argv[0], p.Argv, p.envPairs())
}

// String returns the process settings as a Bourne shell command.
func (p *Process) String() string {
	env := strings.Join(p.envPairs(), " ")
	cmd := strings.Join(p.Argv, " ")
	// cd / && env FOO=BAR cmd -arg1 -arg2 foo < /dev/null 1>/dev/null 2>/dev/null
	return fmt.Sprintf("cd %s && env %s %s <%s 1>%s 2>%s",
		p.Chdir, env, cmd, p.Stdin, p.Stdout, p.Stderr)
}

// envPairs converts the key:value map into an array of key=val which
// is what execve(3P) uses.
func (p *Process) envPairs() []string {
	env := make([]string, len(p.Env))
	i := 0
	for key, value := range p.Env {
		env[i] = fmt.Sprintf("%s=%s", key, value)
		i++
	}
	return env
}
<|endoftext|>


<commit_before>// Licensed under the Apache License, Version 2.0 (the "License")
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//     http://www.apache.org/licenses/LICENSE-2.0
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// Author: Alicja Kwiecinska (kwiecinskaa@google.com) github: alicjakwie

// File generation for Hermes
package hermes

import (
	"fmt"
	"crypto/sha1"
)

type HermesFile struct {
	name string
	contents string
}

// method of HermesFile generates HermesFile.name of the form Hermes_id_checksum where id is an integer & id <= 50
func (file *HermesFile) generateFileName(file_id int, file_checksum string) {
	file.name = file.name :=  fmt.Sprintf("Hermes_%02d_%v", file_id, file_checksum)
}

// method of HermesFile generates HermesFile.contents now a string without any significance in the future a pseudo random byte generator will be used
func (file *HermesFile) generateFileContents(file_id int) {
	file.contents = "jhfvjhdfjhfjjhjhdfvjvcvfjh";
}

// method of HermesFile generates the checksum of the file contents
func (file HermesFile) generateFileChecksum() string {
	file_contents := []byte(file.contents)
	hash := sha1.Sum(file_contents)
	// return checksum in hex notation
	return fmt.Sprintf("%x", hash)
}

// method of HermesFile generates the file takes id as a parameter
func GenerateHermesFile (id int) HermesFile {
	file := HermesFile{}
	file.generateFileContents(id)
	checksum := file.generateFileChecksum()
	file.generateFileName(id, checksum)
	return file
}
<commit_msg>Update file_gen_test.go<commit_after>package hermes

import(
	"testing"
	"strconv"
)

func TestChecksum(t *testing.T){
	global_contents := "jhfvjhdfjhfjjhjhdfvjvcvfjh"
	want := "_68f3caf439065824dcf75651c202e9f7c28ebf07" //expected checksum result
	file := HermesFile{}
	file.contents = global_contents;
	got := file.generateFileChecksum()
	if want != got {
		t.Errorf("generateFileChecksum() failed expected %v got %v", want, got)
	}
}

func TestFileName(t *testing.T){
	file := HermesFile{}
	file_ID := 23;
	fake_checksum :="_abba"
	want :=  "Hermes_"+strconv.Itoa(file_ID)+"_abba" //expected file name result
	file.generateFileName(file_ID, fake_checksum)
	got := file.name
	if got != want {
		t.Errorf("generateFileName(%v, \"abba\") failed expected %v got %v", file_ID, want, got)
	}
	file_ID = 4;
	want = "Hermes_0"+strconv.Itoa(file_ID)+"_abba" //expected file name result
	file.generateFileName(file_ID, fake_checksum)
	got = file.name
	if got != want {
		t.Errorf("generateFileName(%v, \"abba\") failed expected %v got %v", file_ID, want, got)
	}
}
<|endoftext|>


<commit_before>/*
Copyright 2014 Google & the Go AUTHORS

Go AUTHORS are:
See https://code.google.com/p/go/source/browse/AUTHORS

Licensed under the terms of Go itself:
https://code.google.com/p/go/source/browse/LICENSE
*/

// Package gce provides access to Google Compute Engine (GCE) metadata and
// API service accounts.
//
// Most of this package is a wrapper around the GCE metadata service,
// as documented at https://developers.google.com/compute/docs/metadata.
package gce

import (
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"net"
	"net/http"
	"strings"
	"sync"
	"time"
)

// Strings is a list of strings.
type Strings []string

// Contains reports whether v is contained in s.
func (s Strings) Contains(v string) bool {
	for _, sv := range s {
		if v == sv {
			return true
		}
	}
	return false
}

var metaClient = &http.Client{
	Transport: &http.Transport{
		Dial: (&net.Dialer{
			Timeout:   750 * time.Millisecond,
			KeepAlive: 30 * time.Second,
		}).Dial,
		ResponseHeaderTimeout: 750 * time.Millisecond,
	},
}

// MetadataValue returns a value from the metadata service.
// The suffix is appended to "http://metadata/computeMetadata/v1/".
func MetadataValue(suffix string) (string, error) {
	url := "http://metadata/computeMetadata/v1/" + suffix
	req, _ := http.NewRequest("GET", url, nil)
	req.Header.Set("Metadata-Flavor", "Google")
	res, err := metaClient.Do(req)
	if err != nil {
		return "", err
	}
	defer res.Body.Close()
	if res.StatusCode != 200 {
		return "", fmt.Errorf("status code %d trying to fetch %s", res.StatusCode, url)
	}
	all, err := ioutil.ReadAll(res.Body)
	if err != nil {
		return "", err
	}
	return string(all), nil
}

func metaValueTrim(suffix string) (s string, err error) {
	s, err = MetadataValue(suffix)
	s = strings.TrimSpace(s)
	return
}

var (
	projOnce sync.Once
	proj     string
)

// OnGCE reports whether this process is running on Google Compute Engine.
func OnGCE() bool {
	// TODO: maybe something cheaper? this is pretty cheap, though.
	return ProjectID() != ""
}

// ProjectID returns the current instance's project ID string or the empty string
// if not running on GCE.
func ProjectID() string {
	projOnce.Do(setProj)
	return proj
}

// InternalIP returns the instance's primary internal IP address.
func InternalIP() (string, error) {
	return metaValueTrim("instance/network-interfaces/0/ip")
}

// ExternalIP returns the instance's primary external (public) IP address.
func ExternalIP() (string, error) {
	return metaValueTrim("instance/network-interfaces/0/access-configs/0/external-ip")
}

// Hostname returns the instance's hostname. This will probably be of
// the form "INSTANCENAME.c.PROJECT.internal" but that isn't
// guaranteed.
//
// TODO: what is this defined to be? Docs say "The host name of the
// instance."
func Hostname() (string, error) {
	return metaValueTrim("network-interfaces/0/ip")
}

func setProj() {
	proj, _ = MetadataValue("project/project-id")
}

// InstanceTags returns the list of user-defined instance tags,
// assigned when initially creating a GCE instance.
func InstanceTags() (Strings, error) {
	var s Strings
	j, err := MetadataValue("instance/tags")
	if err != nil {
		return nil, err
	}
	if err := json.NewDecoder(strings.NewReader(j)).Decode(&s); err != nil {
		return nil, err
	}
	return s, nil
}

// InstanceID returns the current VM's numeric instance ID.
func InstanceID() (string, error) {
	return metaValueTrim("instance/id")
}

// InstanceAttributes returns the list of user-defined attributes,
// assigned when initially creating a GCE VM instance. The value of an
// attribute can be obtained with InstanceAttributeValue.
func InstanceAttributes() (Strings, error) { return lines("instance/attributes/") }

// ProjectAttributes returns the list of user-defined attributes
// applying to the project as a whole, not just this VM.  The value of
// an attribute can be obtained with ProjectAttributeValue.
func ProjectAttributes() (Strings, error) { return lines("project/attributes/") }

func lines(suffix string) (Strings, error) {
	j, err := MetadataValue(suffix)
	if err != nil {
		return nil, err
	}
	s := strings.Split(strings.TrimSpace(j), "\n")
	for i := range s {
		s[i] = strings.TrimSpace(s[i])
	}
	return Strings(s), nil
}

// InstanceAttributeValue returns the value of the provided VM
// instance attribute.
func InstanceAttributeValue(attr string) (string, error) {
	return MetadataValue("instance/attributes/" + attr)
}

// ProjectAttributeValue returns the value of the provided
// project attribute.
func ProjectAttributeValue(attr string) (string, error) {
	return MetadataValue("project/attributes/" + attr)
}

// Scopes returns the service account scopes for the given account.
// The account may be empty or the string "default" to use the instance's
// main account.
func Scopes(serviceAccount string) (Strings, error) {
	if serviceAccount == "" {
		serviceAccount = "default"
	}
	return lines("instance/service-accounts/" + serviceAccount + "/scopes")
}

// Transport is an HTTP transport that adds authentication headers to
// the request using the default GCE service account and forwards the
// requests to the http package's default transport.
var Transport = NewTransport("default", http.DefaultTransport)

// Client is an http Client that uses the default GCE transport.
var Client = &http.Client{Transport: Transport}

// NewTransport returns a transport that uses the provided GCE
// serviceAccount (optional) to add authentication headers and then
// uses the provided underlying "base" transport.
//
// For more information on Service Accounts, see
// https://developers.google.com/compute/docs/authentication.
func NewTransport(serviceAccount string, base http.RoundTripper) http.RoundTripper {
	if serviceAccount == "" {
		serviceAccount = "default"
	}
	return &transport{base: base, acct: serviceAccount}
}

type transport struct {
	base http.RoundTripper
	acct string

	mu      sync.Mutex
	token   string
	expires time.Time
}

func (t *transport) getToken() (string, error) {
	t.mu.Lock()
	defer t.mu.Unlock()
	if t.token != "" && t.expires.After(time.Now().Add(2*time.Second)) {
		return t.token, nil
	}
	tokenJSON, err := MetadataValue("instance/service-accounts/" + t.acct + "/token")
	if err != nil {
		return "", err
	}
	var token struct {
		AccessToken string `json:"access_token"`
		ExpiresIn   int    `json:"expires_in"`
	}
	if err := json.NewDecoder(strings.NewReader(tokenJSON)).Decode(&token); err != nil {
		return "", err
	}
	if token.AccessToken == "" {
		return "", errors.New("no access token returned")
	}
	t.token = token.AccessToken
	t.expires = time.Now().Add(time.Duration(token.ExpiresIn) * time.Second)
	return t.token, nil
}

func (t *transport) RoundTrip(req *http.Request) (*http.Response, error) {
	token, err := t.getToken()
	if err != nil {
		return nil, err
	}
	req.Header.Add("Authorization", "Bearer "+token)
	return t.base.RoundTrip(req)
}
<commit_msg>update gce library in third_party<commit_after>/*
Copyright 2014 Google & the Go AUTHORS

Go AUTHORS are:
See https://code.google.com/p/go/source/browse/AUTHORS

Licensed under the terms of Go itself:
https://code.google.com/p/go/source/browse/LICENSE
*/

// Package gce provides access to Google Compute Engine (GCE) metadata and
// API service accounts.
//
// Most of this package is a wrapper around the GCE metadata service,
// as documented at https://developers.google.com/compute/docs/metadata.
package gce

import (
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"net"
	"net/http"
	"strings"
	"sync"
	"time"
)

// Strings is a list of strings.
type Strings []string

// Contains reports whether v is contained in s.
func (s Strings) Contains(v string) bool {
	for _, sv := range s {
		if v == sv {
			return true
		}
	}
	return false
}

var metaClient = &http.Client{
	Transport: &http.Transport{
		Dial: (&net.Dialer{
			Timeout:   750 * time.Millisecond,
			KeepAlive: 30 * time.Second,
		}).Dial,
		ResponseHeaderTimeout: 750 * time.Millisecond,
	},
}

// MetadataValue returns a value from the metadata service.
// The suffix is appended to "http://metadata/computeMetadata/v1/".
func MetadataValue(suffix string) (string, error) {
	url := "http://metadata/computeMetadata/v1/" + suffix
	req, _ := http.NewRequest("GET", url, nil)
	req.Header.Set("Metadata-Flavor", "Google")
	res, err := metaClient.Do(req)
	if err != nil {
		return "", err
	}
	defer res.Body.Close()
	if res.StatusCode != 200 {
		return "", fmt.Errorf("status code %d trying to fetch %s", res.StatusCode, url)
	}
	all, err := ioutil.ReadAll(res.Body)
	if err != nil {
		return "", err
	}
	return string(all), nil
}

func metaValueTrim(suffix string) (s string, err error) {
	s, err = MetadataValue(suffix)
	s = strings.TrimSpace(s)
	return
}

type cachedValue struct {
	k    string
	trim bool
	mu   sync.Mutex
	v    string
}

var (
	proj   = &cachedValue{k: "project/project-id", trim: true}
	projID = &cachedValue{k: "project/numeric-project-id", trim: true}
	instID = &cachedValue{k: "instance/id", trim: true}
)

func (c *cachedValue) get() (v string, err error) {
	defer c.mu.Unlock()
	c.mu.Lock()
	if c.v != "" {
		return c.v, nil
	}
	if c.trim {
		v, err = metaValueTrim(c.k)
	} else {
		v, err = MetadataValue(c.k)
	}
	if err == nil {
		c.v = v
	}
	return
}

var onGCE struct {
	sync.Mutex
	set bool
	v   bool
}

// OnGCE reports whether this process is running on Google Compute Engine.
func OnGCE() bool {
	defer onGCE.Unlock()
	onGCE.Lock()
	if onGCE.set {
		return onGCE.v
	}
	onGCE.set = true

	res, err := metaClient.Get("http://metadata.google.internal")
	if err != nil {
		return false
	}
	onGCE.v = res.Header.Get("Metadata-Flavor") == "Google"
	return onGCE.v
}

// ProjectID returns the current instance's project ID string.
func ProjectID() (string, error) { return proj.get() }

// NumericProjectID returns the current instance's numeric project ID.
func NumericProjectID() (string, error) { return projID.get() }

// InternalIP returns the instance's primary internal IP address.
func InternalIP() (string, error) {
	return metaValueTrim("instance/network-interfaces/0/ip")
}

// ExternalIP returns the instance's primary external (public) IP address.
func ExternalIP() (string, error) {
	return metaValueTrim("instance/network-interfaces/0/access-configs/0/external-ip")
}

// Hostname returns the instance's hostname. This will probably be of
// the form "INSTANCENAME.c.PROJECT.internal" but that isn't
// guaranteed.
//
// TODO: what is this defined to be? Docs say "The host name of the
// instance."
func Hostname() (string, error) {
	return metaValueTrim("network-interfaces/0/ip")
}

// InstanceTags returns the list of user-defined instance tags,
// assigned when initially creating a GCE instance.
func InstanceTags() (Strings, error) {
	var s Strings
	j, err := MetadataValue("instance/tags")
	if err != nil {
		return nil, err
	}
	if err := json.NewDecoder(strings.NewReader(j)).Decode(&s); err != nil {
		return nil, err
	}
	return s, nil
}

// InstanceID returns the current VM's numeric instance ID.
func InstanceID() (string, error) {
	return instID.get()
}

// InstanceAttributes returns the list of user-defined attributes,
// assigned when initially creating a GCE VM instance. The value of an
// attribute can be obtained with InstanceAttributeValue.
func InstanceAttributes() (Strings, error) { return lines("instance/attributes/") }

// ProjectAttributes returns the list of user-defined attributes
// applying to the project as a whole, not just this VM.  The value of
// an attribute can be obtained with ProjectAttributeValue.
func ProjectAttributes() (Strings, error) { return lines("project/attributes/") }

func lines(suffix string) (Strings, error) {
	j, err := MetadataValue(suffix)
	if err != nil {
		return nil, err
	}
	s := strings.Split(strings.TrimSpace(j), "\n")
	for i := range s {
		s[i] = strings.TrimSpace(s[i])
	}
	return Strings(s), nil
}

// InstanceAttributeValue returns the value of the provided VM
// instance attribute.
func InstanceAttributeValue(attr string) (string, error) {
	return MetadataValue("instance/attributes/" + attr)
}

// ProjectAttributeValue returns the value of the provided
// project attribute.
func ProjectAttributeValue(attr string) (string, error) {
	return MetadataValue("project/attributes/" + attr)
}

// Scopes returns the service account scopes for the given account.
// The account may be empty or the string "default" to use the instance's
// main account.
func Scopes(serviceAccount string) (Strings, error) {
	if serviceAccount == "" {
		serviceAccount = "default"
	}
	return lines("instance/service-accounts/" + serviceAccount + "/scopes")
}

// Transport is an HTTP transport that adds authentication headers to
// the request using the default GCE service account and forwards the
// requests to the http package's default transport.
var Transport = NewTransport("default", http.DefaultTransport)

// Client is an http Client that uses the default GCE transport.
var Client = &http.Client{Transport: Transport}

// NewTransport returns a transport that uses the provided GCE
// serviceAccount (optional) to add authentication headers and then
// uses the provided underlying "base" transport.
//
// For more information on Service Accounts, see
// https://developers.google.com/compute/docs/authentication.
func NewTransport(serviceAccount string, base http.RoundTripper) http.RoundTripper {
	if serviceAccount == "" {
		serviceAccount = "default"
	}
	return &transport{base: base, acct: serviceAccount}
}

type transport struct {
	base http.RoundTripper
	acct string

	mu      sync.Mutex
	token   string
	expires time.Time
}

func (t *transport) getToken() (string, error) {
	t.mu.Lock()
	defer t.mu.Unlock()
	if t.token != "" && t.expires.After(time.Now().Add(2*time.Second)) {
		return t.token, nil
	}
	tokenJSON, err := MetadataValue("instance/service-accounts/" + t.acct + "/token")
	if err != nil {
		return "", err
	}
	var token struct {
		AccessToken string `json:"access_token"`
		ExpiresIn   int    `json:"expires_in"`
	}
	if err := json.NewDecoder(strings.NewReader(tokenJSON)).Decode(&token); err != nil {
		return "", err
	}
	if token.AccessToken == "" {
		return "", errors.New("no access token returned")
	}
	t.token = token.AccessToken
	t.expires = time.Now().Add(time.Duration(token.ExpiresIn) * time.Second)
	return t.token, nil
}

// cloneRequest returns a clone of the provided *http.Request.
// The clone is a shallow copy of the struct and its Header map.
func cloneRequest(r *http.Request) *http.Request {
	// shallow copy of the struct
	r2 := new(http.Request)
	*r2 = *r
	// deep copy of the Header
	r2.Header = make(http.Header)
	for k, s := range r.Header {
		r2.Header[k] = s
	}
	return r2
}

func (t *transport) RoundTrip(req *http.Request) (*http.Response, error) {
	token, err := t.getToken()
	if err != nil {
		return nil, err
	}

	newReq := cloneRequest(req)
	newReq.Header.Set("Authorization", "Bearer "+token)

	// Needed for some APIs, like Google Cloud Storage?
	// See https://developers.google.com/storage/docs/projects
	// Which despite saying XML, also seems to fix JSON API?
	projID, _ := ProjectID()
	newReq.Header["x-goog-project-id"] = []string{projID}

	return t.base.RoundTrip(newReq)
}
<|endoftext|>