<commit_before>package coreutils

import (
	"errors"
	"io/ioutil"
	"os"
	"os/user"
	"path/filepath"
	"strings"
)

// AbsPath get the absolute directory path, cleaning out any file names, home directory references, etc.
func AbsPath(path string) string {
	user, userGetErr := user.Current()

	if userGetErr == nil { // If we didn't fail getting the current user
		path = strings.Replace(path, "~", user.HomeDir+Separator, -1) // Replace any home directory reference
	}

	path, _ = filepath.Abs(path) // Get the absolute path of path

	var stripLastElement bool

	if file, openErr := os.Open(path); openErr == nil { // Attempt to open the path, to validate if it is a file or directory
		stat, statErr := file.Stat()
		stripLastElement = (statErr == nil) && !stat.IsDir() // Sets stripLastElement to true if stat.IsDir is not true
	} else { // If we failed to open the directory or file
		lastElement := filepath.Base(path)
		stripLastElement = filepath.Ext(lastElement) != "" // If lastElement is either a dotfile or has an extension, assume it is a file
	}

	if stripLastElement {
		path = filepath.Dir(path) + Separator // Strip out the last element and add the separator
	}

	return path
}

// CopyDirectory will copy a directory, sub-directories, and files
func CopyDirectory(sourceDirectory, destinationDirectory string) error {
	var copyError error

	if IsDir(sourceDirectory) { // If sourceDirectory is a valid directory
		os.MkdirAll(destinationDirectory, UniversalFileMode)                     // Make all the needed directories to destinationDirectory
		sourceDirectoryFile, _ := os.Open(sourceDirectory)                       // Get the source directory "file" struct
		directoryContents, directoryReadError := sourceDirectoryFile.Readdir(-1) // Read the directory contents

		if directoryReadError == nil { /// If there was no read error on the directory
			if len(directoryContents) != 0 { // If there is content
				for _, contentItemFileInfo := range directoryContents { // For each FileInfo struct in directoryContents
					contentItemName := contentItemFileInfo.Name() // Get the name of the item
					sourceItemPath := sourceDirectory + "/" + contentItemName
					destinationItemPath := destinationDirectory + "/" + contentItemName

					if contentItemFileInfo.IsDir() { // If this is a directory
						copyError = CopyDirectory(sourceItemPath, destinationItemPath) // Copy this sub-directory and its contents
					} else { // If this is a file
						copyError = CopyFile(sourceItemPath, destinationItemPath) // Copy the directory
					}
				}
			}
		} else { // If there was a read error on the directory
			copyError = errors.New("Unable to read: " + sourceDirectory)
		}
	} else { // If sourceDirectory is not a valid directory
		copyError = errors.New(sourceDirectory + " is not a valid directory.")
	}

	return copyError
}

// CopyFile will copy a file and its relevant permissions
func CopyFile(sourceFile, destinationFile string) error {
	var copyError error

	sourceFileStruct, sourceFileError := os.Open(sourceFile) // Attempt to open the sourceFile

	if sourceFileError == nil { // If there was not an error opening the source file
		sourceFileStats, _ := sourceFileStruct.Stat() // Get the stats of the file

		if sourceFileStats.IsDir() { // If this is actually a directory
			copyError = errors.New(sourceFile + " is a directory. Please use CopyDirectory instead.")
		} else { // If it is indeed a file
			var fileContent []byte
			sourceFileMode := sourceFileStats.Mode() // Get the FileMode of this file
			sourceFileStruct.Close()                 // Close the file

			fileContent, copyError = ioutil.ReadFile(sourceFile) // Read the source file
			copyError = WriteOrUpdateFile(destinationFile, fileContent, sourceFileMode)
		}
	} else { // If the file does not exist
		copyError = errors.New(sourceFile + " does not exist.")
	}

	return copyError
}

// FindClosestFile will return the closest related file to the one provided from a specific path
func FindClosestFile(file string) (string, error) {
	var closestFile string
	var closestFileError error

	directory := filepath.Dir(file) + "/" // Get the directory of the file
	file = filepath.Base(file)            // Change file to only being the base (file name and extension)

	if _, fileReadError := ioutil.ReadFile(directory + file); fileReadError != nil { // If there was a read error for the file
		fileNoCaps := strings.ToLower(file)                            // Set fileNoCaps to the file name with no caps
		fileNoHyphen := strings.Replace(file, "-", "", -1)             // Set fileNoHyphen to the file name with no -
		fileNoCapsNoHyphen := strings.Replace(fileNoCaps, "-", "", -1) // Set fileNoCapsNoHyphen to file name with no caps or -

		fileClosestAttempts := []string{fileNoCaps, fileNoHyphen, fileNoCapsNoHyphen} // Set fileClosestAttempts to an array of the closest attempts strings

		for _, fileAttemptName := range fileClosestAttempts {
			_, fileAttemptReadError := ioutil.ReadFile(directory + fileAttemptName) // Attempt to read this file

			if fileAttemptReadError == nil { // If we successfully found a match
				closestFile = fileAttemptName // Set closest file to this attempt name
				break
			}
		}

		if closestFile == "" { // If no matches were found
			closestFileError = errors.New("No match for " + directory + file + " found.")
		}
	} else { // If there was no read error for the file, meaning the closest file is the file itself
		closestFile = file // Set to original file provided
	}

	return directory + closestFile, closestFileError
}

// GetFiles will get all the files from a directory.
func GetFiles(path string) ([]string, error) {
	var files []string      // Define files as a []string
	var getFilesError error // Define getFilesError as an error

	if IsDir(path) { // If path is a directory
		var directory *os.File
		directory, _ = os.Open(path)
		directoryContents, directoryReadError := directory.Readdir(-1)

		if directoryReadError == nil { // If there was no issue reading the directory contents
			for _, fileInfoStruct := range directoryContents { // For each FileInfo struct in directoryContents
				if !fileInfoStruct.IsDir() { // If the FileInfo indicates the object is not a directory
					files = append(files, path+"/"+fileInfoStruct.Name()) // Add to files the file's name
				}
			}
		} else { // If there was ano issue reading the directory content
			getFilesError = errors.New("Cannot read the contents of " + path)
		}
	} else { // If path is not a directory
		getFilesError = errors.New(path + " is not a directory.")
	}

	return files, getFilesError
}

// GetFilesContains will return any files from a directory containing a particular string
func GetFilesContains(path, substring string) ([]string, error) {
	var files []string                // Define files as the parsed files
	var getFilesError error           // Define getFilesError as an error
	var allDirectoryContents []string // Define allDirectoryContents as the contents returned (if any) from GetFiles

	allDirectoryContents, getFilesError = GetFiles(path) // Get all the files from the path

	if getFilesError == nil { // If there was no issue getting the directory contents
		for _, fileName := range allDirectoryContents { // For each file name in directory contents
			if strings.Contains(filepath.Base(fileName), substring) { // If the file name contains our substring
				files = append(files, fileName) // Append to files
			}
		}
	}

	return files, getFilesError
}

// IsDir checks if the path provided is a directory or not
func IsDir(path string) bool {
	var isDir bool
	fileObject, fileOpenError := os.Open(path) // Open currentDirectory + path

	if fileOpenError == nil { // If there was no error opening the file object
		stat, filePathError := fileObject.Stat() // Get any stats

		if filePathError == nil { // If we got the statistics properly
			isDir = stat.IsDir() // Set isDir to result from stat
		}
	}

	return isDir
}

// WriteOrUpdateFile writes or updates the file contents of the passed file under the leading filepath with the specified sourceFileMode
func WriteOrUpdateFile(file string, fileContent []byte, sourceFileMode os.FileMode) error {
	var writeOrUpdateErr error
	destinationFileDirectories := AbsPath(file)

	if sourceFileMode == 0777 { // If things are global rwe
		sourceFileMode = UniversalFileMode // No, I can't let you do that Dave. (Changes to 744)
	}

	if destinationFileDirectories != "." { // If this is not the same directory as working dir
		writeOrUpdateErr = os.MkdirAll(destinationFileDirectories, sourceFileMode) // Make all the necessary directories
	}

	if writeOrUpdateErr == nil { // If there was no issue creating the directory
		writeOrUpdateErr = ioutil.WriteFile(file, fileContent, sourceFileMode) // Write the file content
	}

	return writeOrUpdateErr
}
<commit_msg>Improve working directory checking and error handling in WriteOrUpdateFile.<commit_after>package coreutils

import (
	"errors"
	"io/ioutil"
	"os"
	"os/user"
	"path/filepath"
	"strings"
)

// AbsPath get the absolute directory path, cleaning out any file names, home directory references, etc.
func AbsPath(path string) string {
	user, userGetErr := user.Current()

	if userGetErr == nil { // If we didn't fail getting the current user
		path = strings.Replace(path, "~", user.HomeDir+Separator, -1) // Replace any home directory reference
	}

	path, _ = filepath.Abs(path) // Get the absolute path of path

	var stripLastElement bool

	if file, openErr := os.Open(path); openErr == nil { // Attempt to open the path, to validate if it is a file or directory
		stat, statErr := file.Stat()
		stripLastElement = (statErr == nil) && !stat.IsDir() // Sets stripLastElement to true if stat.IsDir is not true
	} else { // If we failed to open the directory or file
		lastElement := filepath.Base(path)
		stripLastElement = filepath.Ext(lastElement) != "" // If lastElement is either a dotfile or has an extension, assume it is a file
	}

	if stripLastElement {
		path = filepath.Dir(path) + Separator // Strip out the last element and add the separator
	}

	return path
}

// CopyDirectory will copy a directory, sub-directories, and files
func CopyDirectory(sourceDirectory, destinationDirectory string) error {
	var copyError error

	if IsDir(sourceDirectory) { // If sourceDirectory is a valid directory
		os.MkdirAll(destinationDirectory, UniversalFileMode)                     // Make all the needed directories to destinationDirectory
		sourceDirectoryFile, _ := os.Open(sourceDirectory)                       // Get the source directory "file" struct
		directoryContents, directoryReadError := sourceDirectoryFile.Readdir(-1) // Read the directory contents

		if directoryReadError == nil { /// If there was no read error on the directory
			if len(directoryContents) != 0 { // If there is content
				for _, contentItemFileInfo := range directoryContents { // For each FileInfo struct in directoryContents
					contentItemName := contentItemFileInfo.Name() // Get the name of the item
					sourceItemPath := sourceDirectory + "/" + contentItemName
					destinationItemPath := destinationDirectory + "/" + contentItemName

					if contentItemFileInfo.IsDir() { // If this is a directory
						copyError = CopyDirectory(sourceItemPath, destinationItemPath) // Copy this sub-directory and its contents
					} else { // If this is a file
						copyError = CopyFile(sourceItemPath, destinationItemPath) // Copy the directory
					}
				}
			}
		} else { // If there was a read error on the directory
			copyError = errors.New("Unable to read: " + sourceDirectory)
		}
	} else { // If sourceDirectory is not a valid directory
		copyError = errors.New(sourceDirectory + " is not a valid directory.")
	}

	return copyError
}

// CopyFile will copy a file and its relevant permissions
func CopyFile(sourceFile, destinationFile string) error {
	var copyError error

	sourceFileStruct, sourceFileError := os.Open(sourceFile) // Attempt to open the sourceFile

	if sourceFileError == nil { // If there was not an error opening the source file
		sourceFileStats, _ := sourceFileStruct.Stat() // Get the stats of the file

		if sourceFileStats.IsDir() { // If this is actually a directory
			copyError = errors.New(sourceFile + " is a directory. Please use CopyDirectory instead.")
		} else { // If it is indeed a file
			var fileContent []byte
			sourceFileMode := sourceFileStats.Mode() // Get the FileMode of this file
			sourceFileStruct.Close()                 // Close the file

			fileContent, copyError = ioutil.ReadFile(sourceFile) // Read the source file
			copyError = WriteOrUpdateFile(destinationFile, fileContent, sourceFileMode)
		}
	} else { // If the file does not exist
		copyError = errors.New(sourceFile + " does not exist.")
	}

	return copyError
}

// FindClosestFile will return the closest related file to the one provided from a specific path
func FindClosestFile(file string) (string, error) {
	var closestFile string
	var closestFileError error

	directory := filepath.Dir(file) + "/" // Get the directory of the file
	file = filepath.Base(file)            // Change file to only being the base (file name and extension)

	if _, fileReadError := ioutil.ReadFile(directory + file); fileReadError != nil { // If there was a read error for the file
		fileNoCaps := strings.ToLower(file)                            // Set fileNoCaps to the file name with no caps
		fileNoHyphen := strings.Replace(file, "-", "", -1)             // Set fileNoHyphen to the file name with no -
		fileNoCapsNoHyphen := strings.Replace(fileNoCaps, "-", "", -1) // Set fileNoCapsNoHyphen to file name with no caps or -

		fileClosestAttempts := []string{fileNoCaps, fileNoHyphen, fileNoCapsNoHyphen} // Set fileClosestAttempts to an array of the closest attempts strings

		for _, fileAttemptName := range fileClosestAttempts {
			_, fileAttemptReadError := ioutil.ReadFile(directory + fileAttemptName) // Attempt to read this file

			if fileAttemptReadError == nil { // If we successfully found a match
				closestFile = fileAttemptName // Set closest file to this attempt name
				break
			}
		}

		if closestFile == "" { // If no matches were found
			closestFileError = errors.New("No match for " + directory + file + " found.")
		}
	} else { // If there was no read error for the file, meaning the closest file is the file itself
		closestFile = file // Set to original file provided
	}

	return directory + closestFile, closestFileError
}

// GetFiles will get all the files from a directory.
func GetFiles(path string) ([]string, error) {
	var files []string      // Define files as a []string
	var getFilesError error // Define getFilesError as an error

	if IsDir(path) { // If path is a directory
		var directory *os.File
		directory, _ = os.Open(path)
		directoryContents, directoryReadError := directory.Readdir(-1)

		if directoryReadError == nil { // If there was no issue reading the directory contents
			for _, fileInfoStruct := range directoryContents { // For each FileInfo struct in directoryContents
				if !fileInfoStruct.IsDir() { // If the FileInfo indicates the object is not a directory
					files = append(files, path+"/"+fileInfoStruct.Name()) // Add to files the file's name
				}
			}
		} else { // If there was ano issue reading the directory content
			getFilesError = errors.New("Cannot read the contents of " + path)
		}
	} else { // If path is not a directory
		getFilesError = errors.New(path + " is not a directory.")
	}

	return files, getFilesError
}

// GetFilesContains will return any files from a directory containing a particular string
func GetFilesContains(path, substring string) ([]string, error) {
	var files []string                // Define files as the parsed files
	var getFilesError error           // Define getFilesError as an error
	var allDirectoryContents []string // Define allDirectoryContents as the contents returned (if any) from GetFiles

	allDirectoryContents, getFilesError = GetFiles(path) // Get all the files from the path

	if getFilesError == nil { // If there was no issue getting the directory contents
		for _, fileName := range allDirectoryContents { // For each file name in directory contents
			if strings.Contains(filepath.Base(fileName), substring) { // If the file name contains our substring
				files = append(files, fileName) // Append to files
			}
		}
	}

	return files, getFilesError
}

// IsDir checks if the path provided is a directory or not
func IsDir(path string) bool {
	var isDir bool
	fileObject, fileOpenError := os.Open(path) // Open currentDirectory + path

	if fileOpenError == nil { // If there was no error opening the file object
		stat, filePathError := fileObject.Stat() // Get any stats

		if filePathError == nil { // If we got the statistics properly
			isDir = stat.IsDir() // Set isDir to result from stat
		}
	}

	return isDir
}

// WriteOrUpdateFile writes or updates the file contents of the passed file under the leading filepath with the specified sourceFileMode
func WriteOrUpdateFile(file string, fileContent []byte, sourceFileMode os.FileMode) error {
	currentDirectory, _ := os.Getwd() // Get the working directory
	currentDirectory = AbsPath(currentDirectory) // Get the absolute path of the current working directory

	writeDirectory := AbsPath(file)
	fileName := filepath.Base(file)

	if sourceFileMode == 0777 { // If things are global rwe
		sourceFileMode = UniversalFileMode // No, I can't let you do that Dave. (Changes to 744)
	}

	if currentDirectory != writeDirectory { // If the currentDirectory is not the same directory as the writeDirectory
		if createDirsErr := os.MkdirAll(writeDirectory, sourceFileMode); createDirsErr != nil { // If we failed to make all the directories needed
			return errors.New("Failed to create the path leading up to " + fileName + ": " + writeDirectory)
		}
	}

	writeErr := ioutil.WriteFile(writeDirectory + fileName, fileContent, sourceFileMode)

	if writeErr != nil {
		writeErr = errors.New("Failed to write " + fileName + " in directory " + writeDirectory)
	}

	return writeErr
}
<|endoftext|>


<commit_before>package main

import (
	"os"
	"fmt"
	"strconv"
	"image"
	"image/png"
	"image/color"
	"math"
	"math/rand"
)

// Our functions
func f0(x, y, a, b, c, d, e, f float64) (float64, float64) {
	return x / 2, y / 2
}

func f1(x, y, a, b, c, d, e, f float64) (float64, float64) {
	return (x + 1) / 2, y / 2
}

func f2(x, y, a, b, c, d, e, f float64) (float64, float64) {
	return x / 2, (y + 1) / 2
}

func f3(x, y, a, b, c, d, e, f float64) (float64, float64) {
	return math.Sin(x), math.Sin(y)
}

func f4(x, y, a, b, c, d, e, f float64) (float64, float64) {
	return math.Cos(x), math.Cos(y)
}

func f5(x, y, a, b, c, d, e, f float64) (float64, float64) {
	return math.Cos(a*x + b*y + c), math.Cos(d*x + e*y + f)
}

// get the third-largest value in a matrix. I can probably do this better
func equalize(values int, arr [][]int) [][]int {
	mx := 0
	total := len(arr) * len(arr[0])
	for _, row := range arr {
		for _, v := range row {
			if mx < v {
				mx = v
			}
		}
	}
	hist := make([]int, mx + 1)
	for _, row := range arr {
		for _, v := range row {
			hist[v] += 1
		}
	}
	min := 0
	max := 0
	top := int(float64(total) * .9995)
	bottom := int(float64(total) * .0005)
	count := 0
	// fmt.Printf("Eq", mx, total, top, bottom)
	// fmt.Printf("Hist", hist)
	for i, n := range hist {
	  count += n
	  if count > bottom && min == 0 {
		 min = i
	  }
	  if count > top {
		 max = i
		 break
	  }
   }
	// fmt.Printf("Eq", mx, total, min, max)
   for i := range arr {
	  for j := range arr[i] {
	    if max == min {
	       arr[i][j] = 0
	       continue
	    }
		 if arr[i][j] > max {
			arr[i][j] = max
		 }
		 if arr[i][j] < min {
			arr[i][j] = min
		 }
		 arr[i][j] = values * (arr[i][j] - min) / (max - min)
	  }
   }
   return arr
}

/*
(x, y) = a random point in the biunit square
iterate {
   i = a random integer from 0 to n  1 inclusive
   (x, y) = Fi(x, y)
   plot (x, y) except during the first 20 iterations
}
*/

func flame(width, height, iters int, usefuncs []int) *image.RGBA {
	x := rand.Float64()*2 - 1
	y := rand.Float64()*2 - 1
	mx := make([][]int, height)
	for y := range mx {
		mx[y] = make([]int, width)
		for x := range mx[y] {
			mx[y][x] = 0
		}
	}
	var a, b, c, d, e, f float64
	// these are our parameters
	a, b, c, d, e, f = 1, 2, 1, 1, 4, 5
	// and the F_i s that we'll be using
	allfuncs := []func(float64, float64, float64, float64, float64, float64, float64, float64) (float64, float64){f0, f1, f2, f3, f4, f5}
	funcs := make([]func(float64, float64, float64, float64, float64, float64, float64, float64) (float64, float64), len(usefuncs))
	for i, v := range(usefuncs) {
	  funcs[i] = allfuncs[v]
    }
	for at := 0; at < iters; at++ {
		x, y = funcs[rand.Intn(len(funcs))](x, y, a, b, c, d, e, f)
		// I should probably refactor this
		if x < -1 {
			x = -1
			continue
		}
		if x > 1 {
			x = 1
			continue
		}
		if y < -1 {
			y = -1
			continue
		}
		if y > 1 {
			y = 1
			continue
		}
		//fmt.Println("after", x,y)
		if at < 20 {
			continue
		}
		// refactor, make more readable
		mx[int((y+1)/2*float64(height-1))][int((x+1)/2*float64(width-1))] += 1
	}
	mx = equalize(255, mx)
	m := image.NewRGBA(image.Rect(0, 0, width, height))
	// now write the values to an image, equalized by the 3rd-brightest point
	for x, row := range mx {
		for y, v := range row {
			val := uint8(v)
			m.Set(x, y, color.RGBA{val, val * 100 / 255, val, 255})
		}
	}
	return m
}

func writeit(w, h, i int, use []int) {
	m := flame(w, h, i, use)
	name := "new-lg-"
	for _, z := range use {
	  name += strconv.Itoa(z)
    }
	toimg, _ := os.Create(name + ".png")
	defer toimg.Close()

	png.Encode(toimg, m)
}

func main() {
   w := 1600
   h := 1600
   i := 10000000
   all := 2*2*2*2*2*2
   for z := 2; z < all/2; z++ {
	  n := 0
	  for s := z; s > 0; s >>= 1 {
		 if s % 2 == 1 {
			n += 1
		 }
	  }
	  use := make([]int, n)
	  n = 0
	  a := 0
	  for s := z; s > 0; s >>= 1 {
		 if s % 2 == 1 {
			use[n] = a
			n += 1
		 }
		 a += 1
	  }
	  fmt.Println("Yeah", z, n, use)
	  writeit(w, h, i, use)
   }
}
<commit_msg>more functions<commit_after>package main

import (
  "os"
  "fmt"
  "strconv"
  "image"
  "image/png"
  "image/color"
  "math"
  "math/rand"
)

// Our functions
func f0(x, y, a, b, c, d, e, f float64) (float64, float64) {
  return x / 2, y / 2
}

func f1(x, y, a, b, c, d, e, f float64) (float64, float64) {
  return (x + 1) / 2, y / 2
}

func f2(x, y, a, b, c, d, e, f float64) (float64, float64) {
  return x / 2, (y + 1) / 2
}

func f3(x, y, a, b, c, d, e, f float64) (float64, float64) {
  return math.Sin(x), math.Sin(y)
}

func f4(x, y, a, b, c, d, e, f float64) (float64, float64) {
  return math.Cos(x), math.Cos(y)
}

func f5(x, y, a, b, c, d, e, f float64) (float64, float64) {
  return math.Cos(a*x + b*y + c), math.Cos(d*x + e*y + f)
}

func f6(x, y, a, b, c, d, e, f float64) (float64, float64) {
  return math.Sin(a*x + b*y + c), math.Sin(d*x + e*y + f)
}

func f7(x, y, a, b, c, d, e, f float64) (float64, float64) {
  return math.Sin(a*x + b*y + c), math.Cos(d*x + e*y + f)
}

func f8(x, y, a, b, c, d, e, f float64) (float64, float64) {
  one := a*x+b*y+c
  two := d*x + e*y + f
  return math.Sin(one) * math.Sin(one), math.Sin(two) * math.Sin(two)
}

func f9(x, y, a, b, c, d, e, f float64) (float64, float64) {
  one := a*x+b*y+c
  two := d*x + e*y + f
  return math.Cos(one) * math.Cos(one), math.Cos(two) * math.Cos(two)
}

func f10(x, y, a, b, c, d, e, f float64) (float64, float64) {
  one := a*x+b*y+c
  two := d*x + e*y + f
  return math.Sin(one) * math.Cos(one), math.Sin(two) * math.Cos(two)
}

// get the third-largest value in a matrix. I can probably do this better
func equalize(values int, arr [][]int) [][]int {
  mx := 0
  total := len(arr) * len(arr[0])
  for _, row := range arr {
    for _, v := range row {
      if mx < v {
	mx = v
      }
    }
  }
  hist := make([]int, mx + 1)
  for _, row := range arr {
    for _, v := range row {
      hist[v] += 1
    }
  }
  min := 0
  max := 0
  top := int(float64(total) * .9995)
  bottom := int(float64(total) * .0005)
  count := 0
  // fmt.Printf("Eq", mx, total, top, bottom)
  // fmt.Printf("Hist", hist)
  for i, n := range hist {
    count += n
    if count > bottom && min == 0 {
      min = i
    }
    if count > top {
      max = i
      break
    }
  }
  // fmt.Printf("Eq", mx, total, min, max)
  for i := range arr {
    for j := range arr[i] {
      if max == min {
	arr[i][j] = 0
	continue
      }
      if arr[i][j] > max {
	arr[i][j] = max
      }
      if arr[i][j] < min {
	arr[i][j] = min
      }
      arr[i][j] = values * (arr[i][j] - min) / (max - min)
    }
  }
  return arr
}

/*
  (x, y) = a random point in the biunit square
  iterate {
  i = a random integer from 0 to n  1 inclusive
  (x, y) = Fi(x, y)
  plot (x, y) except during the first 20 iterations
  }
*/

func flame(width, height, iters int, usefuncs []int) *image.RGBA {
  x := rand.Float64()*2 - 1
  y := rand.Float64()*2 - 1
  mx := make([][]int, height)
  for y := range mx {
    mx[y] = make([]int, width)
    for x := range mx[y] {
      mx[y][x] = 0
    }
  }
  var a, b, c, d, e, f float64
  // these are our parameters
  a, b, c, d, e, f = 1, 2, 1, 1, 4, 5
  allfuncs := [11]func(float64, float64, float64, float64, float64, float64, float64, float64) (float64, float64){f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10}
  // and the F_i s that we'll be using
  funcs := make([]func(float64, float64, float64, float64, float64, float64, float64, float64) (float64, float64), len(usefuncs))
  for i, v := range(usefuncs) {
    funcs[i] = allfuncs[v]
  }
  for at := 0; at < iters; at++ {
    x, y = funcs[rand.Intn(len(funcs))](x, y, a, b, c, d, e, f)
    // I should probably refactor this
    if x < -1 {
      x = -1
      continue
    }
    if x > 1 {
      x = 1
      continue
    }
    if y < -1 {
      y = -1
      continue
    }
    if y > 1 {
      y = 1
      continue
    }
    //fmt.Println("after", x,y)
    if at < 20 {
      continue
    }
    // refactor, make more readable
    mx[int((y+1)/2*float64(height-1))][int((x+1)/2*float64(width-1))] += 1
  }
  mx = equalize(255, mx)
  m := image.NewRGBA(image.Rect(0, 0, width, height))
  // now write the values to an image, equalized by the 3rd-brightest point
  for x, row := range mx {
    for y, v := range row {
      val := uint8(v)
      m.Set(x, y, color.RGBA{val, val * 100 / 255, val, 255})
    }
  }
  return m
}

func writeit(w, h, i int, use []int) {
  m := flame(w, h, i, use)
  name := "smallish-"
  num := ""
  for _, z := range use {
    num = strconv.Itoa(z) + num
  }
  toimg, _ := os.Create(name + num + ".png")
  defer toimg.Close()

  png.Encode(toimg, m)
}

func main() {
  w := 400
  h := 400
  i := 1000000
  all := int(math.Pow(2, 11))
  for z := all/4; z < all; z++ {
    n := 0
    for s := z; s > 0; s >>= 1 {
      if s % 2 == 1 {
	n += 1
      }
    }
    use := make([]int, n)
    n = 0
    a := 0
    for s := z; s > 0; s >>= 1 {
      if s % 2 == 1 {
	use[n] = a
	n += 1
      }
      a += 1
    }
    fmt.Println("Yeah", use)
    writeit(w, h, i, use)
  }
}
<|endoftext|>


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

package remote

import (
	"crypto/tls"
	"encoding/json"
	"fmt"
	"net"
	"net/http"
	"net/url"
	"regexp"
	"strconv"

	"github.com/coreos/flannel/Godeps/_workspace/src/github.com/coreos/etcd/pkg/transport"
	"github.com/coreos/flannel/Godeps/_workspace/src/github.com/coreos/go-systemd/activation"
	log "github.com/coreos/flannel/Godeps/_workspace/src/github.com/golang/glog"
	"github.com/coreos/flannel/Godeps/_workspace/src/github.com/gorilla/mux"
	"github.com/coreos/flannel/Godeps/_workspace/src/golang.org/x/net/context"

	"github.com/coreos/flannel/subnet"
)

type handler func(context.Context, subnet.Manager, http.ResponseWriter, *http.Request)

func jsonResponse(w http.ResponseWriter, code int, v interface{}) {
	w.Header().Set("Content-Type", "application/json; charset=utf-8")
	w.WriteHeader(code)
	if err := json.NewEncoder(w).Encode(v); err != nil {
		log.Error("Error JSON encoding response: %v", err)
	}
}

// GET /{network}/config
func handleGetNetworkConfig(ctx context.Context, sm subnet.Manager, w http.ResponseWriter, r *http.Request) {
	defer r.Body.Close()

	network := mux.Vars(r)["network"]
	if network == "_" {
		network = ""
	}

	c, err := sm.GetNetworkConfig(ctx, network)
	if err != nil {
		w.WriteHeader(http.StatusInternalServerError)
		fmt.Fprint(w, err)
		return
	}

	jsonResponse(w, http.StatusOK, c)
}

// POST /{network}/leases
func handleAcquireLease(ctx context.Context, sm subnet.Manager, w http.ResponseWriter, r *http.Request) {
	defer r.Body.Close()

	network := mux.Vars(r)["network"]
	if network == "_" {
		network = ""
	}

	attrs := subnet.LeaseAttrs{}
	if err := json.NewDecoder(r.Body).Decode(&attrs); err != nil {
		w.WriteHeader(http.StatusBadRequest)
		fmt.Fprint(w, "JSON decoding error: ", err)
		return
	}

	lease, err := sm.AcquireLease(ctx, network, &attrs)
	if err != nil {
		w.WriteHeader(http.StatusInternalServerError)
		fmt.Fprint(w, err)
		return
	}

	jsonResponse(w, http.StatusOK, lease)
}

// PUT /{network}/{lease.network}
func handleRenewLease(ctx context.Context, sm subnet.Manager, w http.ResponseWriter, r *http.Request) {
	defer r.Body.Close()

	network := mux.Vars(r)["network"]
	if network == "_" {
		network = ""
	}

	lease := subnet.Lease{}
	if err := json.NewDecoder(r.Body).Decode(&lease); err != nil {
		w.WriteHeader(http.StatusBadRequest)
		fmt.Fprint(w, "JSON decoding error: ", err)
		return
	}

	if err := sm.RenewLease(ctx, network, &lease); err != nil {
		w.WriteHeader(http.StatusInternalServerError)
		fmt.Fprint(w, err)
		return
	}

	jsonResponse(w, http.StatusOK, lease)
}

func getCursor(u *url.URL) interface{} {
	vals, ok := u.Query()["next"]
	if !ok {
		return nil
	}
	return vals[0]
}

// GET /{network}/leases?next=cursor
func handleWatchLeases(ctx context.Context, sm subnet.Manager, w http.ResponseWriter, r *http.Request) {
	defer r.Body.Close()

	network := mux.Vars(r)["network"]
	if network == "_" {
		network = ""
	}

	cursor := getCursor(r.URL)

	wr, err := sm.WatchLeases(ctx, network, cursor)
	if err != nil {
		w.WriteHeader(http.StatusInternalServerError)
		fmt.Fprint(w, err)
		return
	}

	switch wr.Cursor.(type) {
	case string:
	case fmt.Stringer:
		wr.Cursor = wr.Cursor.(fmt.Stringer).String()
	default:
		w.WriteHeader(http.StatusInternalServerError)
		fmt.Fprint(w, fmt.Errorf("internal error: watch cursor is of unknown type"))
		return
	}

	jsonResponse(w, http.StatusOK, wr)
}

// GET /?next=cursor watches
// GET / retrieves all networks
func handleNetworks(ctx context.Context, sm subnet.Manager, w http.ResponseWriter, r *http.Request) {
	defer r.Body.Close()

	cursor := getCursor(r.URL)
	wr, err := sm.WatchNetworks(ctx, cursor)
	if err != nil {
		w.WriteHeader(http.StatusInternalServerError)
		fmt.Fprint(w, err)
		return
	}

	switch wr.Cursor.(type) {
	case string:
	case fmt.Stringer:
		wr.Cursor = wr.Cursor.(fmt.Stringer).String()
	default:
		w.WriteHeader(http.StatusInternalServerError)
		fmt.Fprint(w, fmt.Errorf("internal error: watch cursor is of unknown type"))
		return
	}

	jsonResponse(w, http.StatusOK, wr)
}

func bindHandler(h handler, ctx context.Context, sm subnet.Manager) http.HandlerFunc {
	return func(resp http.ResponseWriter, req *http.Request) {
		h(ctx, sm, resp, req)
	}
}

func fdListener(addr string) (net.Listener, error) {
	fdOffset := 0
	if addr != "" {
		fd, err := strconv.Atoi(addr)
		if err != nil {
			return nil, fmt.Errorf("fd index is not a number")
		}
		fdOffset = fd - 3
	}

	listeners, err := activation.Listeners(false)
	if err != nil {
		return nil, err
	}

	if fdOffset >= len(listeners) {
		return nil, fmt.Errorf("fd %v is out of range (%v)", addr, len(listeners)+3)
	}

	if listeners[fdOffset] == nil {
		return nil, fmt.Errorf("fd %v was not socket activated", addr)
	}

	return listeners[fdOffset], nil
}

func listener(addr, cafile, certfile, keyfile string) (net.Listener, error) {
	rex := regexp.MustCompile("(?:([a-z]+)://)?(.*)")
	groups := rex.FindStringSubmatch(addr)

	var l net.Listener
	var err error

	switch {
	case groups == nil:
		return nil, fmt.Errorf("bad listener address")

	case groups[1] == "", groups[1] == "tcp":
		if l, err = net.Listen("tcp", groups[2]); err != nil {
			return nil, err
		}

	case groups[1] == "fd":
		if l, err = fdListener(groups[2]); err != nil {
			return nil, err
		}

	default:
		return nil, fmt.Errorf("bad listener scheme")
	}

	tlsinfo := transport.TLSInfo{
		CAFile:   cafile,
		CertFile: certfile,
		KeyFile:  keyfile,
	}

	if !tlsinfo.Empty() {
		cfg, err := tlsinfo.ServerConfig()
		if err != nil {
			return nil, err
		}

		l = tls.NewListener(l, cfg)
	}

	return l, nil
}

func RunServer(ctx context.Context, sm subnet.Manager, listenAddr, cafile, certfile, keyfile string) {
	// {network} is always required a the API level but to
	// keep backward compat, special "_" network is allowed
	// that means "no network"

	r := mux.NewRouter()
	r.HandleFunc("/v1/{network}/config", bindHandler(handleGetNetworkConfig, ctx, sm)).Methods("GET")
	r.HandleFunc("/v1/{network}/leases", bindHandler(handleAcquireLease, ctx, sm)).Methods("POST")
	r.HandleFunc("/v1/{network}/leases/{subnet}", bindHandler(handleRenewLease, ctx, sm)).Methods("PUT")
	r.HandleFunc("/v1/{network}/leases", bindHandler(handleWatchLeases, ctx, sm)).Methods("GET")
	r.HandleFunc("/v1/", bindHandler(handleNetworks, ctx, sm)).Methods("GET")

	l, err := listener(listenAddr, cafile, certfile, keyfile)
	if err != nil {
		log.Errorf("Error listening on %v: %v", listenAddr, err)
		return
	}

	c := make(chan error, 1)
	go func() {
		c <- http.Serve(l, httpLogger(r))
	}()

	select {
	case <-ctx.Done():
		l.Close()
		<-c

	case err := <-c:
		log.Errorf("Error serving on %v: %v", listenAddr, err)
	}
}
<commit_msg>Notify systemd service when server is ready to listen<commit_after>// Copyright 2015 CoreOS, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package remote

import (
	"crypto/tls"
	"encoding/json"
	"fmt"
	"net"
	"net/http"
	"net/url"
	"regexp"
	"strconv"

	"github.com/coreos/flannel/Godeps/_workspace/src/github.com/coreos/etcd/pkg/transport"
	"github.com/coreos/flannel/Godeps/_workspace/src/github.com/coreos/go-systemd/activation"
	"github.com/coreos/flannel/Godeps/_workspace/src/github.com/coreos/go-systemd/daemon"
	log "github.com/coreos/flannel/Godeps/_workspace/src/github.com/golang/glog"
	"github.com/coreos/flannel/Godeps/_workspace/src/github.com/gorilla/mux"
	"github.com/coreos/flannel/Godeps/_workspace/src/golang.org/x/net/context"

	"github.com/coreos/flannel/subnet"
)

type handler func(context.Context, subnet.Manager, http.ResponseWriter, *http.Request)

func jsonResponse(w http.ResponseWriter, code int, v interface{}) {
	w.Header().Set("Content-Type", "application/json; charset=utf-8")
	w.WriteHeader(code)
	if err := json.NewEncoder(w).Encode(v); err != nil {
		log.Error("Error JSON encoding response: %v", err)
	}
}

// GET /{network}/config
func handleGetNetworkConfig(ctx context.Context, sm subnet.Manager, w http.ResponseWriter, r *http.Request) {
	defer r.Body.Close()

	network := mux.Vars(r)["network"]
	if network == "_" {
		network = ""
	}

	c, err := sm.GetNetworkConfig(ctx, network)
	if err != nil {
		w.WriteHeader(http.StatusInternalServerError)
		fmt.Fprint(w, err)
		return
	}

	jsonResponse(w, http.StatusOK, c)
}

// POST /{network}/leases
func handleAcquireLease(ctx context.Context, sm subnet.Manager, w http.ResponseWriter, r *http.Request) {
	defer r.Body.Close()

	network := mux.Vars(r)["network"]
	if network == "_" {
		network = ""
	}

	attrs := subnet.LeaseAttrs{}
	if err := json.NewDecoder(r.Body).Decode(&attrs); err != nil {
		w.WriteHeader(http.StatusBadRequest)
		fmt.Fprint(w, "JSON decoding error: ", err)
		return
	}

	lease, err := sm.AcquireLease(ctx, network, &attrs)
	if err != nil {
		w.WriteHeader(http.StatusInternalServerError)
		fmt.Fprint(w, err)
		return
	}

	jsonResponse(w, http.StatusOK, lease)
}

// PUT /{network}/{lease.network}
func handleRenewLease(ctx context.Context, sm subnet.Manager, w http.ResponseWriter, r *http.Request) {
	defer r.Body.Close()

	network := mux.Vars(r)["network"]
	if network == "_" {
		network = ""
	}

	lease := subnet.Lease{}
	if err := json.NewDecoder(r.Body).Decode(&lease); err != nil {
		w.WriteHeader(http.StatusBadRequest)
		fmt.Fprint(w, "JSON decoding error: ", err)
		return
	}

	if err := sm.RenewLease(ctx, network, &lease); err != nil {
		w.WriteHeader(http.StatusInternalServerError)
		fmt.Fprint(w, err)
		return
	}

	jsonResponse(w, http.StatusOK, lease)
}

func getCursor(u *url.URL) interface{} {
	vals, ok := u.Query()["next"]
	if !ok {
		return nil
	}
	return vals[0]
}

// GET /{network}/leases?next=cursor
func handleWatchLeases(ctx context.Context, sm subnet.Manager, w http.ResponseWriter, r *http.Request) {
	defer r.Body.Close()

	network := mux.Vars(r)["network"]
	if network == "_" {
		network = ""
	}

	cursor := getCursor(r.URL)

	wr, err := sm.WatchLeases(ctx, network, cursor)
	if err != nil {
		w.WriteHeader(http.StatusInternalServerError)
		fmt.Fprint(w, err)
		return
	}

	switch wr.Cursor.(type) {
	case string:
	case fmt.Stringer:
		wr.Cursor = wr.Cursor.(fmt.Stringer).String()
	default:
		w.WriteHeader(http.StatusInternalServerError)
		fmt.Fprint(w, fmt.Errorf("internal error: watch cursor is of unknown type"))
		return
	}

	jsonResponse(w, http.StatusOK, wr)
}

// GET /?next=cursor watches
// GET / retrieves all networks
func handleNetworks(ctx context.Context, sm subnet.Manager, w http.ResponseWriter, r *http.Request) {
	defer r.Body.Close()

	cursor := getCursor(r.URL)
	wr, err := sm.WatchNetworks(ctx, cursor)
	if err != nil {
		w.WriteHeader(http.StatusInternalServerError)
		fmt.Fprint(w, err)
		return
	}

	switch wr.Cursor.(type) {
	case string:
	case fmt.Stringer:
		wr.Cursor = wr.Cursor.(fmt.Stringer).String()
	default:
		w.WriteHeader(http.StatusInternalServerError)
		fmt.Fprint(w, fmt.Errorf("internal error: watch cursor is of unknown type"))
		return
	}

	jsonResponse(w, http.StatusOK, wr)
}

func bindHandler(h handler, ctx context.Context, sm subnet.Manager) http.HandlerFunc {
	return func(resp http.ResponseWriter, req *http.Request) {
		h(ctx, sm, resp, req)
	}
}

func fdListener(addr string) (net.Listener, error) {
	fdOffset := 0
	if addr != "" {
		fd, err := strconv.Atoi(addr)
		if err != nil {
			return nil, fmt.Errorf("fd index is not a number")
		}
		fdOffset = fd - 3
	}

	listeners, err := activation.Listeners(false)
	if err != nil {
		return nil, err
	}

	if fdOffset >= len(listeners) {
		return nil, fmt.Errorf("fd %v is out of range (%v)", addr, len(listeners)+3)
	}

	if listeners[fdOffset] == nil {
		return nil, fmt.Errorf("fd %v was not socket activated", addr)
	}

	return listeners[fdOffset], nil
}

func listener(addr, cafile, certfile, keyfile string) (net.Listener, error) {
	rex := regexp.MustCompile("(?:([a-z]+)://)?(.*)")
	groups := rex.FindStringSubmatch(addr)

	var l net.Listener
	var err error

	switch {
	case groups == nil:
		return nil, fmt.Errorf("bad listener address")

	case groups[1] == "", groups[1] == "tcp":
		if l, err = net.Listen("tcp", groups[2]); err != nil {
			return nil, err
		}

	case groups[1] == "fd":
		if l, err = fdListener(groups[2]); err != nil {
			return nil, err
		}

	default:
		return nil, fmt.Errorf("bad listener scheme")
	}

	tlsinfo := transport.TLSInfo{
		CAFile:   cafile,
		CertFile: certfile,
		KeyFile:  keyfile,
	}

	if !tlsinfo.Empty() {
		cfg, err := tlsinfo.ServerConfig()
		if err != nil {
			return nil, err
		}

		l = tls.NewListener(l, cfg)
	}

	return l, nil
}

func RunServer(ctx context.Context, sm subnet.Manager, listenAddr, cafile, certfile, keyfile string) {
	// {network} is always required a the API level but to
	// keep backward compat, special "_" network is allowed
	// that means "no network"

	r := mux.NewRouter()
	r.HandleFunc("/v1/{network}/config", bindHandler(handleGetNetworkConfig, ctx, sm)).Methods("GET")
	r.HandleFunc("/v1/{network}/leases", bindHandler(handleAcquireLease, ctx, sm)).Methods("POST")
	r.HandleFunc("/v1/{network}/leases/{subnet}", bindHandler(handleRenewLease, ctx, sm)).Methods("PUT")
	r.HandleFunc("/v1/{network}/leases", bindHandler(handleWatchLeases, ctx, sm)).Methods("GET")
	r.HandleFunc("/v1/", bindHandler(handleNetworks, ctx, sm)).Methods("GET")

	l, err := listener(listenAddr, cafile, certfile, keyfile)
	if err != nil {
		log.Errorf("Error listening on %v: %v", listenAddr, err)
		return
	}

	c := make(chan error, 1)
	go func() {
		c <- http.Serve(l, httpLogger(r))
	}()

	daemon.SdNotify("READY=1")

	select {
	case <-ctx.Done():
		l.Close()
		<-c

	case err := <-c:
		log.Errorf("Error serving on %v: %v", listenAddr, err)
	}
}
<|endoftext|>


<commit_before>package influxdb

import (
	"bytes"
	"encoding/json"
	"errors"
	"net/http"

	"github.com/influxdb/influxdb/influxql"
)

const (
	MAX_MAP_RESPONSE_SIZE = 1024 * 1024 * 1024
)

// RemoteMapper implements the influxql.Mapper interface. The engine uses the remote mapper
// to pull map results from shards that only exist on other servers in the cluster.
type RemoteMapper struct {
	dataNodes []*DataNode
	resp      *http.Response
	results   chan interface{}
	unmarshal influxql.UnmarshalFunc
	complete  bool

	Call            string   `json:",omitempty"`
	Database        string   `json:",omitempty"`
	MeasurementName string   `json:",omitempty"`
	TMin            int64    `json:",omitempty"`
	TMax            int64    `json:",omitempty"`
	SeriesIDs       []uint64 `json:",omitempty"`
	ShardID         uint64   `json:",omitempty"`
	Filters         []string `json:",omitempty"`
	WhereFields     []*Field `json:",omitempty"`
	SelectFields    []*Field `json:",omitempty"`
	SelectTags      []string `json:",omitempty"`
	Limit           int      `json:",omitempty"`
	Offset          int      `json:",omitempty"`
	Interval        int64    `json:",omitempty"`
	ChunkSize       int      `json:",omitempty"`
}

// Responses get streamed back to the remote mapper from the remote machine that runs a local mapper
type MapResponse struct {
	Err       string `json:",omitempty"`
	Data      []byte
	Completed bool `json:",omitempty"`
}

// Open is a no op, real work is done starting with Being
func (m *RemoteMapper) Open() error { return nil }

// Close the response body
func (m *RemoteMapper) Close() {
	if m.resp != nil && m.resp.Body != nil {
		m.resp.Body.Close()
	}
}

// Begin sends a request to the remote server to start streaming map results
func (m *RemoteMapper) Begin(c *influxql.Call, startingTime int64, chunkSize int) error {
	// get the function for unmarshaling results
	f, err := influxql.InitializeUnmarshaller(c)
	if err != nil {
		return err
	}
	m.unmarshal = f

	if c != nil {
		m.Call = c.String()
	}
	m.ChunkSize = chunkSize
	m.TMin = startingTime

	// send the request to map to the remote server
	b, err := json.Marshal(m)
	if err != nil {
		return err
	}

	// request to start streaming results
	resp, err := http.Post(m.dataNodes[0].URL.String()+"/run_mapper", "application/json", bytes.NewReader(b))
	if err != nil {
		return err
	}
	m.resp = resp

	return nil
}

// NextInterval is part of the mapper interface. In this case we read the next chunk from the remote mapper
func (m *RemoteMapper) NextInterval() (interface{}, error) {
	// just return nil if the mapper has completed its run
	if m.complete {
		return nil, nil
	}

	// read the chunk
	chunk := make([]byte, MAX_MAP_RESPONSE_SIZE, MAX_MAP_RESPONSE_SIZE)
	n, err := m.resp.Body.Read(chunk)
	if err != nil {
		return nil, err
	}
	if n == 0 {
		return nil, nil
	}

	// marshal the response
	mr := &MapResponse{}
	err = json.Unmarshal(chunk[:n], mr)
	if err != nil {
		return nil, err
	}
	if mr.Err != "" {
		return nil, errors.New(mr.Err)
	}

	// if it's a complete message, we've emptied this mapper of all data
	if mr.Completed {
		m.complete = true
		return nil, nil
	}

	// marshal the data that came from the MapFN
	v, err := m.unmarshal(mr.Data)
	if err != nil {
		return nil, err
	}

	return v, nil
}

// CallExpr will parse the Call string into an expression or return nil
func (m *RemoteMapper) CallExpr() (*influxql.Call, error) {
	if m.Call == "" {
		return nil, nil
	}

	c, err := influxql.ParseExpr(m.Call)
	if err != nil {
		return nil, err
	}
	call, ok := c.(*influxql.Call)

	if !ok {
		return nil, errors.New("unable to marshal aggregate call")
	}
	return call, nil
}

// FilterExprs will parse the filter strings and return any expressions. This array
// will be the same size as the SeriesIDs array with each element having a filter (which could be nil)
func (m *RemoteMapper) FilterExprs() []influxql.Expr {
	exprs := make([]influxql.Expr, len(m.SeriesIDs), len(m.SeriesIDs))

	// if filters is empty, they're all nil. if filters has one element, all filters
	// should be set to that. Otherwise marshal each filter
	if len(m.Filters) == 1 {
		f, _ := influxql.ParseExpr(m.Filters[0])
		for i, _ := range exprs {
			exprs[i] = f
		}
	} else if len(m.Filters) > 1 {
		for i, s := range m.Filters {
			f, _ := influxql.ParseExpr(s)
			exprs[i] = f
		}
	}

	return exprs
}

// SetFilters will convert the given arrray of filters into filters that can be marshaled and sent to the remote system
func (m *RemoteMapper) SetFilters(filters []influxql.Expr) {
	l := filters[0]
	allFiltersTheSame := true
	for _, f := range filters {
		if l != f {
			allFiltersTheSame = false
			break
		}
	}

	// we don't need anything if they're all the same and nil
	if l == nil && allFiltersTheSame {
		return
	} else if allFiltersTheSame { // just set one filter element since they're all the same
		m.Filters = []string{l.String()}
		return
	}

	// marshal all of them since there are different ones
	m.Filters = make([]string, len(filters), len(filters))
	for i, f := range filters {
		m.Filters[i] = f.String()
	}
}
<commit_msg>Limix max remote response to 1MB<commit_after>package influxdb

import (
	"bytes"
	"encoding/json"
	"errors"
	"net/http"

	"github.com/influxdb/influxdb/influxql"
)

const (
	MAX_MAP_RESPONSE_SIZE = 1024 * 1024
)

// RemoteMapper implements the influxql.Mapper interface. The engine uses the remote mapper
// to pull map results from shards that only exist on other servers in the cluster.
type RemoteMapper struct {
	dataNodes []*DataNode
	resp      *http.Response
	results   chan interface{}
	unmarshal influxql.UnmarshalFunc
	complete  bool

	Call            string   `json:",omitempty"`
	Database        string   `json:",omitempty"`
	MeasurementName string   `json:",omitempty"`
	TMin            int64    `json:",omitempty"`
	TMax            int64    `json:",omitempty"`
	SeriesIDs       []uint64 `json:",omitempty"`
	ShardID         uint64   `json:",omitempty"`
	Filters         []string `json:",omitempty"`
	WhereFields     []*Field `json:",omitempty"`
	SelectFields    []*Field `json:",omitempty"`
	SelectTags      []string `json:",omitempty"`
	Limit           int      `json:",omitempty"`
	Offset          int      `json:",omitempty"`
	Interval        int64    `json:",omitempty"`
	ChunkSize       int      `json:",omitempty"`
}

// Responses get streamed back to the remote mapper from the remote machine that runs a local mapper
type MapResponse struct {
	Err       string `json:",omitempty"`
	Data      []byte
	Completed bool `json:",omitempty"`
}

// Open is a no op, real work is done starting with Being
func (m *RemoteMapper) Open() error { return nil }

// Close the response body
func (m *RemoteMapper) Close() {
	if m.resp != nil && m.resp.Body != nil {
		m.resp.Body.Close()
	}
}

// Begin sends a request to the remote server to start streaming map results
func (m *RemoteMapper) Begin(c *influxql.Call, startingTime int64, chunkSize int) error {
	// get the function for unmarshaling results
	f, err := influxql.InitializeUnmarshaller(c)
	if err != nil {
		return err
	}
	m.unmarshal = f

	if c != nil {
		m.Call = c.String()
	}
	m.ChunkSize = chunkSize
	m.TMin = startingTime

	// send the request to map to the remote server
	b, err := json.Marshal(m)
	if err != nil {
		return err
	}

	// request to start streaming results
	resp, err := http.Post(m.dataNodes[0].URL.String()+"/run_mapper", "application/json", bytes.NewReader(b))
	if err != nil {
		return err
	}
	m.resp = resp

	return nil
}

// NextInterval is part of the mapper interface. In this case we read the next chunk from the remote mapper
func (m *RemoteMapper) NextInterval() (interface{}, error) {
	// just return nil if the mapper has completed its run
	if m.complete {
		return nil, nil
	}

	// read the chunk
	chunk := make([]byte, MAX_MAP_RESPONSE_SIZE, MAX_MAP_RESPONSE_SIZE)
	n, err := m.resp.Body.Read(chunk)
	if err != nil {
		return nil, err
	}
	if n == 0 {
		return nil, nil
	}

	// marshal the response
	mr := &MapResponse{}
	err = json.Unmarshal(chunk[:n], mr)
	if err != nil {
		return nil, err
	}
	if mr.Err != "" {
		return nil, errors.New(mr.Err)
	}

	// if it's a complete message, we've emptied this mapper of all data
	if mr.Completed {
		m.complete = true
		return nil, nil
	}

	// marshal the data that came from the MapFN
	v, err := m.unmarshal(mr.Data)
	if err != nil {
		return nil, err
	}

	return v, nil
}

// CallExpr will parse the Call string into an expression or return nil
func (m *RemoteMapper) CallExpr() (*influxql.Call, error) {
	if m.Call == "" {
		return nil, nil
	}

	c, err := influxql.ParseExpr(m.Call)
	if err != nil {
		return nil, err
	}
	call, ok := c.(*influxql.Call)

	if !ok {
		return nil, errors.New("unable to marshal aggregate call")
	}
	return call, nil
}

// FilterExprs will parse the filter strings and return any expressions. This array
// will be the same size as the SeriesIDs array with each element having a filter (which could be nil)
func (m *RemoteMapper) FilterExprs() []influxql.Expr {
	exprs := make([]influxql.Expr, len(m.SeriesIDs), len(m.SeriesIDs))

	// if filters is empty, they're all nil. if filters has one element, all filters
	// should be set to that. Otherwise marshal each filter
	if len(m.Filters) == 1 {
		f, _ := influxql.ParseExpr(m.Filters[0])
		for i, _ := range exprs {
			exprs[i] = f
		}
	} else if len(m.Filters) > 1 {
		for i, s := range m.Filters {
			f, _ := influxql.ParseExpr(s)
			exprs[i] = f
		}
	}

	return exprs
}

// SetFilters will convert the given arrray of filters into filters that can be marshaled and sent to the remote system
func (m *RemoteMapper) SetFilters(filters []influxql.Expr) {
	l := filters[0]
	allFiltersTheSame := true
	for _, f := range filters {
		if l != f {
			allFiltersTheSame = false
			break
		}
	}

	// we don't need anything if they're all the same and nil
	if l == nil && allFiltersTheSame {
		return
	} else if allFiltersTheSame { // just set one filter element since they're all the same
		m.Filters = []string{l.String()}
		return
	}

	// marshal all of them since there are different ones
	m.Filters = make([]string, len(filters), len(filters))
	for i, f := range filters {
		m.Filters[i] = f.String()
	}
}
<|endoftext|>


<commit_before>package dynamodb

import (
	"fmt"
	"sync"

	SDK "github.com/aws/aws-sdk-go/service/dynamodb"

	"github.com/evalphobia/aws-sdk-go-wrapper/config"
	"github.com/evalphobia/aws-sdk-go-wrapper/log"
	"github.com/evalphobia/aws-sdk-go-wrapper/private/errors"
	"github.com/evalphobia/aws-sdk-go-wrapper/private/pointers"
)

const (
	serviceName = "DynamoDB"
)

// DynamoDB has DynamoDB client and table list.
type DynamoDB struct {
	client *SDK.DynamoDB

	logger log.Logger
	prefix string

	tablesMu    sync.RWMutex
	tables      map[string]*Table
	writeTables map[string]struct{}
}

// New returns initializesvc *DynamoDB.
func New(conf config.Config) (*DynamoDB, error) {
	sess, err := conf.Session()
	if err != nil {
		return nil, err
	}

	cli := SDK.New(sess)
	svc := &DynamoDB{
		client:      cli,
		logger:      log.DefaultLogger,
		prefix:      conf.DefaultPrefix,
		tables:      make(map[string]*Table),
		writeTables: make(map[string]struct{}),
	}
	return svc, nil
}

// SetLogger sets logger.
func (svc *DynamoDB) SetLogger(logger log.Logger) {
	svc.logger = logger
}

// ===================
// Table Operation
// ===================

// CreateTable new DynamoDB table
func (svc *DynamoDB) CreateTable(design *TableDesign) error {
	if design.HashKey == nil {
		err := fmt.Errorf("error on `CreateTable`; cannot find hashkey in TableDesign;")
		svc.Errorf("%s", err.Error())
		return err
	}

	originalName := design.name
	design.name = svc.prefix + design.name
	in := design.CreateTableInput()
	out, err := svc.client.CreateTable(in)
	if err != nil {
		svc.Errorf("error on `CreateTable` operation; table=%s; error=%s;", design.GetName(), err.Error())
		design.name = originalName
		return err
	}

	design = newTableDesignFromDescription(NewTableDescription(out.TableDescription))
	svc.Infof("success on `CreateTable` operation; table=%s; status=%s;", design.GetName(), design.status)
	return nil
}

// ForceDeleteTable deletes DynamoDB table.
func (svc *DynamoDB) ForceDeleteTable(name string) error {
	tableName := svc.prefix + name
	in := &SDK.DeleteTableInput{
		TableName: pointers.String(tableName),
	}
	out, err := svc.client.DeleteTable(in)
	if err != nil {
		svc.Errorf("error on `DeleteTable` operation; table=%s; error=%s;", tableName, err.Error())
		return err
	}

	svc.tablesMu.Lock()
	delete(svc.tables, name)
	svc.tablesMu.Unlock()

	desc := NewTableDescription(out.TableDescription)
	svc.Infof("success on `DeleteTable` operation; table=%s; status=%s;", tableName, desc.TableStatus)
	return nil
}

// GetTable returns *Table.
func (svc *DynamoDB) GetTable(name string) (*Table, error) {
	if tbl := svc.GetCachedTable(name); tbl != nil {
		return tbl, nil
	}
	// get the table from AWS api.
	t, err := NewTable(svc, name)
	if err != nil {
		return nil, err
	}

	tableName := svc.prefix + name
	svc.tablesMu.Lock()
	svc.tables[tableName] = t
	svc.tablesMu.Unlock()
	return t, nil
}

// GetCachedTable returns *Table from cache.
func (svc *DynamoDB) GetCachedTable(name string) *Table {
	tableName := svc.prefix + name

	// get the table from cache
	svc.tablesMu.RLock()
	defer svc.tablesMu.RUnlock()
	return svc.tables[tableName]
}

// ListTables gets the list of DynamoDB table.
func (svc *DynamoDB) ListTables() ([]string, error) {
	res, err := svc.client.ListTables(&SDK.ListTablesInput{})
	if err != nil {
		return nil, err
	}

	list := make([]string, len(res.TableNames))
	for i, name := range res.TableNames {
		list[i] = *name
	}
	return list, nil
}

// DescribeTable executes `DescribeTable` operation and get table info.
func (svc *DynamoDB) DescribeTable(name string) (TableDescription, error) {
	res, err := svc.client.DescribeTable(&SDK.DescribeTableInput{
		TableName: pointers.String(name),
	})
	switch {
	case err != nil:
		svc.Errorf("error on `DescribeTable` operation; table=%s; error=%s;", name, err.Error())
		return TableDescription{}, err
	case res == nil:
		err := fmt.Errorf("response is nil")
		svc.Errorf("error on `DescribeTable` operation; table=%s; error=%s;", name, err.Error())
		return TableDescription{}, err
	}

	return NewTableDescription(res.Table), nil
}

// ========================
// Query&Command Operation
// ========================

// PutAll executes put operation for all tables in write spool list.
func (svc *DynamoDB) PutAll() error {
	errList := errors.NewErrors(serviceName)
	for name := range svc.writeTables {
		err := svc.tables[name].Put()
		if err != nil {
			errList.Add(err)
			svc.Errorf("error on `Put` operation; table=%s; error=%s;", name, err.Error())
		}
		svc.removeWriteTable(name)
	}

	if errList.HasError() {
		return errList
	}
	return nil
}

// BatchPutAll executes put operation for all tables with batch operations in write spool list.
func (svc *DynamoDB) BatchPutAll() error {
	errList := errors.NewErrors(serviceName)
	for name := range svc.writeTables {
		err := svc.tables[name].BatchPut()
		if err != nil {
			errList.Add(err)
			svc.Errorf("error on `BatchPut` operation; table=%s; error=%s;", name, err.Error())
		}
		svc.removeWriteTable(name)
	}

	if errList.HasError() {
		return errList
	}
	return nil
}

// addWriteTable adds the table to write spool list.
func (svc *DynamoDB) addWriteTable(tbl *Table) {
	svc.tablesMu.Lock()
	defer svc.tablesMu.Unlock()

	name := tbl.nameWithPrefix
	svc.writeTables[name] = struct{}{}
	if _, ok := svc.tables[name]; !ok {
		svc.tables[name] = tbl
	}
}

// removeWriteTable removes the table from write spool list.
func (svc *DynamoDB) removeWriteTable(name string) {
	svc.tablesMu.Lock()
	defer svc.tablesMu.Unlock()
	delete(svc.writeTables, name)
}

// DoQuery executes `Query` operation and get mapped-items.
func (svc *DynamoDB) DoQuery(in *SDK.QueryInput) (*QueryResult, error) {
	req, err := svc.client.Query(in)
	if err != nil {
		svc.Errorf("error on `Query` operation; table=%s; error=%s", *in.TableName, err.Error())
		return nil, err
	}

	res := &QueryResult{
		Items:            req.Items,
		LastEvaluatedKey: req.LastEvaluatedKey,
		Count:            *req.Count,
		ScannedCount:     *req.ScannedCount,
	}
	return res, nil
}

// ========================
// misc
// ========================

// Infof logging information.
func (svc *DynamoDB) Infof(format string, v ...interface{}) {
	svc.logger.Infof(serviceName, format, v...)
}

// Errorf logging error information.
func (svc *DynamoDB) Errorf(format string, v ...interface{}) {
	svc.logger.Errorf(serviceName, format, v...)
}

func newErrors() *errors.Errors {
	return errors.NewErrors(serviceName)
}
<commit_msg>[dynamodb] Add GetClient function (#72)<commit_after>package dynamodb

import (
	"fmt"
	"sync"

	SDK "github.com/aws/aws-sdk-go/service/dynamodb"

	"github.com/evalphobia/aws-sdk-go-wrapper/config"
	"github.com/evalphobia/aws-sdk-go-wrapper/log"
	"github.com/evalphobia/aws-sdk-go-wrapper/private/errors"
	"github.com/evalphobia/aws-sdk-go-wrapper/private/pointers"
)

const (
	serviceName = "DynamoDB"
)

// DynamoDB has DynamoDB client and table list.
type DynamoDB struct {
	client *SDK.DynamoDB

	logger log.Logger
	prefix string

	tablesMu    sync.RWMutex
	tables      map[string]*Table
	writeTables map[string]struct{}
}

// New returns initializesvc *DynamoDB.
func New(conf config.Config) (*DynamoDB, error) {
	sess, err := conf.Session()
	if err != nil {
		return nil, err
	}

	cli := SDK.New(sess)
	svc := &DynamoDB{
		client:      cli,
		logger:      log.DefaultLogger,
		prefix:      conf.DefaultPrefix,
		tables:      make(map[string]*Table),
		writeTables: make(map[string]struct{}),
	}
	return svc, nil
}

// GetClient get client.
func (svc *DynamoDB) GetClient() *SDK.DynamoDB {
	return svc.client
}

// SetLogger sets logger.
func (svc *DynamoDB) SetLogger(logger log.Logger) {
	svc.logger = logger
}

// ===================
// Table Operation
// ===================

// CreateTable new DynamoDB table
func (svc *DynamoDB) CreateTable(design *TableDesign) error {
	if design.HashKey == nil {
		err := fmt.Errorf("error on `CreateTable`; cannot find hashkey in TableDesign;")
		svc.Errorf("%s", err.Error())
		return err
	}

	originalName := design.name
	design.name = svc.prefix + design.name
	in := design.CreateTableInput()
	out, err := svc.client.CreateTable(in)
	if err != nil {
		svc.Errorf("error on `CreateTable` operation; table=%s; error=%s;", design.GetName(), err.Error())
		design.name = originalName
		return err
	}

	design = newTableDesignFromDescription(NewTableDescription(out.TableDescription))
	svc.Infof("success on `CreateTable` operation; table=%s; status=%s;", design.GetName(), design.status)
	return nil
}

// ForceDeleteTable deletes DynamoDB table.
func (svc *DynamoDB) ForceDeleteTable(name string) error {
	tableName := svc.prefix + name
	in := &SDK.DeleteTableInput{
		TableName: pointers.String(tableName),
	}
	out, err := svc.client.DeleteTable(in)
	if err != nil {
		svc.Errorf("error on `DeleteTable` operation; table=%s; error=%s;", tableName, err.Error())
		return err
	}

	svc.tablesMu.Lock()
	delete(svc.tables, name)
	svc.tablesMu.Unlock()

	desc := NewTableDescription(out.TableDescription)
	svc.Infof("success on `DeleteTable` operation; table=%s; status=%s;", tableName, desc.TableStatus)
	return nil
}

// GetTable returns *Table.
func (svc *DynamoDB) GetTable(name string) (*Table, error) {
	if tbl := svc.GetCachedTable(name); tbl != nil {
		return tbl, nil
	}
	// get the table from AWS api.
	t, err := NewTable(svc, name)
	if err != nil {
		return nil, err
	}

	tableName := svc.prefix + name
	svc.tablesMu.Lock()
	svc.tables[tableName] = t
	svc.tablesMu.Unlock()
	return t, nil
}

// GetCachedTable returns *Table from cache.
func (svc *DynamoDB) GetCachedTable(name string) *Table {
	tableName := svc.prefix + name

	// get the table from cache
	svc.tablesMu.RLock()
	defer svc.tablesMu.RUnlock()
	return svc.tables[tableName]
}

// ListTables gets the list of DynamoDB table.
func (svc *DynamoDB) ListTables() ([]string, error) {
	res, err := svc.client.ListTables(&SDK.ListTablesInput{})
	if err != nil {
		return nil, err
	}

	list := make([]string, len(res.TableNames))
	for i, name := range res.TableNames {
		list[i] = *name
	}
	return list, nil
}

// DescribeTable executes `DescribeTable` operation and get table info.
func (svc *DynamoDB) DescribeTable(name string) (TableDescription, error) {
	res, err := svc.client.DescribeTable(&SDK.DescribeTableInput{
		TableName: pointers.String(name),
	})
	switch {
	case err != nil:
		svc.Errorf("error on `DescribeTable` operation; table=%s; error=%s;", name, err.Error())
		return TableDescription{}, err
	case res == nil:
		err := fmt.Errorf("response is nil")
		svc.Errorf("error on `DescribeTable` operation; table=%s; error=%s;", name, err.Error())
		return TableDescription{}, err
	}

	return NewTableDescription(res.Table), nil
}

// ========================
// Query&Command Operation
// ========================

// PutAll executes put operation for all tables in write spool list.
func (svc *DynamoDB) PutAll() error {
	errList := errors.NewErrors(serviceName)
	for name := range svc.writeTables {
		err := svc.tables[name].Put()
		if err != nil {
			errList.Add(err)
			svc.Errorf("error on `Put` operation; table=%s; error=%s;", name, err.Error())
		}
		svc.removeWriteTable(name)
	}

	if errList.HasError() {
		return errList
	}
	return nil
}

// BatchPutAll executes put operation for all tables with batch operations in write spool list.
func (svc *DynamoDB) BatchPutAll() error {
	errList := errors.NewErrors(serviceName)
	for name := range svc.writeTables {
		err := svc.tables[name].BatchPut()
		if err != nil {
			errList.Add(err)
			svc.Errorf("error on `BatchPut` operation; table=%s; error=%s;", name, err.Error())
		}
		svc.removeWriteTable(name)
	}

	if errList.HasError() {
		return errList
	}
	return nil
}

// addWriteTable adds the table to write spool list.
func (svc *DynamoDB) addWriteTable(tbl *Table) {
	svc.tablesMu.Lock()
	defer svc.tablesMu.Unlock()

	name := tbl.nameWithPrefix
	svc.writeTables[name] = struct{}{}
	if _, ok := svc.tables[name]; !ok {
		svc.tables[name] = tbl
	}
}

// removeWriteTable removes the table from write spool list.
func (svc *DynamoDB) removeWriteTable(name string) {
	svc.tablesMu.Lock()
	defer svc.tablesMu.Unlock()
	delete(svc.writeTables, name)
}

// DoQuery executes `Query` operation and get mapped-items.
func (svc *DynamoDB) DoQuery(in *SDK.QueryInput) (*QueryResult, error) {
	req, err := svc.client.Query(in)
	if err != nil {
		svc.Errorf("error on `Query` operation; table=%s; error=%s", *in.TableName, err.Error())
		return nil, err
	}

	res := &QueryResult{
		Items:            req.Items,
		LastEvaluatedKey: req.LastEvaluatedKey,
		Count:            *req.Count,
		ScannedCount:     *req.ScannedCount,
	}
	return res, nil
}

// ========================
// misc
// ========================

// Infof logging information.
func (svc *DynamoDB) Infof(format string, v ...interface{}) {
	svc.logger.Infof(serviceName, format, v...)
}

// Errorf logging error information.
func (svc *DynamoDB) Errorf(format string, v ...interface{}) {
	svc.logger.Errorf(serviceName, format, v...)
}

func newErrors() *errors.Errors {
	return errors.NewErrors(serviceName)
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"

	"github.com/hashicorp/terraform/helper/schema"
	"github.com/whitepages/go-stingray"
)

func resourcePool() *schema.Resource {
	return &schema.Resource{
		Create: resourcePoolCreate,
		Read:   resourcePoolRead,
		Update: resourcePoolUpdate,
		Delete: resourcePoolDelete,

		Schema: map[string]*schema.Schema{
			"name": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
			},

			"bandwidth_class": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				Default:  "",
			},

			"connection_max_connect_time": &schema.Schema{
				Type:     schema.TypeInt,
				Optional: true,
				Default:  4,
			},

			"connection_max_connections_per_node": &schema.Schema{
				Type:     schema.TypeInt,
				Optional: true,
				Default:  0,
			},

			"connection_max_queue_size": &schema.Schema{
				Type:     schema.TypeInt,
				Optional: true,
				Default:  0,
			},

			"connection_max_reply_time": &schema.Schema{
				Type:     schema.TypeInt,
				Optional: true,
				Default:  30,
			},

			"connection_queue_timeout": &schema.Schema{
				Type:     schema.TypeInt,
				Optional: true,
				Default:  10,
			},

			"failure_pool": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				Default:  "",
			},

			"load_balancing_algorithm": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				Default:  "round_robin",
			},

			"load_balancing_priority_enabled": &schema.Schema{
				Type:     schema.TypeBool,
				Optional: true,
				Default:  false,
			},

			"load_balancing_priority_nodes": &schema.Schema{
				Type:     schema.TypeInt,
				Optional: true,
				Default:  1,
			},

			"max_connection_attempts": &schema.Schema{
				Type:     schema.TypeInt,
				Optional: true,
				Default:  0,
			},

			"max_idle_connections_pernode": &schema.Schema{
				Type:     schema.TypeInt,
				Optional: true,
				Default:  50,
			},

			"max_timed_out_connection_attempts": &schema.Schema{
				Type:     schema.TypeInt,
				Optional: true,
				Default:  2,
			},

			"monitors": &schema.Schema{
				Type:     schema.TypeSet,
				Optional: true,
				Elem:     &schema.Schema{Type: schema.TypeString},
				Set:      schema.HashString,
			},

			"node_close_with_rst": &schema.Schema{
				Type:     schema.TypeBool,
				Optional: true,
				Default:  false,
			},

			"node_connection_attempts": &schema.Schema{
				Type:     schema.TypeInt,
				Optional: true,
				Default:  3,
			},

			"nodes": &schema.Schema{
				Type:     schema.TypeSet,
				Optional: true,
				Elem:     &schema.Schema{Type: schema.TypeString},
				Set:      schema.HashString,
			},

			"note": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				Default:  "",
			},

			"passive_monitoring": &schema.Schema{
				Type:     schema.TypeBool,
				Optional: true,
				Default:  true,
			},

			"persistence_class": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				Default:  "",
			},

			"tcp_nagle": &schema.Schema{
				Type:     schema.TypeBool,
				Optional: true,
				Default:  true,
			},

			"transparent": &schema.Schema{
				Type:     schema.TypeBool,
				Optional: true,
				Default:  false,
			},

			"udp_accept_from": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				Default:  "dest_only",
			},

			"udp_accept_from_mask": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				Default:  "",
			},
		},
	}
}

func resourcePoolCreate(d *schema.ResourceData, meta interface{}) error {
	err := resourcePoolSet(d, meta)
	if err != nil {
		return err
	}

	return resourcePoolRead(d, meta)
}

func resourcePoolRead(d *schema.ResourceData, meta interface{}) error {
	c := meta.(*providerConfig).client

	r, resp, err := c.GetPool(d.Get("name").(string))
	if err != nil {
		if resp != nil && resp.StatusCode == 404 {
			// The resource doesn't exist anymore
			d.SetId("")

			return nil
		}

		return fmt.Errorf("Error reading resource: %s", err)
	}

	d.Set("bandwidth_class", string(*r.Basic.BandwidthClass))
	d.Set("connection_max_connect_time", int(*r.Connection.MaxConnectTime))
	d.Set("connection_max_connections_per_node", int(*r.Connection.MaxConnectionsPerNode))
	d.Set("connection_max_queue_size", int(*r.Connection.MaxQueueSize))
	d.Set("connection_max_reply_time", int(*r.Connection.MaxReplyTime))
	d.Set("connection_queue_timeout", int(*r.Connection.QueueTimeout))
	d.Set("failure_pool", string(*r.Basic.FailurePool))
	d.Set("load_balancing_algorithm", string(*r.LoadBalancing.Algorithm))
	d.Set("load_balancing_priority_enabled", bool(*r.LoadBalancing.PriorityEnabled))
	d.Set("load_balancing_priority_nodes", int(*r.LoadBalancing.PriorityNodes))
	d.Set("max_connection_attempts", int(*r.Basic.MaxConnectionAttempts))
	d.Set("max_idle_connections_pernode", int(*r.Basic.MaxIdleConnectionsPerNode))
	d.Set("max_timed_out_connection_attempts", int(*r.Basic.MaxTimedOutConnectionAttempts))
	d.Set("monitors", []string(*r.Basic.Monitors))
	d.Set("node_close_with_rst", bool(*r.Basic.NodeCloseWithRST))
	d.Set("node_connection_attempts", int(*r.Basic.NodeConnectionAttempts))
	d.Set("nodes", nodesTableToNodes(*r.Basic.NodesTable))
	d.Set("note", string(*r.Basic.Note))
	d.Set("passive_monitoring", bool(*r.Basic.PassiveMonitoring))
	d.Set("persistence_class", string(*r.Basic.PersistenceClass))
	d.Set("tcp_nagle", bool(*r.TCP.Nagle))
	d.Set("udp_accept_from", string(*r.UDP.AcceptFrom))
	d.Set("udp_accept_from_mask_class", string(*r.UDP.AcceptFromMask))
	d.Set("transparent", bool(*r.Basic.Transparent))

	return nil
}

func resourcePoolUpdate(d *schema.ResourceData, meta interface{}) error {
	err := resourcePoolSet(d, meta)
	if err != nil {
		return err
	}

	return resourcePoolRead(d, meta)
}

func resourcePoolDelete(d *schema.ResourceData, meta interface{}) error {
	c := meta.(*providerConfig).client
	r := stingray.NewPool(d.Id())

	_, err := c.Delete(r)
	if err != nil {
		return err
	}

	return nil
}

func resourcePoolSet(d *schema.ResourceData, meta interface{}) error {
	c := meta.(*providerConfig).client
	r := stingray.NewPool(d.Get("name").(string))

	setString(&r.Basic.BandwidthClass, d, "bandwidth_class")
	setInt(&r.Connection.MaxConnectTime, d, "connection_max_connect_time")
	setInt(&r.Connection.MaxConnectionsPerNode, d, "connection_max_connections_per_node")
	setInt(&r.Connection.MaxQueueSize, d, "connection_max_queue_size")
	setInt(&r.Connection.MaxReplyTime, d, "connection_max_reply_time")
	setInt(&r.Connection.QueueTimeout, d, "connection_queue_timeout")
	setString(&r.Basic.FailurePool, d, "failure_pool")
	setString(&r.LoadBalancing.Algorithm, d, "load_balancing_algorithm")
	setBool(&r.LoadBalancing.PriorityEnabled, d, "load_balancing_priority_enabled")
	setInt(&r.LoadBalancing.PriorityNodes, d, "load_balancing_priority_nodes")
	setInt(&r.Basic.MaxConnectionAttempts, d, "max_connection_attempts")
	setInt(&r.Basic.MaxIdleConnectionsPerNode, d, "max_idle_connections_pernode")
	setInt(&r.Basic.MaxTimedOutConnectionAttempts, d, "max_timed_out_connection_attempts")
	setStringSet(&r.Basic.Monitors, d, "monitors")
	setBool(&r.Basic.NodeCloseWithRST, d, "node_close_with_rst")
	setInt(&r.Basic.NodeConnectionAttempts, d, "node_connection_attempts")
	setNodesTable(&r.Basic.NodesTable, d, "nodes")
	setString(&r.Basic.Note, d, "note")
	setBool(&r.Basic.PassiveMonitoring, d, "passive_monitoring")
	setString(&r.Basic.PersistenceClass, d, "persistence_class")
	setBool(&r.TCP.Nagle, d, "tcp_nagle")
	setBool(&r.Basic.Transparent, d, "transparent")
	setString(&r.UDP.AcceptFrom, d, "udp_accept_from")
	setString(&r.UDP.AcceptFromMask, d, "udp_accept_from_mask")

	_, err := c.Set(r)
	if err != nil {
		return err
	}

	d.SetId(d.Get("name").(string))

	return nil
}

func setNodesTable(target **stingray.NodesTable, d *schema.ResourceData, key string) {
	if _, ok := d.GetOk(key); ok {
		var nodes []string
		if v := d.Get(key).(*schema.Set); v.Len() > 0 {
			nodes = make([]string, v.Len())
			for i, v := range v.List() {
				nodes[i] = v.(string)
			}
		}
		nodesTable := nodesToNodesTable(nodes)
		*target = &nodesTable
	}
}

func nodesToNodesTable(nodes []string) stingray.NodesTable {
	t := []stingray.Node{}

	for _, v := range nodes {
		t = append(t, stingray.Node{Node: stingray.String(v)})
	}

	return t
}

func nodesTableToNodes(t []stingray.Node) []string {
	nodes := []string{}

	for _, v := range t {
		// A node deleted from the web UI will still exist in
		// the nodes_table, but state and weight will not
		// exist
		if v.State != nil {
			nodes = append(nodes, *v.Node)
		}
	}

	return nodes
}
<commit_msg>stingray_pool: Add dns_autoscale section<commit_after>package main

import (
	"fmt"

	"github.com/hashicorp/terraform/helper/schema"
	"github.com/whitepages/go-stingray"
)

func resourcePool() *schema.Resource {
	return &schema.Resource{
		Create: resourcePoolCreate,
		Read:   resourcePoolRead,
		Update: resourcePoolUpdate,
		Delete: resourcePoolDelete,

		Schema: map[string]*schema.Schema{
			"name": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
			},

			"bandwidth_class": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				Default:  "",
			},

			"connection_max_connect_time": &schema.Schema{
				Type:     schema.TypeInt,
				Optional: true,
				Default:  4,
			},

			"connection_max_connections_per_node": &schema.Schema{
				Type:     schema.TypeInt,
				Optional: true,
				Default:  0,
			},

			"connection_max_queue_size": &schema.Schema{
				Type:     schema.TypeInt,
				Optional: true,
				Default:  0,
			},

			"connection_max_reply_time": &schema.Schema{
				Type:     schema.TypeInt,
				Optional: true,
				Default:  30,
			},

			"connection_queue_timeout": &schema.Schema{
				Type:     schema.TypeInt,
				Optional: true,
				Default:  10,
			},

			"dns_autoscale_enabled": &schema.Schema{
				Type:     schema.TypeBool,
				Optional: true,
				Default:  false,
			},

			"dns_autoscale_hostnames": &schema.Schema{
				Type:     schema.TypeSet,
				Optional: true,
				Elem:     &schema.Schema{Type: schema.TypeString},
				Set:      schema.HashString,
			},

			"dns_autoscale_port": &schema.Schema{
				Type:     schema.TypeInt,
				Optional: true,
				Default:  80,
			},

			"failure_pool": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				Default:  "",
			},

			"load_balancing_algorithm": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				Default:  "round_robin",
			},

			"load_balancing_priority_enabled": &schema.Schema{
				Type:     schema.TypeBool,
				Optional: true,
				Default:  false,
			},

			"load_balancing_priority_nodes": &schema.Schema{
				Type:     schema.TypeInt,
				Optional: true,
				Default:  1,
			},

			"max_connection_attempts": &schema.Schema{
				Type:     schema.TypeInt,
				Optional: true,
				Default:  0,
			},

			"max_idle_connections_pernode": &schema.Schema{
				Type:     schema.TypeInt,
				Optional: true,
				Default:  50,
			},

			"max_timed_out_connection_attempts": &schema.Schema{
				Type:     schema.TypeInt,
				Optional: true,
				Default:  2,
			},

			"monitors": &schema.Schema{
				Type:     schema.TypeSet,
				Optional: true,
				Elem:     &schema.Schema{Type: schema.TypeString},
				Set:      schema.HashString,
			},

			"node_close_with_rst": &schema.Schema{
				Type:     schema.TypeBool,
				Optional: true,
				Default:  false,
			},

			"node_connection_attempts": &schema.Schema{
				Type:     schema.TypeInt,
				Optional: true,
				Default:  3,
			},

			"nodes": &schema.Schema{
				Type:     schema.TypeSet,
				Optional: true,
				Elem:     &schema.Schema{Type: schema.TypeString},
				Set:      schema.HashString,
			},

			"note": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				Default:  "",
			},

			"passive_monitoring": &schema.Schema{
				Type:     schema.TypeBool,
				Optional: true,
				Default:  true,
			},

			"persistence_class": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				Default:  "",
			},

			"tcp_nagle": &schema.Schema{
				Type:     schema.TypeBool,
				Optional: true,
				Default:  true,
			},

			"transparent": &schema.Schema{
				Type:     schema.TypeBool,
				Optional: true,
				Default:  false,
			},

			"udp_accept_from": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				Default:  "dest_only",
			},

			"udp_accept_from_mask": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				Default:  "",
			},
		},
	}
}

func resourcePoolCreate(d *schema.ResourceData, meta interface{}) error {
	err := resourcePoolSet(d, meta)
	if err != nil {
		return err
	}

	return resourcePoolRead(d, meta)
}

func resourcePoolRead(d *schema.ResourceData, meta interface{}) error {
	c := meta.(*providerConfig).client

	r, resp, err := c.GetPool(d.Get("name").(string))
	if err != nil {
		if resp != nil && resp.StatusCode == 404 {
			// The resource doesn't exist anymore
			d.SetId("")

			return nil
		}

		return fmt.Errorf("Error reading resource: %s", err)
	}

	d.Set("bandwidth_class", string(*r.Basic.BandwidthClass))
	d.Set("connection_max_connect_time", int(*r.Connection.MaxConnectTime))
	d.Set("connection_max_connections_per_node", int(*r.Connection.MaxConnectionsPerNode))
	d.Set("connection_max_queue_size", int(*r.Connection.MaxQueueSize))
	d.Set("connection_max_reply_time", int(*r.Connection.MaxReplyTime))
	d.Set("connection_queue_timeout", int(*r.Connection.QueueTimeout))
	d.Set("dns_autoscale_enabled", bool(*r.DNSAutoscale.Enabled))
	d.Set("dns_autoscale_hostnames", []string(*r.DNSAutoscale.Hostnames))
	d.Set("dns_autoscale_port", int(*r.DNSAutoscale.Port))
	d.Set("failure_pool", string(*r.Basic.FailurePool))
	d.Set("load_balancing_algorithm", string(*r.LoadBalancing.Algorithm))
	d.Set("load_balancing_priority_enabled", bool(*r.LoadBalancing.PriorityEnabled))
	d.Set("load_balancing_priority_nodes", int(*r.LoadBalancing.PriorityNodes))
	d.Set("max_connection_attempts", int(*r.Basic.MaxConnectionAttempts))
	d.Set("max_idle_connections_pernode", int(*r.Basic.MaxIdleConnectionsPerNode))
	d.Set("max_timed_out_connection_attempts", int(*r.Basic.MaxTimedOutConnectionAttempts))
	d.Set("monitors", []string(*r.Basic.Monitors))
	d.Set("node_close_with_rst", bool(*r.Basic.NodeCloseWithRST))
	d.Set("node_connection_attempts", int(*r.Basic.NodeConnectionAttempts))
	d.Set("nodes", nodesTableToNodes(*r.Basic.NodesTable))
	d.Set("note", string(*r.Basic.Note))
	d.Set("passive_monitoring", bool(*r.Basic.PassiveMonitoring))
	d.Set("persistence_class", string(*r.Basic.PersistenceClass))
	d.Set("tcp_nagle", bool(*r.TCP.Nagle))
	d.Set("udp_accept_from", string(*r.UDP.AcceptFrom))
	d.Set("udp_accept_from_mask_class", string(*r.UDP.AcceptFromMask))
	d.Set("transparent", bool(*r.Basic.Transparent))

	return nil
}

func resourcePoolUpdate(d *schema.ResourceData, meta interface{}) error {
	err := resourcePoolSet(d, meta)
	if err != nil {
		return err
	}

	return resourcePoolRead(d, meta)
}

func resourcePoolDelete(d *schema.ResourceData, meta interface{}) error {
	c := meta.(*providerConfig).client
	r := stingray.NewPool(d.Id())

	_, err := c.Delete(r)
	if err != nil {
		return err
	}

	return nil
}

func resourcePoolSet(d *schema.ResourceData, meta interface{}) error {
	c := meta.(*providerConfig).client
	r := stingray.NewPool(d.Get("name").(string))

	setString(&r.Basic.BandwidthClass, d, "bandwidth_class")
	setInt(&r.Connection.MaxConnectTime, d, "connection_max_connect_time")
	setInt(&r.Connection.MaxConnectionsPerNode, d, "connection_max_connections_per_node")
	setInt(&r.Connection.MaxQueueSize, d, "connection_max_queue_size")
	setInt(&r.Connection.MaxReplyTime, d, "connection_max_reply_time")
	setInt(&r.Connection.QueueTimeout, d, "connection_queue_timeout")
	setBool(&r.DNSAutoscale.Enabled, d, "dns_autoscale_enabled")
	setStringSet(&r.DNSAutoscale.Hostnames, d, "dns_autoscale_hostnames")
	setInt(&r.DNSAutoscale.Port, d, "dns_autoscale_port")
	setString(&r.Basic.FailurePool, d, "failure_pool")
	setString(&r.LoadBalancing.Algorithm, d, "load_balancing_algorithm")
	setBool(&r.LoadBalancing.PriorityEnabled, d, "load_balancing_priority_enabled")
	setInt(&r.LoadBalancing.PriorityNodes, d, "load_balancing_priority_nodes")
	setInt(&r.Basic.MaxConnectionAttempts, d, "max_connection_attempts")
	setInt(&r.Basic.MaxIdleConnectionsPerNode, d, "max_idle_connections_pernode")
	setInt(&r.Basic.MaxTimedOutConnectionAttempts, d, "max_timed_out_connection_attempts")
	setStringSet(&r.Basic.Monitors, d, "monitors")
	setBool(&r.Basic.NodeCloseWithRST, d, "node_close_with_rst")
	setInt(&r.Basic.NodeConnectionAttempts, d, "node_connection_attempts")
	setNodesTable(&r.Basic.NodesTable, d, "nodes")
	setString(&r.Basic.Note, d, "note")
	setBool(&r.Basic.PassiveMonitoring, d, "passive_monitoring")
	setString(&r.Basic.PersistenceClass, d, "persistence_class")
	setBool(&r.TCP.Nagle, d, "tcp_nagle")
	setBool(&r.Basic.Transparent, d, "transparent")
	setString(&r.UDP.AcceptFrom, d, "udp_accept_from")
	setString(&r.UDP.AcceptFromMask, d, "udp_accept_from_mask")

	_, err := c.Set(r)
	if err != nil {
		return err
	}

	d.SetId(d.Get("name").(string))

	return nil
}

func setNodesTable(target **stingray.NodesTable, d *schema.ResourceData, key string) {
	if _, ok := d.GetOk(key); ok {
		var nodes []string
		if v := d.Get(key).(*schema.Set); v.Len() > 0 {
			nodes = make([]string, v.Len())
			for i, v := range v.List() {
				nodes[i] = v.(string)
			}
		}
		nodesTable := nodesToNodesTable(nodes)
		*target = &nodesTable
	}
}

func nodesToNodesTable(nodes []string) stingray.NodesTable {
	t := []stingray.Node{}

	for _, v := range nodes {
		t = append(t, stingray.Node{Node: stingray.String(v)})
	}

	return t
}

func nodesTableToNodes(t []stingray.Node) []string {
	nodes := []string{}

	for _, v := range t {
		// A node deleted from the web UI will still exist in
		// the nodes_table, but state and weight will not
		// exist
		if v.State != nil {
			nodes = append(nodes, *v.Node)
		}
	}

	return nodes
}
<|endoftext|>


<commit_before>package gopencils

import (
	"fmt"
	"io/ioutil"
	"net/http"
	"net/http/httptest"
	"testing"

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

var (
	testMux *http.ServeMux
	testSrv *httptest.Server
)

func init() {
	testMux = http.NewServeMux()
	testSrv = httptest.NewServer(testMux)
}

type respStruct struct {
	Login   string
	Id      int
	Name    string
	Message string
}
type httpbinResponse struct {
	Args    string
	Headers map[string]string
	Url     string
	Json    map[string]interface{}
}

func TestResouceUrl(t *testing.T) {
	api := Api("https://test-url.com")
	assert.Equal(t, api.Api.BaseUrl.String(), "https://test-url.com",
		"Parsed Url Should match")
	api.SetQuery(map[string]string{"key1": "value1", "key2": "value2"})
	assert.Equal(t, api.QueryValues.Encode(), "key1=value1&key2=value2",
		"Parsed QueryString Url Should match")
	assert.Equal(t, api.Url, "", "Base Url Should be empty")
}

func TestCanUsePathInResourceUrl(t *testing.T) {
	testMux.HandleFunc("/path/to/api/resname/id123",
		func(rw http.ResponseWriter, req *http.Request) {
			fmt.Fprintln(rw, `{"Test":"Okay"}`)
		})

	res := Api(testSrv.URL+"/path/to/api", nil)

	var resp struct {
		Test string
	}

	_, err := res.Res("resname").Id("id123", &resp).Get()
	assert.Nil(t, err, "err should be nil")
	assert.Equal(t, "Okay", resp.Test, "resp shoul be Okay")
}

func TestCanUseAuthForApi(t *testing.T) {
	api := Api("https://test-url.com", &BasicAuth{"username", "password"})
	assert.Equal(t, api.Api.BasicAuth.Username, "username",
		"Username should match")
	assert.Equal(t, api.Api.BasicAuth.Password, "password",
		"Password should match")
}

func TestCanGetResource(t *testing.T) {
	// github stubs
	testMux.HandleFunc("/users/bndr",
		func(rw http.ResponseWriter, req *http.Request) {
			fmt.Fprintln(rw, readJson("_tests/github_bndr.json"))
		})
	testMux.HandleFunc("/users/torvalds",
		func(rw http.ResponseWriter, req *http.Request) {
			fmt.Fprintln(rw, readJson("_tests/github_torvalds.json"))
		})

	api := Api(testSrv.URL)
	// Users endpoint
	users := api.Res("users")

	usernames := []string{"bndr", "torvalds"}

	for _, username := range usernames {
		// Create a new pointer to response Struct
		r := new(respStruct)
		// Get user with id i into the newly created response struct
		_, err := users.Id(username, r).Get()
		if err != nil {
			t.Log("Error Getting Data from Test API\nErr:", err)
		} else {
			assert.Equal(t, r.Message, "", "Error message must be empty")
			assert.Equal(t, r.Login, username, "Username should be equal")
		}
	}
	resp := new(respStruct)
	api.Res("users", resp).Id("bndr").Get()
	assert.Equal(t, resp.Login, "bndr")
	resp2 := new(respStruct)
	api.Res("users").Id("bndr", resp2).Get()
	assert.Equal(t, resp2.Login, "bndr")
}

func TestCanCreateResource(t *testing.T) {
	testMux.HandleFunc("/post",
		func(rw http.ResponseWriter, req *http.Request) {
			assert.Equal(t, req.Method, "POST", "unexpected Method")
			assert.Equal(t, req.URL.Path, "/post", "unexpected Path")
			assert.Equal(t, req.Header.Get("Content-Type"), "application/json",
				"Expected json content type")
			fmt.Fprintln(rw, readJson("_tests/common_response.json"))
		})

	api := Api(testSrv.URL)
	payload := map[string]interface{}{"Key": "Value1"}
	r := new(httpbinResponse)
	api.Res("post", r).Post(payload)
	assert.Equal(t, r.Json["Key"], "Value1", "Payload must match")
}

func TestCanPutResource(t *testing.T) {
	testMux.HandleFunc("/put",
		func(rw http.ResponseWriter, req *http.Request) {
			assert.Equal(t, req.Method, "PUT", "unexpected Method")
			assert.Equal(t, req.URL.Path, "/put", "unexpected Path")
			assert.Equal(t, req.Header.Get("Content-Type"), "application/json",
				"Expected json content type")
			fmt.Fprintln(rw, readJson("_tests/common_response.json"))
		})

	api := Api(testSrv.URL)
	payload := map[string]interface{}{"Key": "Value1"}
	r := new(httpbinResponse)
	api.Res("put", r).Put(payload)
	assert.Equal(t, r.Json["Key"], "Value1", "Payload must match")
}

func TestCanDeleteResource(t *testing.T) {
	testMux.HandleFunc("/delete",
		func(rw http.ResponseWriter, req *http.Request) {
			assert.Equal(t, req.Method, "DELETE", "unexpected Method")
			assert.Equal(t, req.URL.Path, "/delete", "unexpected Path")
			fmt.Fprintln(rw, readJson("_tests/delete_response.json"))
		})

	api := Api(testSrv.URL)
	r := new(httpbinResponse)
	api.Id("delete", r).Delete()
	assert.Equal(t, r.Url, "https://httpbin.org/delete", "Url must match")
}

func TestResource_id(t *testing.T) {
	api := Api("https://test-url.com")
	assert.Equal(t, api.Res("users").Id("test").Url, "users/test",
		"Url should match")
	assert.Equal(t, api.Res("users").Id(123).Res("items").Id(111).Url,
		"users/123/items/111", "Multilevel Url should match")
}

func TestDoNotDecodeBodyOnErr(t *testing.T) {
	tests := []int{
		400, 401, 500, 501,
	}

	// will be changed later
	code := 0
	testMux.HandleFunc("/error",
		func(rw http.ResponseWriter, req *http.Request) {
			rw.WriteHeader(code)
			fmt.Fprintln(rw, readJson("_tests/error.json"))
		})

	api := Api(testSrv.URL)

	for _, code = range tests {
		resp := make(map[string]interface{})
		api.Id("error", &resp).Get()

		assert.Equal(t, resp, map[string]interface{}{},
			fmt.Sprintf("response should be unparsed: %d", code))
	}
}

func readJson(path string) string {
	buf, err := ioutil.ReadFile(path)
	if err != nil {
		panic(err)
	}

	return string(buf)
}
<commit_msg>#11: test that body is really accessible<commit_after>package gopencils

import (
	"fmt"
	"io/ioutil"
	"net/http"
	"net/http/httptest"
	"strings"
	"testing"

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

var (
	testMux *http.ServeMux
	testSrv *httptest.Server
)

func init() {
	testMux = http.NewServeMux()
	testSrv = httptest.NewServer(testMux)
}

type respStruct struct {
	Login   string
	Id      int
	Name    string
	Message string
}
type httpbinResponse struct {
	Args    string
	Headers map[string]string
	Url     string
	Json    map[string]interface{}
}

func TestResouceUrl(t *testing.T) {
	api := Api("https://test-url.com")
	assert.Equal(t, api.Api.BaseUrl.String(), "https://test-url.com",
		"Parsed Url Should match")
	api.SetQuery(map[string]string{"key1": "value1", "key2": "value2"})
	assert.Equal(t, api.QueryValues.Encode(), "key1=value1&key2=value2",
		"Parsed QueryString Url Should match")
	assert.Equal(t, api.Url, "", "Base Url Should be empty")
}

func TestCanUsePathInResourceUrl(t *testing.T) {
	testMux.HandleFunc("/path/to/api/resname/id123",
		func(rw http.ResponseWriter, req *http.Request) {
			fmt.Fprintln(rw, `{"Test":"Okay"}`)
		})

	res := Api(testSrv.URL+"/path/to/api", nil)

	var resp struct {
		Test string
	}

	_, err := res.Res("resname").Id("id123", &resp).Get()
	assert.Nil(t, err, "err should be nil")
	assert.Equal(t, "Okay", resp.Test, "resp shoul be Okay")
}

func TestCanUseAuthForApi(t *testing.T) {
	api := Api("https://test-url.com", &BasicAuth{"username", "password"})
	assert.Equal(t, api.Api.BasicAuth.Username, "username",
		"Username should match")
	assert.Equal(t, api.Api.BasicAuth.Password, "password",
		"Password should match")
}

func TestCanGetResource(t *testing.T) {
	// github stubs
	testMux.HandleFunc("/users/bndr",
		func(rw http.ResponseWriter, req *http.Request) {
			fmt.Fprintln(rw, readJson("_tests/github_bndr.json"))
		})
	testMux.HandleFunc("/users/torvalds",
		func(rw http.ResponseWriter, req *http.Request) {
			fmt.Fprintln(rw, readJson("_tests/github_torvalds.json"))
		})

	api := Api(testSrv.URL)
	// Users endpoint
	users := api.Res("users")

	usernames := []string{"bndr", "torvalds"}

	for _, username := range usernames {
		// Create a new pointer to response Struct
		r := new(respStruct)
		// Get user with id i into the newly created response struct
		_, err := users.Id(username, r).Get()
		if err != nil {
			t.Log("Error Getting Data from Test API\nErr:", err)
		} else {
			assert.Equal(t, r.Message, "", "Error message must be empty")
			assert.Equal(t, r.Login, username, "Username should be equal")
		}
	}
	resp := new(respStruct)
	api.Res("users", resp).Id("bndr").Get()
	assert.Equal(t, resp.Login, "bndr")
	resp2 := new(respStruct)
	api.Res("users").Id("bndr", resp2).Get()
	assert.Equal(t, resp2.Login, "bndr")
}

func TestCanCreateResource(t *testing.T) {
	testMux.HandleFunc("/post",
		func(rw http.ResponseWriter, req *http.Request) {
			assert.Equal(t, req.Method, "POST", "unexpected Method")
			assert.Equal(t, req.URL.Path, "/post", "unexpected Path")
			assert.Equal(t, req.Header.Get("Content-Type"), "application/json",
				"Expected json content type")
			fmt.Fprintln(rw, readJson("_tests/common_response.json"))
		})

	api := Api(testSrv.URL)
	payload := map[string]interface{}{"Key": "Value1"}
	r := new(httpbinResponse)
	api.Res("post", r).Post(payload)
	assert.Equal(t, r.Json["Key"], "Value1", "Payload must match")
}

func TestCanPutResource(t *testing.T) {
	testMux.HandleFunc("/put",
		func(rw http.ResponseWriter, req *http.Request) {
			assert.Equal(t, req.Method, "PUT", "unexpected Method")
			assert.Equal(t, req.URL.Path, "/put", "unexpected Path")
			assert.Equal(t, req.Header.Get("Content-Type"), "application/json",
				"Expected json content type")
			fmt.Fprintln(rw, readJson("_tests/common_response.json"))
		})

	api := Api(testSrv.URL)
	payload := map[string]interface{}{"Key": "Value1"}
	r := new(httpbinResponse)
	api.Res("put", r).Put(payload)
	assert.Equal(t, r.Json["Key"], "Value1", "Payload must match")
}

func TestCanDeleteResource(t *testing.T) {
	testMux.HandleFunc("/delete",
		func(rw http.ResponseWriter, req *http.Request) {
			assert.Equal(t, req.Method, "DELETE", "unexpected Method")
			assert.Equal(t, req.URL.Path, "/delete", "unexpected Path")
			fmt.Fprintln(rw, readJson("_tests/delete_response.json"))
		})

	api := Api(testSrv.URL)
	r := new(httpbinResponse)
	api.Id("delete", r).Delete()
	assert.Equal(t, r.Url, "https://httpbin.org/delete", "Url must match")
}

func TestResource_id(t *testing.T) {
	api := Api("https://test-url.com")
	assert.Equal(t, api.Res("users").Id("test").Url, "users/test",
		"Url should match")
	assert.Equal(t, api.Res("users").Id(123).Res("items").Id(111).Url,
		"users/123/items/111", "Multilevel Url should match")
}

func TestDoNotDecodeBodyOnErr(t *testing.T) {
	tests := []int{
		400, 401, 500, 501,
	}

	actualData := strings.TrimSpace(readJson("_tests/error.json"))

	// will be changed later
	code := 0
	testMux.HandleFunc("/error",
		func(rw http.ResponseWriter, req *http.Request) {
			rw.WriteHeader(code)
			fmt.Fprintln(rw, actualData)
		})

	api := Api(testSrv.URL)

	for _, code = range tests {
		resp := make(map[string]interface{})
		r, err := api.Id("error", &resp).Get()
		if err != nil {
			t.Fatal(err)
		}

		assert.Equal(t, map[string]interface{}{}, resp,
			fmt.Sprintf("response should be unparsed: %d", code))

		respData, err := ioutil.ReadAll(r.Raw.Body)
		if err != nil {
			t.Fatal(err)
		}

		assert.Equal(t, actualData, strings.TrimSpace(string(respData)),
			fmt.Sprintf("response body is not accessible: %d", code))
	}
}

func readJson(path string) string {
	buf, err := ioutil.ReadFile(path)
	if err != nil {
		panic(err)
	}

	return string(buf)
}
<|endoftext|>