<commit_before>// Copyright (c) 2015 Marin Atanasov Nikolov <dnaeon@gmail.com>
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
// 1. Redistributions of source code must retain the above copyright
//    notice, this list of conditions and the following disclaimer
//    in this position and unchanged.
// 2. Redistributions in binary form must reproduce the above copyright
//    notice, this list of conditions and the following disclaimer in the
//    documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
// OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
// IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
// NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
// THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

package recorder_test

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

	"github.com/dnaeon/go-vcr/recorder"
)

type recordTest struct {
	method string
	body   io.Reader
	out    string
}

func (test recordTest) perform(t *testing.T, url string, r *recorder.Recorder) {
	// Create an HTTP client and inject our transport
	client := &http.Client{
		Transport: r.Transport, // Inject our transport!
	}

	req, err := http.NewRequest(test.method, url, test.body)
	if err != nil {
		t.Fatal(err)
	}
	resp, err := client.Do(req)
	if err != nil {
		t.Fatal(err)
	}
	defer resp.Body.Close()

	content, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		t.Fatal(err)
	}
	if strings.TrimSpace(string(content)) != test.out {
		t.Fatalf("got:\t%s\n\twant:\t%s", string(content), string(test.out))
	}
}

func TestRecord(t *testing.T) {
	runID := time.Now().Format(time.RFC3339Nano)
	tests := []recordTest{
		{
			method: "GET",
			out:    "GET " + runID,
		},
		{
			method: "POST",
			body:   strings.NewReader("post body"),
			out:    "POST " + runID + "\npost body",
		},
	}

	dir, err := ioutil.TempDir("", "")
	if err != nil {
		t.Fatal(err)
	}
	cassPath := path.Join(dir, "record_test")
	var serverURL string
	serverUp := false

	func() {
		// Start our recorder
		r, err := recorder.New(cassPath)
		if err != nil {
			t.Fatal(err)
		}
		defer r.Stop() // Make sure recorder is stopped once done with it

		server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			fmt.Fprintf(w, "%s %s", r.Method, runID)
			if r.Body != nil {
				defer r.Body.Close()
				fmt.Fprintln(w)
				io.Copy(w, r.Body)
			}
		}))
		serverUp = true
		defer func() {
			server.Close()
			t.Log("server shut down")
			serverUp = false
		}()
		serverURL = server.URL

		t.Log("recording")
		for _, test := range tests {
			test.perform(t, serverURL, r)
		}
	}()

	if serverUp {
		t.Fatal("expected server to have shut down")
	}

	// Re-run without the actual server
	func() {
		r, err := recorder.New(cassPath)
		if err != nil {
			t.Fatal(err)
		}
		defer r.Stop()

		t.Log("replaying")
		for _, test := range tests {
			test.perform(t, serverURL, r)
		}
	}()
}
<commit_msg>Remove unnecessary closure<commit_after>// Copyright (c) 2015 Marin Atanasov Nikolov <dnaeon@gmail.com>
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
// 1. Redistributions of source code must retain the above copyright
//    notice, this list of conditions and the following disclaimer
//    in this position and unchanged.
// 2. Redistributions in binary form must reproduce the above copyright
//    notice, this list of conditions and the following disclaimer in the
//    documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
// OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
// IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
// NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
// THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

package recorder_test

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

	"github.com/dnaeon/go-vcr/recorder"
)

type recordTest struct {
	method string
	body   io.Reader
	out    string
}

func (test recordTest) perform(t *testing.T, url string, r *recorder.Recorder) {
	// Create an HTTP client and inject our transport
	client := &http.Client{
		Transport: r.Transport, // Inject our transport!
	}

	req, err := http.NewRequest(test.method, url, test.body)
	if err != nil {
		t.Fatal(err)
	}
	resp, err := client.Do(req)
	if err != nil {
		t.Fatal(err)
	}
	defer resp.Body.Close()

	content, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		t.Fatal(err)
	}
	if strings.TrimSpace(string(content)) != test.out {
		t.Fatalf("got:\t%s\n\twant:\t%s", string(content), string(test.out))
	}
}

func TestRecord(t *testing.T) {
	runID := time.Now().Format(time.RFC3339Nano)
	tests := []recordTest{
		{
			method: "GET",
			out:    "GET " + runID,
		},
		{
			method: "POST",
			body:   strings.NewReader("post body"),
			out:    "POST " + runID + "\npost body",
		},
	}

	dir, err := ioutil.TempDir("", "")
	if err != nil {
		t.Fatal(err)
	}
	cassPath := path.Join(dir, "record_test")
	var serverURL string
	serverUp := false

	func() {
		// Start our recorder
		r, err := recorder.New(cassPath)
		if err != nil {
			t.Fatal(err)
		}
		defer r.Stop() // Make sure recorder is stopped once done with it

		server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			fmt.Fprintf(w, "%s %s", r.Method, runID)
			if r.Body != nil {
				defer r.Body.Close()
				fmt.Fprintln(w)
				io.Copy(w, r.Body)
			}
		}))
		serverUp = true
		defer func() {
			server.Close()
			t.Log("server shut down")
			serverUp = false
		}()
		serverURL = server.URL

		t.Log("recording")
		for _, test := range tests {
			test.perform(t, serverURL, r)
		}
	}()

	if serverUp {
		t.Fatal("expected server to have shut down")
	}

	// Re-run without the actual server
	r, err := recorder.New(cassPath)
	if err != nil {
		t.Fatal(err)
	}
	defer r.Stop()

	t.Log("replaying")
	for _, test := range tests {
		test.perform(t, serverURL, r)
	}
}
<|endoftext|>


<commit_before>/*
 * This file is a part of linuxdeploy - tool for
 * creating standalone applications for Linux
 *
 * Copyright (C) 2017 Taras Kushnir <kushnirTV@gmail.com>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the MIT License.

 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 */

package main

import (
  "log"
  "os/exec"
  "path/filepath"
  "strings"
  "os"
  "fmt"
)

func (ad *AppDeployer) processLibTasks() {
  if _, err := exec.LookPath("ldd"); err != nil {
    log.Fatal("ldd cannot be found!")
  }

  for request := range ad.libsChannel {
    ad.processLibTask(request)
    ad.waitGroup.Done()
  }

  log.Println("Libraries processing finished")
}

func (ad *AppDeployer) processLibTask(request *DeployRequest) {
  libpath := request.FullPath()

  if ad.canSkipLibrary(libpath) {
    log.Printf("Skipping library: %v", libpath)
    return
  }

  log.Printf("Processing library: %v", libpath)

  dependencies, err := ad.findLddDependencies(request.Basename(), libpath)
  if err != nil {
    log.Printf("Error while dependency check for %v: %v", libpath, err)
    return
  }

  ad.accountLibrary(libpath)

  ad.waitGroup.Add(1)
  go func(copyRequest *DeployRequest) {
    ad.copyChannel <- copyRequest
  }(request)

  flags := request.flags
  // fix rpath of all the libs
  //flags.ClearFlag(FIX_RPATH_FLAG)
  flags.AddFlag(LDD_DEPENDENCY_FLAG)

  for _, dependPath := range dependencies {
    if !ad.isLibraryDeployed(dependPath) {
      ad.addLibTask("", dependPath, "lib", flags)
    }
  }
}

func (ad *AppDeployer) canSkipLibrary(libpath string) bool {
  canSkip := false
  if strings.HasPrefix(libpath, "linux-vdso.so") {
    canSkip = true
  } else if ad.isLibraryDeployed(libpath) {
    canSkip = true
  }

  return canSkip
}

func (ad *AppDeployer) findLddDependencies(basename, filepath string) ([]string, error) {
  log.Printf("Inspecting %v", filepath)

  out, err := exec.Command("ldd", filepath).Output()
  if err != nil { return nil, err }

  dependencies := make([]string, 0, 10)

  output := string(out)
  lines := strings.Split(output, "\n")
  for _, line := range lines {
    line = strings.TrimSpace(line)
    libname, libpath, err := parseLddOutputLine(line)

    if err != nil {
      log.Printf("Cannot parse ldd line: %v", line)
      continue
    }

    if len(libpath) == 0 {
      libpath = ad.resolveLibrary(libname)
    }

    log.Printf("[%v]: depends on %v from ldd [%v]", basename, libpath, line)
    dependencies = append(dependencies, libpath)
  }

  return dependencies, nil
}

func (ad *AppDeployer) addAdditionalLibPath(libpath string) {
  log.Printf("Adding addition libpath: %v", libpath)
  foundPath := libpath
  var err error

  if !filepath.IsAbs(foundPath) {
    if foundPath, err = filepath.Abs(foundPath); err == nil {
      log.Printf("Trying to resolve libpath to: %v", foundPath)

      if _, err = os.Stat(foundPath); os.IsNotExist(err) {
        exeDir := filepath.Dir(ad.targetExePath)
        foundPath = filepath.Join(exeDir, libpath)
        log.Printf("Trying to resolve libpath to: %v", foundPath)
      }
    }
  }

  if _, err := os.Stat(foundPath); os.IsNotExist(err) {
    log.Printf("Cannot find library path: %v", foundPath)
    return
  }

  log.Printf("Resolved additional libpath to: %v", foundPath)
  ad.additionalLibPaths = append(ad.additionalLibPaths, foundPath)
}

func (ad *AppDeployer) resolveLibrary(libname string) (foundPath string) {
  foundPath = libname

  for _, extraLibPath := range ad.additionalLibPaths {
    possiblePath := filepath.Join(extraLibPath, libname)

    if _, err := os.Stat(possiblePath); err == nil {
      foundPath = possiblePath
      break
    }
  }

  log.Printf("Resolving library %v to %v", libname, foundPath)
  return foundPath
}

func (ad *AppDeployer) processCopyTasks() {
  copiedFiles := make(map[string]bool)

  for copyRequest := range ad.copyChannel {
    ad.processCopyTask(copiedFiles, copyRequest)
    ad.waitGroup.Done()
  }

  log.Printf("Copy tasks processing finished")
}

func (ad *AppDeployer) processCopyTask(copiedFiles map[string]bool, copyRequest *DeployRequest) {
  var destinationPath, destinationPrefix string

  if len(copyRequest.sourceRoot) == 0 {
    // absolute path
    destinationPrefix = copyRequest.targetPath
  } else {
    destinationPrefix = filepath.Join(copyRequest.targetPath, copyRequest.SourceDir())
  }

  sourcePath := copyRequest.FullPath()
  destinationPath = filepath.Join(ad.destinationRoot, destinationPrefix, filepath.Base(copyRequest.sourcePath))

  if _, ok := copiedFiles[destinationPath]; ok {
    log.Printf("File %v has already been copied", sourcePath)
    return
  }

  ensureDirExists(destinationPath)
  err := copyFile(sourcePath, destinationPath)

  if err != nil {
    log.Printf("Error while copying [%v] to [%v]: %v", sourcePath, destinationPath, err)
    return
  }

  copiedFiles[destinationPath] = true
  log.Printf("Copied [%v] to [%v]", sourcePath, destinationPath)
  isQtLibrary := false

  if copyRequest.IsLddDependency() {
    libraryBasename := filepath.Base(destinationPath)
    libname := strings.ToLower(libraryBasename)

    if strings.HasPrefix(libname, "libqt") {
      ad.addQtLibTask(destinationPath)
      isQtLibrary = true
    }
  }

  if !isQtLibrary && copyRequest.RequiresRPathFix() {
    ad.addFixRPathTask(destinationPath)
  }
}

func (ad *AppDeployer) processFixRPathTasks() {
  patchelfAvailable := true

  if _, err := exec.LookPath("patchelf"); err != nil {
    log.Printf("Patchelf cannot be found!")
    patchelfAvailable = false
  }

  destinationRoot := ad.destinationRoot
  fixedFiles := make(map[string]bool)

  for fullpath := range ad.rpathChannel {
    if patchelfAvailable {
      if _, ok := fixedFiles[fullpath]; !ok {
        fixRPath(fullpath, destinationRoot)
        fixedFiles[fullpath] = true
      } else {
        log.Printf("RPATH has been already fixed for %v", fullpath)
      }
    }

    ad.addStripTask(fullpath)

    ad.waitGroup.Done()
  }

  log.Printf("RPath change requests processing finished")
}

func fixRPath(fullpath, destinationRoot string) {
  libdir := filepath.Dir(fullpath)
  relativePath, err := filepath.Rel(libdir, destinationRoot)
  if err != nil {
    log.Println(err)
    return
  }

  rpath := fmt.Sprintf("$ORIGIN:$ORIGIN/%s/lib/", relativePath)
  log.Printf("Changing RPATH for %v to %v", fullpath, rpath)

  cmd := exec.Command("patchelf", "--set-rpath", rpath, fullpath)
  if err = cmd.Run(); err != nil {
    log.Println(err)
  }
}

func (ad *AppDeployer) addStripTask(fullpath string) {
  if *stripFlag {
    ad.waitGroup.Add(1)
    go func() {
      ad.stripChannel <- fullpath
    }()
  }
}

func (ad *AppDeployer) processStripTasks() {
  stripAvailable := true

  if _, err := exec.LookPath("strip"); err != nil {
    log.Printf("Strip cannot be found!")
    stripAvailable = false
  }

  strippedBinaries := make(map[string]bool)

  for fullpath := range ad.stripChannel {
    if stripAvailable {
      if _, ok := strippedBinaries[fullpath]; !ok {
        stripBinary(fullpath)
      } else {
        log.Printf("%v has been already stripped", fullpath)
      }
    }

    ad.waitGroup.Done()
  }

  log.Printf("Strip requests processing finished")
}

func stripBinary(fullpath string) {
  log.Printf("Running strip on %v", fullpath)

  cmd := exec.Command("strip", fullpath)
  if err := cmd.Run(); err != nil {
    log.Println(err)
  }
}
<commit_msg>More verbose stripping<commit_after>/*
 * This file is a part of linuxdeploy - tool for
 * creating standalone applications for Linux
 *
 * Copyright (C) 2017 Taras Kushnir <kushnirTV@gmail.com>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the MIT License.

 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 */

package main

import (
  "log"
  "os/exec"
  "path/filepath"
  "strings"
  "os"
  "fmt"
)

func (ad *AppDeployer) processLibTasks() {
  if _, err := exec.LookPath("ldd"); err != nil {
    log.Fatal("ldd cannot be found!")
  }

  for request := range ad.libsChannel {
    ad.processLibTask(request)
    ad.waitGroup.Done()
  }

  log.Println("Libraries processing finished")
}

func (ad *AppDeployer) processLibTask(request *DeployRequest) {
  libpath := request.FullPath()

  if ad.canSkipLibrary(libpath) {
    log.Printf("Skipping library: %v", libpath)
    return
  }

  log.Printf("Processing library: %v", libpath)

  dependencies, err := ad.findLddDependencies(request.Basename(), libpath)
  if err != nil {
    log.Printf("Error while dependency check for %v: %v", libpath, err)
    return
  }

  ad.accountLibrary(libpath)

  ad.waitGroup.Add(1)
  go func(copyRequest *DeployRequest) {
    ad.copyChannel <- copyRequest
  }(request)

  flags := request.flags
  // fix rpath of all the libs
  //flags.ClearFlag(FIX_RPATH_FLAG)
  flags.AddFlag(LDD_DEPENDENCY_FLAG)

  for _, dependPath := range dependencies {
    if !ad.isLibraryDeployed(dependPath) {
      ad.addLibTask("", dependPath, "lib", flags)
    }
  }
}

func (ad *AppDeployer) canSkipLibrary(libpath string) bool {
  canSkip := false
  if strings.HasPrefix(libpath, "linux-vdso.so") {
    canSkip = true
  } else if ad.isLibraryDeployed(libpath) {
    canSkip = true
  }

  return canSkip
}

func (ad *AppDeployer) findLddDependencies(basename, filepath string) ([]string, error) {
  log.Printf("Inspecting %v", filepath)

  out, err := exec.Command("ldd", filepath).Output()
  if err != nil { return nil, err }

  dependencies := make([]string, 0, 10)

  output := string(out)
  lines := strings.Split(output, "\n")
  for _, line := range lines {
    line = strings.TrimSpace(line)
    libname, libpath, err := parseLddOutputLine(line)

    if err != nil {
      log.Printf("Cannot parse ldd line: %v", line)
      continue
    }

    if len(libpath) == 0 {
      libpath = ad.resolveLibrary(libname)
    }

    log.Printf("[%v]: depends on %v from ldd [%v]", basename, libpath, line)
    dependencies = append(dependencies, libpath)
  }

  return dependencies, nil
}

func (ad *AppDeployer) addAdditionalLibPath(libpath string) {
  log.Printf("Adding addition libpath: %v", libpath)
  foundPath := libpath
  var err error

  if !filepath.IsAbs(foundPath) {
    if foundPath, err = filepath.Abs(foundPath); err == nil {
      log.Printf("Trying to resolve libpath to: %v", foundPath)

      if _, err = os.Stat(foundPath); os.IsNotExist(err) {
        exeDir := filepath.Dir(ad.targetExePath)
        foundPath = filepath.Join(exeDir, libpath)
        log.Printf("Trying to resolve libpath to: %v", foundPath)
      }
    }
  }

  if _, err := os.Stat(foundPath); os.IsNotExist(err) {
    log.Printf("Cannot find library path: %v", foundPath)
    return
  }

  log.Printf("Resolved additional libpath to: %v", foundPath)
  ad.additionalLibPaths = append(ad.additionalLibPaths, foundPath)
}

func (ad *AppDeployer) resolveLibrary(libname string) (foundPath string) {
  foundPath = libname

  for _, extraLibPath := range ad.additionalLibPaths {
    possiblePath := filepath.Join(extraLibPath, libname)

    if _, err := os.Stat(possiblePath); err == nil {
      foundPath = possiblePath
      break
    }
  }

  log.Printf("Resolving library %v to %v", libname, foundPath)
  return foundPath
}

func (ad *AppDeployer) processCopyTasks() {
  copiedFiles := make(map[string]bool)

  for copyRequest := range ad.copyChannel {
    ad.processCopyTask(copiedFiles, copyRequest)
    ad.waitGroup.Done()
  }

  log.Printf("Copy tasks processing finished")
}

func (ad *AppDeployer) processCopyTask(copiedFiles map[string]bool, copyRequest *DeployRequest) {
  var destinationPath, destinationPrefix string

  if len(copyRequest.sourceRoot) == 0 {
    // absolute path
    destinationPrefix = copyRequest.targetPath
  } else {
    destinationPrefix = filepath.Join(copyRequest.targetPath, copyRequest.SourceDir())
  }

  sourcePath := copyRequest.FullPath()
  destinationPath = filepath.Join(ad.destinationRoot, destinationPrefix, filepath.Base(copyRequest.sourcePath))

  if _, ok := copiedFiles[destinationPath]; ok {
    log.Printf("File %v has already been copied", sourcePath)
    return
  }

  ensureDirExists(destinationPath)
  err := copyFile(sourcePath, destinationPath)

  if err != nil {
    log.Printf("Error while copying [%v] to [%v]: %v", sourcePath, destinationPath, err)
    return
  }

  copiedFiles[destinationPath] = true
  log.Printf("Copied [%v] to [%v]", sourcePath, destinationPath)
  isQtLibrary := false

  if copyRequest.IsLddDependency() {
    libraryBasename := filepath.Base(destinationPath)
    libname := strings.ToLower(libraryBasename)

    if strings.HasPrefix(libname, "libqt") {
      ad.addQtLibTask(destinationPath)
      isQtLibrary = true
    }
  }

  if !isQtLibrary && copyRequest.RequiresRPathFix() {
    ad.addFixRPathTask(destinationPath)
  }
}

func (ad *AppDeployer) processFixRPathTasks() {
  patchelfAvailable := true

  if _, err := exec.LookPath("patchelf"); err != nil {
    log.Printf("Patchelf cannot be found!")
    patchelfAvailable = false
  }

  destinationRoot := ad.destinationRoot
  fixedFiles := make(map[string]bool)

  for fullpath := range ad.rpathChannel {
    if patchelfAvailable {
      if _, ok := fixedFiles[fullpath]; !ok {
        fixRPath(fullpath, destinationRoot)
        fixedFiles[fullpath] = true
      } else {
        log.Printf("RPATH has been already fixed for %v", fullpath)
      }
    }

    ad.addStripTask(fullpath)

    ad.waitGroup.Done()
  }

  log.Printf("RPath change requests processing finished")
}

func fixRPath(fullpath, destinationRoot string) {
  libdir := filepath.Dir(fullpath)
  relativePath, err := filepath.Rel(libdir, destinationRoot)
  if err != nil {
    log.Println(err)
    return
  }

  rpath := fmt.Sprintf("$ORIGIN:$ORIGIN/%s/lib/", relativePath)
  log.Printf("Changing RPATH for %v to %v", fullpath, rpath)

  cmd := exec.Command("patchelf", "--set-rpath", rpath, fullpath)
  if err = cmd.Run(); err != nil {
    log.Println(err)
  }
}

func (ad *AppDeployer) addStripTask(fullpath string) {
  if *stripFlag {
    ad.waitGroup.Add(1)
    go func() {
      ad.stripChannel <- fullpath
    }()
  }
}

func (ad *AppDeployer) processStripTasks() {
  stripAvailable := true

  if _, err := exec.LookPath("strip"); err != nil {
    log.Printf("Strip cannot be found!")
    stripAvailable = false
  }

  strippedBinaries := make(map[string]bool)

  for fullpath := range ad.stripChannel {
    if stripAvailable {
      if _, ok := strippedBinaries[fullpath]; !ok {
        stripBinary(fullpath)
      } else {
        log.Printf("%v has been already stripped", fullpath)
      }
    }

    ad.waitGroup.Done()
  }

  log.Printf("Strip requests processing finished")
}

func stripBinary(fullpath string) {
  log.Printf("Running strip on %v", fullpath)

  out, err := exec.Command("strip", fullpath).Output()
  if err != nil {
    log.Printf("Error while stripping %v: %v", fullpath, out)
  }
}
<|endoftext|>


<commit_before>package poll

import (
	"encoding/json"
	"io/ioutil"
)

type PollConf struct {
	Host string
	User PollUser
}

type PollUser struct {
	Id       string
	Password string
}

func LoadConf(path string) (*PollConf, error) {
	b, err := ioutil.ReadFile(path)
	if err != nil {
		return nil, err
	}
	var p PollConf
	json.Unmarshal(b, &p)
	return &p, nil
}
<commit_msg>add PollConf validation<commit_after>package poll

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
)

type PollConf struct {
	Host string
	User PollUser
}

type PollUser struct {
	Id       string
	Password string
}

func LoadConf(path string) (*PollConf, error) {
	b, err := ioutil.ReadFile(path)
	if err != nil {
		return nil, err
	}
	var p PollConf
	json.Unmarshal(b, &p)
	if err := p.validate(); err != nil {
		return nil, err
	}
	return &p, nil
}

func (c *PollConf) validate() error {
	if len(c.Host) == 0 {
		return fmt.Errorf("Config `Host` is missing.")
	}
	if len(c.User.Id) == 0 {
		return fmt.Errorf("Config `Host` is missing.")
	}
	if len(c.User.Password) == 0 {
		return fmt.Errorf("Config `Host` is missing.")
	}
	return nil
}
<|endoftext|>


<commit_before>package state

import (
	"math/big"
	"testing"

	checker "gopkg.in/check.v1"

	"github.com/ethereum/go-ethereum/common"
	"github.com/ethereum/go-ethereum/ethdb"
)

type StateSuite struct {
	state *StateDB
}

var _ = checker.Suite(&StateSuite{})

var toAddr = common.BytesToAddress

func (s *StateSuite) TestDump(c *checker.C) {
	return
	// generate a few entries
	obj1 := s.state.GetOrNewStateObject(toAddr([]byte{0x01}))
	obj1.AddBalance(big.NewInt(22))
	obj2 := s.state.GetOrNewStateObject(toAddr([]byte{0x01, 0x02}))
	obj2.SetCode([]byte{3, 3, 3, 3, 3, 3, 3})
	obj3 := s.state.GetOrNewStateObject(toAddr([]byte{0x02}))
	obj3.SetBalance(big.NewInt(44))

	// write some of them to the trie
	s.state.UpdateStateObject(obj1)
	s.state.UpdateStateObject(obj2)

	// check that dump contains the state objects that are in trie
	got := string(s.state.Dump())
	want := `{
    "root": "6e277ae8357d013e50f74eedb66a991f6922f93ae03714de58b3d0c5e9eee53f",
    "accounts": {
        "1468288056310c82aa4c01a7e12a10f8111a0560e72b700555479031b86c357d": {
            "balance": "22",
            "nonce": 0,
            "root": "56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
            "codeHash": "c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470",
            "storage": {}
        },
        "a17eacbc25cda025e81db9c5c62868822c73ce097cee2a63e33a2e41268358a1": {
            "balance": "0",
            "nonce": 0,
            "root": "56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
            "codeHash": "87874902497a5bb968da31a2998d8f22e949d1ef6214bcdedd8bae24cca4b9e3",
            "storage": {}
        }
    }
}`
	if got != want {
		c.Errorf("dump mismatch:\ngot: %s\nwant: %s\n", got, want)
	}
}

func (s *StateSuite) SetUpTest(c *checker.C) {
	db, _ := ethdb.NewMemDatabase()
	s.state = New(common.Hash{}, db)
}

func TestNull(t *testing.T) {
	db, _ := ethdb.NewMemDatabase()
	state := New(common.Hash{}, db)

	address := common.HexToAddress("0x823140710bf13990e4500136726d8b55")
	state.CreateAccount(address)
	//value := common.FromHex("0x823140710bf13990e4500136726d8b55")
	value := make([]byte, 16)
	state.SetState(address, common.Hash{}, value)
	state.Update()
	state.Sync()
	value = state.GetState(address, common.Hash{})
}

func (s *StateSuite) TestSnapshot(c *checker.C) {
	stateobjaddr := toAddr([]byte("aa"))
	storageaddr := common.Big("0")
	data1 := common.NewValue(42)
	data2 := common.NewValue(43)

	// get state object
	stateObject := s.state.GetOrNewStateObject(stateobjaddr)
	// set inital state object value
	stateObject.SetStorage(storageaddr, data1)
	// get snapshot of current state
	snapshot := s.state.Copy()

	// get state object. is this strictly necessary?
	stateObject = s.state.GetStateObject(stateobjaddr)
	// set new state object value
	stateObject.SetStorage(storageaddr, data2)
	// restore snapshot
	s.state.Set(snapshot)

	// get state object
	stateObject = s.state.GetStateObject(stateobjaddr)
	// get state storage value
	res := stateObject.GetStorage(storageaddr)

	c.Assert(data1, checker.DeepEquals, res)
}
<commit_msg>core/state: fixed state tests<commit_after>package state

import (
	"math/big"
	"testing"

	checker "gopkg.in/check.v1"

	"github.com/ethereum/go-ethereum/common"
	"github.com/ethereum/go-ethereum/ethdb"
)

type StateSuite struct {
	state *StateDB
}

var _ = checker.Suite(&StateSuite{})

var toAddr = common.BytesToAddress

func (s *StateSuite) TestDump(c *checker.C) {
	return
	// generate a few entries
	obj1 := s.state.GetOrNewStateObject(toAddr([]byte{0x01}))
	obj1.AddBalance(big.NewInt(22))
	obj2 := s.state.GetOrNewStateObject(toAddr([]byte{0x01, 0x02}))
	obj2.SetCode([]byte{3, 3, 3, 3, 3, 3, 3})
	obj3 := s.state.GetOrNewStateObject(toAddr([]byte{0x02}))
	obj3.SetBalance(big.NewInt(44))

	// write some of them to the trie
	s.state.UpdateStateObject(obj1)
	s.state.UpdateStateObject(obj2)

	// check that dump contains the state objects that are in trie
	got := string(s.state.Dump())
	want := `{
    "root": "6e277ae8357d013e50f74eedb66a991f6922f93ae03714de58b3d0c5e9eee53f",
    "accounts": {
        "1468288056310c82aa4c01a7e12a10f8111a0560e72b700555479031b86c357d": {
            "balance": "22",
            "nonce": 0,
            "root": "56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
            "codeHash": "c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470",
            "storage": {}
        },
        "a17eacbc25cda025e81db9c5c62868822c73ce097cee2a63e33a2e41268358a1": {
            "balance": "0",
            "nonce": 0,
            "root": "56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
            "codeHash": "87874902497a5bb968da31a2998d8f22e949d1ef6214bcdedd8bae24cca4b9e3",
            "storage": {}
        }
    }
}`
	if got != want {
		c.Errorf("dump mismatch:\ngot: %s\nwant: %s\n", got, want)
	}
}

func (s *StateSuite) SetUpTest(c *checker.C) {
	db, _ := ethdb.NewMemDatabase()
	s.state = New(common.Hash{}, db)
}

func TestNull(t *testing.T) {
	db, _ := ethdb.NewMemDatabase()
	state := New(common.Hash{}, db)

	address := common.HexToAddress("0x823140710bf13990e4500136726d8b55")
	state.CreateAccount(address)
	//value := common.FromHex("0x823140710bf13990e4500136726d8b55")
	var value common.Hash
	state.SetState(address, common.Hash{}, value)
	state.Update()
	state.Sync()
	value = state.GetState(address, common.Hash{})
	if !common.EmptyHash(value) {
		t.Errorf("expected empty hash. got %x", value)
	}
}

func (s *StateSuite) TestSnapshot(c *checker.C) {
	stateobjaddr := toAddr([]byte("aa"))
	var storageaddr common.Hash
	data1 := common.BytesToHash([]byte{42})
	data2 := common.BytesToHash([]byte{43})

	// set inital state object value
	s.state.SetState(stateobjaddr, storageaddr, data1)
	// get snapshot of current state
	snapshot := s.state.Copy()

	// set new state object value
	s.state.SetState(stateobjaddr, storageaddr, data2)
	// restore snapshot
	s.state.Set(snapshot)

	// get state storage value
	res := s.state.GetState(stateobjaddr, storageaddr)

	c.Assert(data1, checker.DeepEquals, res)
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2013 Zhen, LLC. http://zhen.io. All rights reserved.
 * Use of this source code is governed by the MIT license.
 *
 */

package scalable

import (
	"hash"
	"hash/fnv"
	"fmt"
	"github.com/zhenjl/bloom"
	"github.com/zhenjl/bloom/partitioned"
	"math"
)

// ScalableBloom is an implementation of the Scalable Bloom Filter that "addresses the problem of having
// to choose an a priori maximum size for the set, and allows an arbitrary growth of the set being presented."
// Reference #2: Scalable Bloom Filters (http://gsd.di.uminho.pt/members/cbm/ps/dbloom.pdf)
type ScalableBloom struct {
	// h is the hash function used to get the list of h1..hk values
	// By default we use hash/fnv.New64(). User can also set their own using SetHasher()
	h hash.Hash

	// p is the fill ratio of the filter partitions. It's mainly used to calculate m at the start.
	// p is not checked when new items are added. So if the fill ratio goes above p, the likelihood
	// of false positives (error rate) will increase.
	//
	// By default we use the fill ratio of p = 0.5
	p float64

	// e is the desired error rate of the bloom filter. The lower the e, the higher the k.
	//
	// By default we use the error rate of e = 0.1% = 0.001. In some papers this is P (uppercase P)
	e float64

	// n is the number of elements the filter is predicted to hold while maintaining the error rate
	// or filter size (m). n is user supplied. But, in case you are interested, the formula is
	// n =~ m * ( (log(p) * log(1-p)) / abs(log e) )
	n uint

	// c is the number of items we have added to the filter
	c uint

	// r is the error tightening ratio with 0 < r < 1.
	// By default we use 0.9 as it result in better average space usage for wide ranges of growth.
	// See Scalable Bloom Filter paper for reference
	r float32

	// bfs is an array of bloom filters used by the scalable bloom filter
	bfs []bloom.Bloom

	// bfc is the bloom filter constructor (New()) that returns the bloom filter to use
	bfc func(uint) bloom.Bloom
}

var _ bloom.Bloom = (*ScalableBloom)(nil)

// New initializes a new partitioned bloom filter.
// n is the number of items this bloom filter predicted to hold.
func New(n uint) bloom.Bloom {
	var (
		p float64 = 0.5
		e float64 = 0.001
		r float32 = 0.9
		h hash.Hash = fnv.New64()
	)

	bf := &ScalableBloom{
		h: h,
		n: n,
		p: p,
		e: e,
		r: r,
	}

	bf.addBloomFilter()

	return bf
}

func (this *ScalableBloom) SetBloomFilter(f func(uint) bloom.Bloom) {
	this.bfc = f
}

func (this *ScalableBloom) SetHasher(h hash.Hash) {
	this.h = h
}

func (this *ScalableBloom) Reset() {
	if this.h == nil {
		this.h = fnv.New64()
	} else {
		this.h.Reset()
	}

	this.bfs = []bloom.Bloom{}
	this.addBloomFilter()
}

func (this *ScalableBloom) SetErrorProbability(e float64) {
	this.e = e
}

func (this *ScalableBloom) EstimatedFillRatio() float64 {
	return this.bfs[len(this.bfs)-1].EstimatedFillRatio()
}

func (this *ScalableBloom) FillRatio() float64 {
	// Since this has multiple bloom filters, we will return the average
	t := float64(0)
	for i := range this.bfs {
		t += this.bfs[i].FillRatio()
	}
	return t/float64(len(this.bfs))
}

func (this *ScalableBloom) Add(item []byte) bloom.Bloom {
	i := len(this.bfs) - 1

	if this.bfs[i].EstimatedFillRatio() > this.p {
		this.addBloomFilter()
		i++
	}

	this.bfs[i].Add(item)
	this.c++
	return this
}

func (this *ScalableBloom) Check(item []byte) bool {
	l := len(this.bfs)
	for i := l - 1; i >= 0; i-- {
		//fmt.Println("checking level ", i)
		if this.bfs[i].Check(item) {
			return true
		}
	}
	return false
}

func (this *ScalableBloom) Count() uint {
	return this.c
}

func (this *ScalableBloom) PrintStats() {
	fmt.Printf("n = %d, p = %f, e = %f\n", this.n, this.p, this.e)
	fmt.Println("Total items:", this.c)

	for i := range this.bfs {
		fmt.Printf("Scalable Bloom Filter #%d\n", i)
		fmt.Printf("-------------------------\n")
		this.bfs[i].PrintStats()
	}
}

func (this *ScalableBloom) addBloomFilter() {
	var bf bloom.Bloom
	if this.bfc == nil {
		bf = partitioned.New(this.n)
	} else {
		bf = this.bfc(this.n)
	}

	e := this.e * math.Pow(float64(this.r), float64(len(this.bfs)))

	bf.SetHasher(this.h)
	bf.SetErrorProbability(e)
	bf.Reset()

	this.bfs = append(this.bfs, bf)
	//fmt.Println("Added new bloom filter")
}
<commit_msg>fix bug in Reset() to reset c=0, thx @jasonmoo<commit_after>/*
 * Copyright (c) 2013 Zhen, LLC. http://zhen.io. All rights reserved.
 * Use of this source code is governed by the MIT license.
 *
 */

package scalable

import (
	"hash"
	"hash/fnv"
	"fmt"
	"github.com/zhenjl/bloom"
	"github.com/zhenjl/bloom/partitioned"
	"math"
)

// ScalableBloom is an implementation of the Scalable Bloom Filter that "addresses the problem of having
// to choose an a priori maximum size for the set, and allows an arbitrary growth of the set being presented."
// Reference #2: Scalable Bloom Filters (http://gsd.di.uminho.pt/members/cbm/ps/dbloom.pdf)
type ScalableBloom struct {
	// h is the hash function used to get the list of h1..hk values
	// By default we use hash/fnv.New64(). User can also set their own using SetHasher()
	h hash.Hash

	// p is the fill ratio of the filter partitions. It's mainly used to calculate m at the start.
	// p is not checked when new items are added. So if the fill ratio goes above p, the likelihood
	// of false positives (error rate) will increase.
	//
	// By default we use the fill ratio of p = 0.5
	p float64

	// e is the desired error rate of the bloom filter. The lower the e, the higher the k.
	//
	// By default we use the error rate of e = 0.1% = 0.001. In some papers this is P (uppercase P)
	e float64

	// n is the number of elements the filter is predicted to hold while maintaining the error rate
	// or filter size (m). n is user supplied. But, in case you are interested, the formula is
	// n =~ m * ( (log(p) * log(1-p)) / abs(log e) )
	n uint

	// c is the number of items we have added to the filter
	c uint

	// r is the error tightening ratio with 0 < r < 1.
	// By default we use 0.9 as it result in better average space usage for wide ranges of growth.
	// See Scalable Bloom Filter paper for reference
	r float32

	// bfs is an array of bloom filters used by the scalable bloom filter
	bfs []bloom.Bloom

	// bfc is the bloom filter constructor (New()) that returns the bloom filter to use
	bfc func(uint) bloom.Bloom
}

var _ bloom.Bloom = (*ScalableBloom)(nil)

// New initializes a new partitioned bloom filter.
// n is the number of items this bloom filter predicted to hold.
func New(n uint) bloom.Bloom {
	var (
		p float64 = 0.5
		e float64 = 0.001
		r float32 = 0.9
		h hash.Hash = fnv.New64()
	)

	bf := &ScalableBloom{
		h: h,
		n: n,
		p: p,
		e: e,
		r: r,
	}

	bf.addBloomFilter()

	return bf
}

func (this *ScalableBloom) SetBloomFilter(f func(uint) bloom.Bloom) {
	this.bfc = f
}

func (this *ScalableBloom) SetHasher(h hash.Hash) {
	this.h = h
}

func (this *ScalableBloom) Reset() {
	if this.h == nil {
		this.h = fnv.New64()
	} else {
		this.h.Reset()
	}

	this.bfs = []bloom.Bloom{}
    this.c = 0
	this.addBloomFilter()
}

func (this *ScalableBloom) SetErrorProbability(e float64) {
	this.e = e
}

func (this *ScalableBloom) EstimatedFillRatio() float64 {
	return this.bfs[len(this.bfs)-1].EstimatedFillRatio()
}

func (this *ScalableBloom) FillRatio() float64 {
	// Since this has multiple bloom filters, we will return the average
	t := float64(0)
	for i := range this.bfs {
		t += this.bfs[i].FillRatio()
	}
	return t/float64(len(this.bfs))
}

func (this *ScalableBloom) Add(item []byte) bloom.Bloom {
	i := len(this.bfs) - 1

	if this.bfs[i].EstimatedFillRatio() > this.p {
		this.addBloomFilter()
		i++
	}

	this.bfs[i].Add(item)
	this.c++
	return this
}

func (this *ScalableBloom) Check(item []byte) bool {
	l := len(this.bfs)
	for i := l - 1; i >= 0; i-- {
		//fmt.Println("checking level ", i)
		if this.bfs[i].Check(item) {
			return true
		}
	}
	return false
}

func (this *ScalableBloom) Count() uint {
	return this.c
}

func (this *ScalableBloom) PrintStats() {
	fmt.Printf("n = %d, p = %f, e = %f\n", this.n, this.p, this.e)
	fmt.Println("Total items:", this.c)

	for i := range this.bfs {
		fmt.Printf("Scalable Bloom Filter #%d\n", i)
		fmt.Printf("-------------------------\n")
		this.bfs[i].PrintStats()
	}
}

func (this *ScalableBloom) addBloomFilter() {
	var bf bloom.Bloom
	if this.bfc == nil {
		bf = partitioned.New(this.n)
	} else {
		bf = this.bfc(this.n)
	}

	e := this.e * math.Pow(float64(this.r), float64(len(this.bfs)))

	bf.SetHasher(this.h)
	bf.SetErrorProbability(e)
	bf.Reset()

	this.bfs = append(this.bfs, bf)
	//fmt.Println("Added new bloom filter")
}
<|endoftext|>


<commit_before>package websocket

import (
	"io"
	"net"
	"time"

	ws "github.com/gorilla/websocket"
)

var _ net.Conn = (*Conn)(nil)

// Conn implements net.Conn interface for gorilla/websocket.
type Conn struct {
	*ws.Conn
	DefaultMessageType int
	done               func()
	reader             io.Reader
}

func (c *Conn) Read(b []byte) (int, error) {
	if c.reader == nil {
		if err := c.prepNextReader(); err != nil {
			return 0, err
		}
	}

	for {
		n, err := c.reader.Read(b)
		switch err {
		case io.EOF:
			c.reader = nil

			if n > 0 {
				return n, nil
			}

			if err := c.prepNextReader(); err != nil {
				return 0, err
			}

			// explicitly looping
		default:
			return n, err
		}
	}
}

func (c *Conn) prepNextReader() error {
	t, r, err := c.Conn.NextReader()
	if err != nil {
		if wserr, ok := err.(*ws.CloseError); ok {
			if wserr.Code == 1000 || wserr.Code == 1005 {
				return io.EOF
			}
		}
		return err
	}

	if t == ws.CloseMessage {
		return io.EOF
	}

	c.reader = r
	return nil
}

func (c *Conn) Write(b []byte) (n int, err error) {
	if err := c.Conn.WriteMessage(c.DefaultMessageType, b); err != nil {
		return 0, err
	}

	return len(b), nil
}

func (c *Conn) Close() error {
	if c.done != nil {
		c.done()
	}

	c.Conn.WriteMessage(ws.CloseMessage, nil)
	return c.Conn.Close()
}

func (c *Conn) LocalAddr() net.Addr {
	return NewAddr(c.Conn.LocalAddr().String())
}

func (c *Conn) RemoteAddr() net.Addr {
	return NewAddr(c.Conn.RemoteAddr().String())
}

func (c *Conn) SetDeadline(t time.Time) error {
	if err := c.SetReadDeadline(t); err != nil {
		return err
	}

	return c.SetWriteDeadline(t)
}

func (c *Conn) SetReadDeadline(t time.Time) error {
	return c.Conn.SetReadDeadline(t)
}

func (c *Conn) SetWriteDeadline(t time.Time) error {
	return c.Conn.SetWriteDeadline(t)
}

// NewConn creates a Conn given a regular gorilla/websocket Conn.
func NewConn(raw *ws.Conn, done func()) *Conn {
	return &Conn{
		Conn:               raw,
		DefaultMessageType: ws.BinaryMessage,
		done:               done,
	}
}
<commit_msg>Make close thread safe<commit_after>package websocket

import (
	"io"
	"net"
	"sync"
	"time"

	ws "github.com/gorilla/websocket"
)

// GracefulCloseTimeout is the time to wait trying to gracefully close a
// connection before simply cutting it.
var GracefulCloseTimeout = 100 * time.Millisecond

var _ net.Conn = (*Conn)(nil)

// Conn implements net.Conn interface for gorilla/websocket.
type Conn struct {
	*ws.Conn
	DefaultMessageType int
	done               func()
	reader             io.Reader
	closeOnce          sync.Once
}

func (c *Conn) Read(b []byte) (int, error) {
	if c.reader == nil {
		if err := c.prepNextReader(); err != nil {
			return 0, err
		}
	}

	for {
		n, err := c.reader.Read(b)
		switch err {
		case io.EOF:
			c.reader = nil

			if n > 0 {
				return n, nil
			}

			if err := c.prepNextReader(); err != nil {
				return 0, err
			}

			// explicitly looping
		default:
			return n, err
		}
	}
}

func (c *Conn) prepNextReader() error {
	t, r, err := c.Conn.NextReader()
	if err != nil {
		if wserr, ok := err.(*ws.CloseError); ok {
			if wserr.Code == 1000 || wserr.Code == 1005 {
				return io.EOF
			}
		}
		return err
	}

	if t == ws.CloseMessage {
		return io.EOF
	}

	c.reader = r
	return nil
}

func (c *Conn) Write(b []byte) (n int, err error) {
	if err := c.Conn.WriteMessage(c.DefaultMessageType, b); err != nil {
		return 0, err
	}

	return len(b), nil
}

// Close closes the connection. Only the first call to Close will receive the
// close error, subsequent and concurrent calls will return nil.
// This method is thread-safe.
func (c *Conn) Close() error {
	var err error = nil
	c.closeOnce.Do(func() {
		if c.done != nil {
			c.done()
			// Be nice to GC
			c.done = nil
		}

		c.Conn.WriteControl(ws.CloseMessage, nil, time.Now().Add(GracefulCloseTimeout))
		err = c.Conn.Close()
	})
	return err
}

func (c *Conn) LocalAddr() net.Addr {
	return NewAddr(c.Conn.LocalAddr().String())
}

func (c *Conn) RemoteAddr() net.Addr {
	return NewAddr(c.Conn.RemoteAddr().String())
}

func (c *Conn) SetDeadline(t time.Time) error {
	if err := c.SetReadDeadline(t); err != nil {
		return err
	}

	return c.SetWriteDeadline(t)
}

func (c *Conn) SetReadDeadline(t time.Time) error {
	return c.Conn.SetReadDeadline(t)
}

func (c *Conn) SetWriteDeadline(t time.Time) error {
	return c.Conn.SetWriteDeadline(t)
}

// NewConn creates a Conn given a regular gorilla/websocket Conn.
func NewConn(raw *ws.Conn, done func()) *Conn {
	return &Conn{
		Conn:               raw,
		DefaultMessageType: ws.BinaryMessage,
		done:               done,
	}
}
<|endoftext|>


<commit_before>package tm

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

//go:generate msgp

// Date represents a UTC time zone day
type Date struct {
	Year  int
	Month int
	Day   int
}

// ParseDate converts a datestring '2016/02/25' into a Date{} struct.
func ParseDate(datestring string) (*Date, error) {
	parts := strings.Split(datestring, "/")
	if len(parts) != 3 {
		return nil, fmt.Errorf("bad datestring '%s': did not have two slashes", datestring)
	}
	year, err := strconv.Atoi(parts[0])
	if err != nil {
		return nil, fmt.Errorf("bad datestring '%s': could not parse year", datestring)
	}
	month, err := strconv.Atoi(parts[1])
	if err != nil {
		return nil, fmt.Errorf("bad datestring '%s': could not parse month", datestring)
	}
	day, err := strconv.Atoi(parts[2])
	if err != nil {
		return nil, fmt.Errorf("bad datestring '%s': could not parse day", datestring)
	}

	if year < 1970 || year > 3000 {
		return nil, fmt.Errorf("year out of bounds: %v", year)
	}
	if month < 1 || month > 12 {
		return nil, fmt.Errorf("month out of bounds: %v", month)
	}
	if day < 1 || day > 31 {
		return nil, fmt.Errorf("day out of bounds: %v", day)
	}

	return &Date{Year: year, Month: month, Day: day}, nil
}

var WestCoastUSLocation *time.Location
var EastCoastUSLocation *time.Location
var LondonLocation *time.Location
var UTCLocation = time.UTC

func init() {
	var err error
	WestCoastUSLocation, err = time.LoadLocation("America/Los_Angeles")
	panicOn(err)
	EastCoastUSLocation, err = time.LoadLocation("America/New_York")
	panicOn(err)
	LondonLocation, err = time.LoadLocation("Europe/London")
	panicOn(err)
}

// UTCDateFromTime returns the date after tm is moved to the UTC time zone.
func UTCDateFromTime(tm time.Time) *Date {
	y, m, d := tm.In(time.UTC).Date()
	return &Date{Year: y, Month: int(m), Day: d}
}

// Unix converts the date into an int64 representing the nanoseconds
// since the unix epoch for the ToGoTime() output of Date d.
func (d *Date) Unix() int64 {
	return d.ToGoTime().Unix()
}

// ToGoTime turns the date into UTC time.Time, at the 0 hrs 0 min 0 second start of the day.
func (d *Date) ToGoTime() time.Time {
	return time.Date(d.Year, time.Month(d.Month), d.Day, 0, 0, 0, 0, time.UTC)
}

// String turns the date into a string.
func (d *Date) String() string {
	return fmt.Sprintf("%04d/%02d/%02d", d.Year, d.Month, d.Day)
}

// return true if a < b
func DateBefore(a *Date, b *Date) bool {
	if a.Year < b.Year {
		return true
	} else if a.Year > b.Year {
		return false
	}

	if a.Month < b.Month {
		return true
	} else if a.Month > b.Month {
		return false
	}

	if a.Day < b.Day {
		return true
	} else if a.Day > b.Day {
		return false
	}

	return false
}

// return true if a > b
func DateAfter(a *Date, b *Date) bool {
	if a.Year > b.Year {
		return true
	} else if a.Year < b.Year {
		return false
	}

	if a.Month > b.Month {
		return true
	} else if a.Month < b.Month {
		return false
	}

	if a.Day > b.Day {
		return true
	} else if a.Day < b.Day {
		return false
	}

	return false
}

// DatesEqual returns true if a and b are the exact same day.
func DatesEqual(a *Date, b *Date) bool {
	if a.Year == b.Year {
		if a.Month == b.Month {
			if a.Day == b.Day {
				return true
			}
		}
	}
	return false
}

// NextDate returns the next calendar day after d.
func NextDate(d *Date) *Date {
	tm := d.ToGoTime()
	next := tm.AddDate(0, 0, 1)
	return UTCDateFromTime(next)
}

// PrevDate returns the first calendar day prior to d.
func PrevDate(d *Date) *Date {
	tm := d.ToGoTime()
	next := tm.AddDate(0, 0, -1)
	return UTCDateFromTime(next)
}
<commit_msg>atg. include TimeToDate()<commit_after>package tm

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

//go:generate msgp

// Date represents a UTC time zone day
type Date struct {
	Year  int
	Month int
	Day   int
}

// ParseDate converts a datestring '2016/02/25' into a Date{} struct.
func ParseDate(datestring string) (*Date, error) {
	parts := strings.Split(datestring, "/")
	if len(parts) != 3 {
		return nil, fmt.Errorf("bad datestring '%s': did not have two slashes", datestring)
	}
	year, err := strconv.Atoi(parts[0])
	if err != nil {
		return nil, fmt.Errorf("bad datestring '%s': could not parse year", datestring)
	}
	month, err := strconv.Atoi(parts[1])
	if err != nil {
		return nil, fmt.Errorf("bad datestring '%s': could not parse month", datestring)
	}
	day, err := strconv.Atoi(parts[2])
	if err != nil {
		return nil, fmt.Errorf("bad datestring '%s': could not parse day", datestring)
	}

	if year < 1970 || year > 3000 {
		return nil, fmt.Errorf("year out of bounds: %v", year)
	}
	if month < 1 || month > 12 {
		return nil, fmt.Errorf("month out of bounds: %v", month)
	}
	if day < 1 || day > 31 {
		return nil, fmt.Errorf("day out of bounds: %v", day)
	}

	return &Date{Year: year, Month: month, Day: day}, nil
}

var WestCoastUSLocation *time.Location
var EastCoastUSLocation *time.Location
var LondonLocation *time.Location
var UTCLocation = time.UTC

func init() {
	var err error
	WestCoastUSLocation, err = time.LoadLocation("America/Los_Angeles")
	panicOn(err)
	EastCoastUSLocation, err = time.LoadLocation("America/New_York")
	panicOn(err)
	LondonLocation, err = time.LoadLocation("Europe/London")
	panicOn(err)
}

// UTCDateFromTime returns the date after tm is moved to the UTC time zone.
func UTCDateFromTime(tm time.Time) *Date {
	y, m, d := tm.In(time.UTC).Date()
	return &Date{Year: y, Month: int(m), Day: d}
}

// Unix converts the date into an int64 representing the nanoseconds
// since the unix epoch for the ToGoTime() output of Date d.
func (d *Date) Unix() int64 {
	return d.ToGoTime().Unix()
}

// ToGoTime turns the date into UTC time.Time, at the 0 hrs 0 min 0 second start of the day.
func (d *Date) ToGoTime() time.Time {
	return time.Date(d.Year, time.Month(d.Month), d.Day, 0, 0, 0, 0, time.UTC)
}

// String turns the date into a string.
func (d *Date) String() string {
	return fmt.Sprintf("%04d/%02d/%02d", d.Year, d.Month, d.Day)
}

// return true if a < b
func DateBefore(a *Date, b *Date) bool {
	if a.Year < b.Year {
		return true
	} else if a.Year > b.Year {
		return false
	}

	if a.Month < b.Month {
		return true
	} else if a.Month > b.Month {
		return false
	}

	if a.Day < b.Day {
		return true
	} else if a.Day > b.Day {
		return false
	}

	return false
}

// return true if a > b
func DateAfter(a *Date, b *Date) bool {
	if a.Year > b.Year {
		return true
	} else if a.Year < b.Year {
		return false
	}

	if a.Month > b.Month {
		return true
	} else if a.Month < b.Month {
		return false
	}

	if a.Day > b.Day {
		return true
	} else if a.Day < b.Day {
		return false
	}

	return false
}

// DatesEqual returns true if a and b are the exact same day.
func DatesEqual(a *Date, b *Date) bool {
	if a.Year == b.Year {
		if a.Month == b.Month {
			if a.Day == b.Day {
				return true
			}
		}
	}
	return false
}

// NextDate returns the next calendar day after d.
func NextDate(d *Date) *Date {
	tm := d.ToGoTime()
	next := tm.AddDate(0, 0, 1)
	return UTCDateFromTime(next)
}

// PrevDate returns the first calendar day prior to d.
func PrevDate(d *Date) *Date {
	tm := d.ToGoTime()
	next := tm.AddDate(0, 0, -1)
	return UTCDateFromTime(next)
}

// TimeToDate returns the UTC Date associated with tm.
func TimeToDate(tm time.Time) Date {
	utc := tm.UTC()
	return Date{
		Year:  utc.Year(),
		Month: int(utc.Month()),
		Day:   utc.Day(),
	}
}
<|endoftext|>


<commit_before>package jsonrpc

import (
	"net/http"
	"net/http/httptest"
	"testing"

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

func TestDebugHandler(t *testing.T) {
	t.Skip()

	mr := NewMethodRepository()

	rec := httptest.NewRecorder()
	r, err := http.NewRequest("", "", nil)
	require.NoError(t, err)

	mr.ServeDebug(rec, r)

	require.Equal(t, http.StatusNotFound, rec.Code)

	require.NoError(t, mr.RegisterMethod("Debug.Sample", SampleHandler(), struct {
		Name string `json:"name"`
	}{}, struct {
		Message string `json:"message,omitempty"`
	}{}))

	rec = httptest.NewRecorder()
	r, err = http.NewRequest("", "", nil)
	require.NoError(t, err)

	mr.ServeDebug(rec, r)

	require.Equal(t, http.StatusOK, rec.Code)
	assert.NotEmpty(t, rec.Body.String())
}
<commit_msg>Restore the testcases that were skipped<commit_after>package jsonrpc

import (
	"net/http"
	"net/http/httptest"
	"testing"

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

func TestDebugHandler(t *testing.T) {
	mr := NewMethodRepository()

	rec := httptest.NewRecorder()
	r, err := http.NewRequest("", "", nil)
	require.NoError(t, err)

	mr.ServeDebug(rec, r)

	require.Equal(t, http.StatusNotFound, rec.Code)

	require.NoError(t, mr.RegisterMethod("Debug.Sample", SampleHandler(), struct {
		Name string `json:"name"`
	}{}, struct {
		Message string `json:"message,omitempty"`
	}{}))

	rec = httptest.NewRecorder()
	r, err = http.NewRequest("", "", nil)
	require.NoError(t, err)

	mr.ServeDebug(rec, r)

	require.Equal(t, http.StatusOK, rec.Code)
	assert.NotEmpty(t, rec.Body.String())
}
<|endoftext|>


<commit_before>package endpoint

import (
	"crypto/tls"
	"crypto/x509"
	"errors"
	"fmt"
	"io/ioutil"
	"sync"
	"time"

	lg "log"

	"github.com/Shopify/sarama"
	"github.com/tidwall/gjson"
	"github.com/tidwall/tile38/internal/log"
)

const kafkaExpiresAfter = time.Second * 30

// KafkaConn is an endpoint connection
type KafkaConn struct {
	mu   sync.Mutex
	ep   Endpoint
	conn sarama.SyncProducer
	ex   bool
	t    time.Time
}

// Expired returns true if the connection has expired
func (conn *KafkaConn) Expired() bool {
	conn.mu.Lock()
	defer conn.mu.Unlock()
	if !conn.ex {
		if time.Since(conn.t) > kafkaExpiresAfter {
			if conn.conn != nil {
				conn.close()
			}
			conn.ex = true
		}
	}
	return conn.ex
}

func (conn *KafkaConn) close() {
	if conn.conn != nil {
		conn.conn.Close()
		conn.conn = nil
	}
}

// Send sends a message
func (conn *KafkaConn) Send(msg string) error {
	conn.mu.Lock()
	defer conn.mu.Unlock()

	if conn.ex {
		return errExpired
	}
	conn.t = time.Now()

	if log.Level > 2 {
		sarama.Logger = lg.New(log.Output(), "[sarama] ", 0)
	}

	uri := fmt.Sprintf("%s:%d", conn.ep.Kafka.Host, conn.ep.Kafka.Port)
	if conn.conn == nil {
		cfg := sarama.NewConfig()

		if conn.ep.Kafka.TLS {
			log.Debugf("building kafka tls config")
			tlsConfig, err := newKafkaTLSConfig(conn.ep.Kafka.CertFile, conn.ep.Kafka.KeyFile, conn.ep.Kafka.CACertFile)
			if err != nil {
				return err
			}
			cfg.Net.TLS.Enable = true
			cfg.Net.TLS.Config = tlsConfig
		}

		cfg.Net.DialTimeout = time.Second
		cfg.Net.ReadTimeout = time.Second * 5
		cfg.Net.WriteTimeout = time.Second * 5
		// Fix #333 : fix backward incompatibility introduced by sarama library
		cfg.Producer.Return.Successes = true
		cfg.Version = sarama.V0_10_0_0

		c, err := sarama.NewSyncProducer([]string{uri}, cfg)
		if err != nil {
			return err
		}

		conn.conn = c
	}

	// parse json again to get out info for our kafka key
	key := gjson.Get(msg, "key")
	id := gjson.Get(msg, "id")
	keyValue := fmt.Sprintf("%s-%s", key.String(), id.String())

	message := &sarama.ProducerMessage{
		Topic: conn.ep.Kafka.TopicName,
		Key:   sarama.StringEncoder(keyValue),
		Value: sarama.StringEncoder(msg),
	}

	_, offset, err := conn.conn.SendMessage(message)
	if err != nil {
		conn.close()
		return err
	}

	if offset < 0 {
		conn.close()
		return errors.New("invalid kafka reply")
	}

	return nil
}

func newKafkaConn(ep Endpoint) *KafkaConn {
	return &KafkaConn{
		ep: ep,
		t:  time.Now(),
	}
}

func newKafkaTLSConfig(CertFile, KeyFile, CACertFile string) (*tls.Config, error) {
	tlsConfig := tls.Config{}

	// Load client cert
	cert, err := tls.LoadX509KeyPair(CertFile, KeyFile)
	if err != nil {
		return &tlsConfig, err
	}
	tlsConfig.Certificates = []tls.Certificate{cert}

	// Load CA cert
	caCert, err := ioutil.ReadFile(CACertFile)
	if err != nil {
		return &tlsConfig, err
	}
	caCertPool := x509.NewCertPool()
	caCertPool.AppendCertsFromPEM(caCert)
	tlsConfig.RootCAs = caCertPool

	tlsConfig.BuildNameToCertificate()
	return &tlsConfig, err
}
<commit_msg>Remove deprecated function<commit_after>package endpoint

import (
	"crypto/tls"
	"crypto/x509"
	"errors"
	"fmt"
	"io/ioutil"
	"sync"
	"time"

	lg "log"

	"github.com/Shopify/sarama"
	"github.com/tidwall/gjson"
	"github.com/tidwall/tile38/internal/log"
)

const kafkaExpiresAfter = time.Second * 30

// KafkaConn is an endpoint connection
type KafkaConn struct {
	mu   sync.Mutex
	ep   Endpoint
	conn sarama.SyncProducer
	ex   bool
	t    time.Time
}

// Expired returns true if the connection has expired
func (conn *KafkaConn) Expired() bool {
	conn.mu.Lock()
	defer conn.mu.Unlock()
	if !conn.ex {
		if time.Since(conn.t) > kafkaExpiresAfter {
			if conn.conn != nil {
				conn.close()
			}
			conn.ex = true
		}
	}
	return conn.ex
}

func (conn *KafkaConn) close() {
	if conn.conn != nil {
		conn.conn.Close()
		conn.conn = nil
	}
}

// Send sends a message
func (conn *KafkaConn) Send(msg string) error {
	conn.mu.Lock()
	defer conn.mu.Unlock()

	if conn.ex {
		return errExpired
	}
	conn.t = time.Now()

	if log.Level > 2 {
		sarama.Logger = lg.New(log.Output(), "[sarama] ", 0)
	}

	uri := fmt.Sprintf("%s:%d", conn.ep.Kafka.Host, conn.ep.Kafka.Port)
	if conn.conn == nil {
		cfg := sarama.NewConfig()

		if conn.ep.Kafka.TLS {
			log.Debugf("building kafka tls config")
			tlsConfig, err := newKafkaTLSConfig(conn.ep.Kafka.CertFile, conn.ep.Kafka.KeyFile, conn.ep.Kafka.CACertFile)
			if err != nil {
				return err
			}
			cfg.Net.TLS.Enable = true
			cfg.Net.TLS.Config = tlsConfig
		}

		cfg.Net.DialTimeout = time.Second
		cfg.Net.ReadTimeout = time.Second * 5
		cfg.Net.WriteTimeout = time.Second * 5
		// Fix #333 : fix backward incompatibility introduced by sarama library
		cfg.Producer.Return.Successes = true
		cfg.Version = sarama.V0_10_0_0

		c, err := sarama.NewSyncProducer([]string{uri}, cfg)
		if err != nil {
			return err
		}

		conn.conn = c
	}

	// parse json again to get out info for our kafka key
	key := gjson.Get(msg, "key")
	id := gjson.Get(msg, "id")
	keyValue := fmt.Sprintf("%s-%s", key.String(), id.String())

	message := &sarama.ProducerMessage{
		Topic: conn.ep.Kafka.TopicName,
		Key:   sarama.StringEncoder(keyValue),
		Value: sarama.StringEncoder(msg),
	}

	_, offset, err := conn.conn.SendMessage(message)
	if err != nil {
		conn.close()
		return err
	}

	if offset < 0 {
		conn.close()
		return errors.New("invalid kafka reply")
	}

	return nil
}

func newKafkaConn(ep Endpoint) *KafkaConn {
	return &KafkaConn{
		ep: ep,
		t:  time.Now(),
	}
}

func newKafkaTLSConfig(CertFile, KeyFile, CACertFile string) (*tls.Config, error) {
	tlsConfig := tls.Config{}

	// Load client cert
	cert, err := tls.LoadX509KeyPair(CertFile, KeyFile)
	if err != nil {
		return &tlsConfig, err
	}
	tlsConfig.Certificates = []tls.Certificate{cert}

	// Load CA cert
	caCert, err := ioutil.ReadFile(CACertFile)
	if err != nil {
		return &tlsConfig, err
	}
	caCertPool := x509.NewCertPool()
	caCertPool.AppendCertsFromPEM(caCert)
	tlsConfig.RootCAs = caCertPool

	return &tlsConfig, err
}
<|endoftext|>


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

package opengl

import (
	"math"

	"github.com/hajimehoshi/ebiten/internal/graphics"
)

var (
	zeroPlus = math.Nextafter32(0, 1)
	oneMinus = math.Nextafter32(1, 0)
)

var (
	vertexShader       shaderType
	fragmentShader     shaderType
	arrayBuffer        bufferType
	elementArrayBuffer bufferType
	dynamicDraw        bufferUsage
	staticDraw         bufferUsage
	Short              DataType
	Float              DataType

	zero             operation
	one              operation
	srcAlpha         operation
	dstAlpha         operation
	oneMinusSrcAlpha operation
	oneMinusDstAlpha operation
)

func convertOperation(op graphics.Operation) operation {
	switch op {
	case graphics.Zero:
		return zero
	case graphics.One:
		return one
	case graphics.SrcAlpha:
		return srcAlpha
	case graphics.DstAlpha:
		return dstAlpha
	case graphics.OneMinusSrcAlpha:
		return oneMinusSrcAlpha
	case graphics.OneMinusDstAlpha:
		return oneMinusDstAlpha
	default:
		panic("not reached")
	}
}

type Context struct {
	locationCache      *locationCache
	screenFramebuffer  framebufferNative // This might not be the default frame buffer '0' (e.g. iOS).
	lastFramebuffer    framebufferNative
	lastTexture        textureNative
	lastViewportWidth  int
	lastViewportHeight int
	lastCompositeMode  graphics.CompositeMode
	maxTextureSize     int
	context
}

var theContext = &Context{}

func GetContext() *Context {
	return theContext
}

func (c *Context) bindTexture(t textureNative) {
	if c.lastTexture == t {
		return
	}
	c.bindTextureImpl(t)
	c.lastTexture = t
}

func (c *Context) bindFramebuffer(f framebufferNative) {
	if c.lastFramebuffer == f {
		return
	}
	c.bindFramebufferImpl(f)
	c.lastFramebuffer = f
}

func (c *Context) setViewport(f *framebuffer) {
	c.bindFramebuffer(f.native)
	if c.lastViewportWidth != f.width || c.lastViewportHeight != f.height {
		c.setViewportImpl(f.width, f.height)
		// glViewport must be called at least at every frame on iOS.
		// As the screen framebuffer is the last render target, next SetViewport should be
		// the first call at a frame.
		if f.native == c.screenFramebuffer {
			c.lastViewportWidth = 0
			c.lastViewportHeight = 0
		} else {
			c.lastViewportWidth = f.width
			c.lastViewportHeight = f.height
		}
	}
}

func (c *Context) getScreenFramebuffer() framebufferNative {
	return c.screenFramebuffer
}

func (c *Context) MaxTextureSize() int {
	if c.maxTextureSize == 0 {
		c.maxTextureSize = c.maxTextureSizeImpl()
	}
	return c.maxTextureSize
}
<commit_msg>opengl: Refactoring: Use value type for theContext<commit_after>// Copyright 2016 Hajime Hoshi
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package opengl

import (
	"github.com/hajimehoshi/ebiten/internal/graphics"
)

var (
	vertexShader       shaderType
	fragmentShader     shaderType
	arrayBuffer        bufferType
	elementArrayBuffer bufferType
	dynamicDraw        bufferUsage
	staticDraw         bufferUsage
	Short              DataType
	Float              DataType

	zero             operation
	one              operation
	srcAlpha         operation
	dstAlpha         operation
	oneMinusSrcAlpha operation
	oneMinusDstAlpha operation
)

func convertOperation(op graphics.Operation) operation {
	switch op {
	case graphics.Zero:
		return zero
	case graphics.One:
		return one
	case graphics.SrcAlpha:
		return srcAlpha
	case graphics.DstAlpha:
		return dstAlpha
	case graphics.OneMinusSrcAlpha:
		return oneMinusSrcAlpha
	case graphics.OneMinusDstAlpha:
		return oneMinusDstAlpha
	default:
		panic("not reached")
	}
}

type Context struct {
	locationCache      *locationCache
	screenFramebuffer  framebufferNative // This might not be the default frame buffer '0' (e.g. iOS).
	lastFramebuffer    framebufferNative
	lastTexture        textureNative
	lastViewportWidth  int
	lastViewportHeight int
	lastCompositeMode  graphics.CompositeMode
	maxTextureSize     int
	context
}

var theContext Context

func GetContext() *Context {
	return &theContext
}

func (c *Context) bindTexture(t textureNative) {
	if c.lastTexture == t {
		return
	}
	c.bindTextureImpl(t)
	c.lastTexture = t
}

func (c *Context) bindFramebuffer(f framebufferNative) {
	if c.lastFramebuffer == f {
		return
	}
	c.bindFramebufferImpl(f)
	c.lastFramebuffer = f
}

func (c *Context) setViewport(f *framebuffer) {
	c.bindFramebuffer(f.native)
	if c.lastViewportWidth != f.width || c.lastViewportHeight != f.height {
		c.setViewportImpl(f.width, f.height)
		// glViewport must be called at least at every frame on iOS.
		// As the screen framebuffer is the last render target, next SetViewport should be
		// the first call at a frame.
		if f.native == c.screenFramebuffer {
			c.lastViewportWidth = 0
			c.lastViewportHeight = 0
		} else {
			c.lastViewportWidth = f.width
			c.lastViewportHeight = f.height
		}
	}
}

func (c *Context) getScreenFramebuffer() framebufferNative {
	return c.screenFramebuffer
}

func (c *Context) MaxTextureSize() int {
	if c.maxTextureSize == 0 {
		c.maxTextureSize = c.maxTextureSizeImpl()
	}
	return c.maxTextureSize
}
<|endoftext|>


<commit_before>package overview

import (
	"sync"

	"github.com/pkg/errors"

	"github.com/davecgh/go-spew/spew"
	"github.com/heptio/developer-dash/internal/cluster"
	"github.com/heptio/developer-dash/internal/log"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
	"k8s.io/apimachinery/pkg/runtime/schema"
	"k8s.io/apimachinery/pkg/watch"
)

// StopFunc tells a watch to stop watching a namespace.
type StopFunc func()

// Watch watches a objects in a namespace.
type Watch interface {
	Start() (StopFunc, error)
}

// ClusterWatch watches a namespace's objects.
type ClusterWatch struct {
	clusterClient cluster.ClientInterface
	cache         Cache
	namespace     string
	logger        log.Logger
}

// NewWatch creates an instance of Watch.
func NewWatch(namespace string, clusterClient cluster.ClientInterface, c Cache, logger log.Logger) *ClusterWatch {
	return &ClusterWatch{
		namespace:     namespace,
		clusterClient: clusterClient,
		cache:         c,
		logger:        logger,
	}
}

// Start starts the watch. It returns a stop function and an error.
func (w *ClusterWatch) Start() (StopFunc, error) {
	resources, err := w.resources()
	if err != nil {
		return nil, err
	}

	var watchers []watch.Interface

	for _, resource := range resources {
		dc, err := w.clusterClient.DynamicClient()
		if err != nil {
			return nil, err
		}

		nri := dc.Resource(resource).Namespace(w.namespace)

		watcher, err := nri.Watch(metav1.ListOptions{})
		if err != nil {
			return nil, errors.Wrapf(err, "did not create watcher for %s/%s/%s on %s namespace", resource.Group, resource.Version, resource.Resource, w.namespace)
		}

		watchers = append(watchers, watcher)
	}

	done := make(chan struct{})

	events, shutdownCh := consumeEvents(done, watchers)

	allDone := make(chan interface{})
	wg := sync.WaitGroup{}
	wg.Add(2)
	go func() {
		// Forward events to handler.
		// Exits after all watchers are stopped in consumeEvents.
		for event := range events {
			w.eventHandler(event)
		}
		wg.Done()
	}()

	go func() {
		// Block until all watch consumers have finished (in consumeEvents)
		<-shutdownCh
		wg.Done()
	}()

	go func() {
		// Block until fan-in consumer as well as individual watch consumers have completed
		// (above two goroutines)
		wg.Wait()
		close(allDone)
	}()

	stopFn := func() {
		// Signal consumer routines to shutdown. Block until all have finished.
		done <- struct{}{}
		<-allDone
	}

	return stopFn, nil
}

func (w *ClusterWatch) eventHandler(event watch.Event) {
	u, ok := event.Object.(*unstructured.Unstructured)
	if !ok {
		return
	}

	switch t := event.Type; t {
	case watch.Added:
		if err := w.cache.Store(u); err != nil {
			w.logger.Errorf("store object: %v", err)
		}
	case watch.Modified:
		if err := w.cache.Store(u); err != nil {
			w.logger.Errorf("store object: %v", err)
		}
	case watch.Deleted:
		if err := w.cache.Delete(u); err != nil {
			w.logger.Errorf("store object: %v", err)
		}
	case watch.Error:
		w.logger.Errorf("unknown log err: %s", spew.Sdump(event))
	default:
		w.logger.Errorf("unknown event %q", t)
	}
}

func (w *ClusterWatch) resources() ([]schema.GroupVersionResource, error) {
	discoveryClient, err := w.clusterClient.DiscoveryClient()
	if err != nil {
		return nil, err
	}

	// NOTE we may want ServerPreferredResources, but FakeDiscovery does not support it.
	lists, err := discoveryClient.ServerResources()
	if err != nil {
		return nil, err
	}

	var gvrs []schema.GroupVersionResource

	for _, list := range lists {
		gv, err := schema.ParseGroupVersion(list.GroupVersion)
		if err != nil {
			return nil, err
		}

		for _, res := range list.APIResources {
			if !res.Namespaced {
				continue
			}
			if isWatchable(res) {

				gvr := schema.GroupVersionResource{
					Group:    gv.Group,
					Version:  gv.Version,
					Resource: res.Name,
				}

				gvrs = append(gvrs, gvr)

			}
		}
	}

	return gvrs, nil
}

func isWatchable(res metav1.APIResource) bool {
	m := make(map[string]bool)

	for _, v := range res.Verbs {
		m[v] = true
	}

	return m["list"] && m["watch"]
}

// consumeEvents performs fan-in of events from multiple watchers into a single event channel.
// This continues until a message is sent on the provided done channel.
func consumeEvents(done <-chan struct{}, watchers []watch.Interface) (chan watch.Event, chan struct{}) {
	var wg sync.WaitGroup

	wg.Add(len(watchers))

	events := make(chan watch.Event)

	shutdownComplete := make(chan struct{})

	for _, watcher := range watchers {
		// Forward events from each watcher to events channel.
		// Each drainer goroutine ends when its watcher's Stop() method is called,
		// which will have the effect of closing its ResultChan and exiting the range loop.
		go func(watcher watch.Interface) {
			for event := range watcher.ResultChan() {
				events <- event
			}
			wg.Done()
		}(watcher)
	}

	go func() {
		// wait for caller to signal done and
		// start shutting the watcher down
		<-done
		for _, watch := range watchers {
			watch.Stop()
		}
	}()

	go func() {
		// wait for all watchers to exit.
		wg.Wait()
		close(events)
		shutdownComplete <- struct{}{}
	}()

	return events, shutdownComplete
}
<commit_msg>Encapsulate WaitGroup with the goroutines being synchronized<commit_after>package overview

import (
	"sync"

	"github.com/pkg/errors"

	"github.com/davecgh/go-spew/spew"
	"github.com/heptio/developer-dash/internal/cluster"
	"github.com/heptio/developer-dash/internal/log"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
	"k8s.io/apimachinery/pkg/runtime/schema"
	"k8s.io/apimachinery/pkg/watch"
)

// StopFunc tells a watch to stop watching a namespace.
type StopFunc func()

// Watch watches a objects in a namespace.
type Watch interface {
	Start() (StopFunc, error)
}

// ClusterWatch watches a namespace's objects.
type ClusterWatch struct {
	clusterClient cluster.ClientInterface
	cache         Cache
	namespace     string
	logger        log.Logger
}

// NewWatch creates an instance of Watch.
func NewWatch(namespace string, clusterClient cluster.ClientInterface, c Cache, logger log.Logger) *ClusterWatch {
	return &ClusterWatch{
		namespace:     namespace,
		clusterClient: clusterClient,
		cache:         c,
		logger:        logger,
	}
}

// Start starts the watch. It returns a stop function and an error.
func (w *ClusterWatch) Start() (StopFunc, error) {
	resources, err := w.resources()
	if err != nil {
		return nil, err
	}

	var watchers []watch.Interface

	for _, resource := range resources {
		dc, err := w.clusterClient.DynamicClient()
		if err != nil {
			return nil, err
		}

		nri := dc.Resource(resource).Namespace(w.namespace)

		watcher, err := nri.Watch(metav1.ListOptions{})
		if err != nil {
			return nil, errors.Wrapf(err, "did not create watcher for %s/%s/%s on %s namespace", resource.Group, resource.Version, resource.Resource, w.namespace)
		}

		watchers = append(watchers, watcher)
	}

	done := make(chan struct{})

	events, shutdownCh := consumeEvents(done, watchers)

	allDone := make(chan interface{})

	go func() {
		wg := sync.WaitGroup{}
		wg.Add(2)
		go func() {
			// Forward events to handler.
			// Exits after all watchers are stopped in consumeEvents.
			for event := range events {
				w.eventHandler(event)
			}
			wg.Done()
		}()

		go func() {
			// Block until all watch consumers have finished (in consumeEvents)
			<-shutdownCh
			wg.Done()
		}()

		// Block until fan-in consumer as well as individual watch consumers have completed
		// (above two goroutines)
		wg.Wait()
		close(allDone)
	}()

	stopFn := func() {
		// Signal consumer routines to shutdown. Block until all have finished.
		done <- struct{}{}
		<-allDone
	}

	return stopFn, nil
}

func (w *ClusterWatch) eventHandler(event watch.Event) {
	u, ok := event.Object.(*unstructured.Unstructured)
	if !ok {
		return
	}

	switch t := event.Type; t {
	case watch.Added:
		if err := w.cache.Store(u); err != nil {
			w.logger.Errorf("store object: %v", err)
		}
	case watch.Modified:
		if err := w.cache.Store(u); err != nil {
			w.logger.Errorf("store object: %v", err)
		}
	case watch.Deleted:
		if err := w.cache.Delete(u); err != nil {
			w.logger.Errorf("store object: %v", err)
		}
	case watch.Error:
		w.logger.Errorf("unknown log err: %s", spew.Sdump(event))
	default:
		w.logger.Errorf("unknown event %q", t)
	}
}

func (w *ClusterWatch) resources() ([]schema.GroupVersionResource, error) {
	discoveryClient, err := w.clusterClient.DiscoveryClient()
	if err != nil {
		return nil, err
	}

	// NOTE we may want ServerPreferredResources, but FakeDiscovery does not support it.
	lists, err := discoveryClient.ServerResources()
	if err != nil {
		return nil, err
	}

	var gvrs []schema.GroupVersionResource

	for _, list := range lists {
		gv, err := schema.ParseGroupVersion(list.GroupVersion)
		if err != nil {
			return nil, err
		}

		for _, res := range list.APIResources {
			if !res.Namespaced {
				continue
			}
			if isWatchable(res) {

				gvr := schema.GroupVersionResource{
					Group:    gv.Group,
					Version:  gv.Version,
					Resource: res.Name,
				}

				gvrs = append(gvrs, gvr)

			}
		}
	}

	return gvrs, nil
}

func isWatchable(res metav1.APIResource) bool {
	m := make(map[string]bool)

	for _, v := range res.Verbs {
		m[v] = true
	}

	return m["list"] && m["watch"]
}

// consumeEvents performs fan-in of events from multiple watchers into a single event channel.
// This continues until a message is sent on the provided done channel.
func consumeEvents(done <-chan struct{}, watchers []watch.Interface) (chan watch.Event, chan struct{}) {
	var wg sync.WaitGroup

	wg.Add(len(watchers))

	events := make(chan watch.Event)

	shutdownComplete := make(chan struct{})

	for _, watcher := range watchers {
		// Forward events from each watcher to events channel.
		// Each drainer goroutine ends when its watcher's Stop() method is called,
		// which will have the effect of closing its ResultChan and exiting the range loop.
		go func(watcher watch.Interface) {
			for event := range watcher.ResultChan() {
				events <- event
			}
			wg.Done()
		}(watcher)
	}

	go func() {
		// wait for caller to signal done and
		// start shutting the watcher down
		<-done
		for _, watch := range watchers {
			watch.Stop()
		}
	}()

	go func() {
		// wait for all watchers to exit.
		wg.Wait()
		close(events)
		shutdownComplete <- struct{}{}
	}()

	return events, shutdownComplete
}
<|endoftext|>


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

package testdata

import "math/rand"

const (
	Small = 32
	Large = 64 * 1024
)

func Seq(start, stop, skip int) []int {
	n := (stop - start) / skip
	s := make([]int, n)
	for i := range s {
		s[i] = (start + i) * skip
	}
	return s
}

func Interleave(n, k int) [][]int {
	l := n * k
	sets := make([][]int, n)
	for i := range sets {
		sets[i] = Seq(i, i+l, n)
	}
	return sets
}

func Concat(n, k, gap int) [][]int {
	l := k + gap
	sets := make([][]int, n)
	for i := range sets {
		start := i * l
		sets[i] = Seq(start, start+l, 1)
	}
	return sets
}

func Reverse(sets [][]int) [][]int {
	n := len(sets)
	for i := range sets[:n/2] {
		j := n - i - 1
		sets[i], sets[j] = sets[j], sets[i]
	}
	return sets
}

func RevCat(n int, size int) [][]int {
	// union, inter: requires most Swap calls, fewest Less calls
	return Reverse(Concat(n, size, 0))
}

func Alternate(n int, size int) [][]int {
	// union, inter: requires ~most Swap calls, most Less calls
	return Interleave(n, size)
}

func Overlap(n int, size int) [][]int {
	return Concat(n, size, -size/2)
}

func Rand(n int, size int) [][]int {
	rand.Seed(0)
	sets := make([][]int, n)
	for i := range sets {
		start, l := rand.Intn(size), rand.Intn(size)+1
		stop := start + l
		sets[i] = Seq(start, stop, 1)
	}
	return sets
}
<commit_msg>Fixed benchmark data generation.<commit_after>// Copyright 2015 Kevin Gillette. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package testdata

import "math/rand"

const (
	Small = 32
	Large = 64 * 1024
)

func Seq(start, stop, skip int) []int {
	n := (stop - start) / skip
	s := make([]int, n)
	for i := range s {
		s[i] = start + (i * skip)
	}
	return s
}

func Interleave(n, k int) [][]int {
	l := n * k
	sets := make([][]int, n)
	for i := range sets {
		sets[i] = Seq(i, i+l, n)
	}
	return sets
}

func Concat(n, k, gap int) [][]int {
	l := k + gap
	sets := make([][]int, n)
	for i := range sets {
		start := i * l
		sets[i] = Seq(start, start+k, 1)
	}
	return sets
}

func Reverse(sets [][]int) [][]int {
	n := len(sets)
	for i := range sets[:n/2] {
		j := n - i - 1
		sets[i], sets[j] = sets[j], sets[i]
	}
	return sets
}

func RevCat(n int, size int) [][]int {
	// union, inter: requires most Swap calls, fewest Less calls
	return Reverse(Concat(n, size, 0))
}

func Alternate(n int, size int) [][]int {
	// union, inter: requires ~most Swap calls, most Less calls
	return Interleave(n, size)
}

func Overlap(n int, size int) [][]int {
	return Concat(n, size, -size/2)
}

func Rand(n int, size int) [][]int {
	rand.Seed(0)
	sets := make([][]int, n)
	for i := range sets {
		start, l := rand.Intn(size), rand.Intn(size)+1
		stop := start + l
		sets[i] = Seq(start, stop, 1)
	}
	return sets
}
<|endoftext|>


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

package testing

import (
	"go/constant"

	"github.com/hajimehoshi/ebiten/internal/graphics"
	"github.com/hajimehoshi/ebiten/internal/shaderir"
)

var (
	projectionMatrix = shaderir.Expr{
		Type: shaderir.Call,
		Exprs: []shaderir.Expr{
			{
				Type:        shaderir.BuiltinFuncExpr,
				BuiltinFunc: shaderir.Mat4F,
			},
			{
				Type: shaderir.Binary,
				Op:   shaderir.Div,
				Exprs: []shaderir.Expr{
					{
						Type:      shaderir.NumberExpr,
						Const:     constant.MakeFloat64(2),
						ConstType: shaderir.ConstTypeFloat,
					},
					{
						Type: shaderir.FieldSelector,
						Exprs: []shaderir.Expr{
							{
								Type:  shaderir.UniformVariable,
								Index: 0,
							},
							{
								Type:      shaderir.SwizzlingExpr,
								Swizzling: "x",
							},
						},
					},
				},
			},
			{
				Type:      shaderir.NumberExpr,
				Const:     constant.MakeFloat64(0),
				ConstType: shaderir.ConstTypeFloat,
			},
			{
				Type:      shaderir.NumberExpr,
				Const:     constant.MakeFloat64(0),
				ConstType: shaderir.ConstTypeFloat,
			},
			{
				Type:      shaderir.NumberExpr,
				Const:     constant.MakeFloat64(0),
				ConstType: shaderir.ConstTypeFloat,
			},
			{
				Type:      shaderir.NumberExpr,
				Const:     constant.MakeFloat64(0),
				ConstType: shaderir.ConstTypeFloat,
			},
			{
				Type: shaderir.Binary,
				Op:   shaderir.Div,
				Exprs: []shaderir.Expr{
					{
						Type:      shaderir.NumberExpr,
						Const:     constant.MakeFloat64(2),
						ConstType: shaderir.ConstTypeFloat,
					},
					{
						Type: shaderir.FieldSelector,
						Exprs: []shaderir.Expr{
							{
								Type:  shaderir.UniformVariable,
								Index: 0,
							},
							{
								Type:      shaderir.SwizzlingExpr,
								Swizzling: "y",
							},
						},
					},
				},
			},
			{
				Type:      shaderir.NumberExpr,
				Const:     constant.MakeFloat64(0),
				ConstType: shaderir.ConstTypeFloat,
			},
			{
				Type:      shaderir.NumberExpr,
				Const:     constant.MakeFloat64(0),
				ConstType: shaderir.ConstTypeFloat,
			},
			{
				Type:      shaderir.NumberExpr,
				Const:     constant.MakeFloat64(0),
				ConstType: shaderir.ConstTypeFloat,
			},
			{
				Type:      shaderir.NumberExpr,
				Const:     constant.MakeFloat64(0),
				ConstType: shaderir.ConstTypeFloat,
			},
			{
				Type:      shaderir.NumberExpr,
				Const:     constant.MakeFloat64(1),
				ConstType: shaderir.ConstTypeFloat,
			},
			{
				Type:      shaderir.NumberExpr,
				Const:     constant.MakeFloat64(0),
				ConstType: shaderir.ConstTypeFloat,
			},
			{
				Type:      shaderir.NumberExpr,
				Const:     constant.MakeFloat64(-1),
				ConstType: shaderir.ConstTypeFloat,
			},
			{
				Type:      shaderir.NumberExpr,
				Const:     constant.MakeFloat64(-1),
				ConstType: shaderir.ConstTypeFloat,
			},
			{
				Type:      shaderir.NumberExpr,
				Const:     constant.MakeFloat64(0),
				ConstType: shaderir.ConstTypeFloat,
			},
			{
				Type:      shaderir.NumberExpr,
				Const:     constant.MakeFloat64(1),
				ConstType: shaderir.ConstTypeFloat,
			},
		},
	}
	vertexPosition = shaderir.Expr{
		Type: shaderir.Call,
		Exprs: []shaderir.Expr{
			{
				Type:        shaderir.BuiltinFuncExpr,
				BuiltinFunc: shaderir.Vec4F,
			},
			{
				Type:  shaderir.LocalVariable,
				Index: 0,
			},
			{
				Type:      shaderir.NumberExpr,
				Const:     constant.MakeFloat64(0),
				ConstType: shaderir.ConstTypeFloat,
			},
			{
				Type:      shaderir.NumberExpr,
				Const:     constant.MakeFloat64(1),
				ConstType: shaderir.ConstTypeFloat,
			},
		},
	}
	defaultVertexFunc = shaderir.VertexFunc{
		Block: shaderir.Block{
			Stmts: []shaderir.Stmt{
				{
					Type: shaderir.Assign,
					Exprs: []shaderir.Expr{
						{
							Type:  shaderir.LocalVariable,
							Index: 5, // the varying variable
						},
						{
							Type:  shaderir.LocalVariable,
							Index: 1, // the 2nd attribute variable
						},
					},
				},
				{
					Type: shaderir.Assign,
					Exprs: []shaderir.Expr{
						{
							Type:  shaderir.LocalVariable,
							Index: 4, // gl_Position in GLSL
						},
						{
							Type: shaderir.Binary,
							Op:   shaderir.Mul,
							Exprs: []shaderir.Expr{
								projectionMatrix,
								vertexPosition,
							},
						},
					},
				},
			},
		},
	}
)

func defaultProgram() shaderir.Program {
	p := shaderir.Program{
		Attributes: []shaderir.Type{
			{Main: shaderir.Vec2}, // Local var (0) in the vertex shader
			{Main: shaderir.Vec2}, // Local var (1) in the vertex shader
			{Main: shaderir.Vec4}, // Local var (2) in the vertex shader
			{Main: shaderir.Vec4}, // Local var (3) in the vertex shader
		},
		Varyings: []shaderir.Type{
			{Main: shaderir.Vec2}, // Local var (4) in the vertex shader, (0) in the fragment shader
		},
		VertexFunc: defaultVertexFunc,
	}

	p.Uniforms = make([]shaderir.Type, graphics.PreservedUniformVariablesNum)
	// Destination texture size
	p.Uniforms[0] = shaderir.Type{Main: shaderir.Vec2}
	// Source texture sizes
	p.Uniforms[1] = shaderir.Type{
		Main:   shaderir.Array,
		Length: graphics.ShaderImageNum,
		Sub:    []shaderir.Type{{Main: shaderir.Vec2}},
	}
	// Source texture offsets
	p.Uniforms[2] = shaderir.Type{
		Main:   shaderir.Array,
		Length: graphics.ShaderImageNum - 1,
		Sub:    []shaderir.Type{{Main: shaderir.Vec2}},
	}
	return p
}

// ShaderProgramFill returns a shader intermediate representation to fill the frambuffer.
//
// Uniform variable's index and its value are:
//
//   0: the framebuffer size (Vec2)
func ShaderProgramFill(r, g, b, a byte) shaderir.Program {
	clr := shaderir.Expr{
		Type: shaderir.Call,
		Exprs: []shaderir.Expr{
			{
				Type:        shaderir.BuiltinFuncExpr,
				BuiltinFunc: shaderir.Vec4F,
			},
			{
				Type:      shaderir.NumberExpr,
				Const:     constant.MakeFloat64(float64(r) / 0xff),
				ConstType: shaderir.ConstTypeFloat,
			},
			{
				Type:      shaderir.NumberExpr,
				Const:     constant.MakeFloat64(float64(g) / 0xff),
				ConstType: shaderir.ConstTypeFloat,
			},
			{
				Type:      shaderir.NumberExpr,
				Const:     constant.MakeFloat64(float64(b) / 0xff),
				ConstType: shaderir.ConstTypeFloat,
			},
			{
				Type:      shaderir.NumberExpr,
				Const:     constant.MakeFloat64(float64(a) / 0xff),
				ConstType: shaderir.ConstTypeFloat,
			},
		},
	}

	p := defaultProgram()
	p.FragmentFunc = shaderir.FragmentFunc{
		Block: shaderir.Block{
			Stmts: []shaderir.Stmt{
				{
					Type: shaderir.Assign,
					Exprs: []shaderir.Expr{
						{
							Type:  shaderir.LocalVariable,
							Index: 2,
						},
						clr,
					},
				},
			},
		},
	}

	return p
}

// ShaderProgramImages returns a shader intermediate representation to render the frambuffer with the given images.
//
// Uniform variables's indices and their values are:
//
//   0:  the framebuffer size (Vec2)
//
// The first image's size and region are represented in attribute variables.
//
// The size and region values are actually not used in this shader so far.
func ShaderProgramImages(imageNum int) shaderir.Program {
	if imageNum <= 0 {
		panic("testing: imageNum must be >= 1")
	}

	p := defaultProgram()
	p.TextureNum = imageNum

	// In the fragment shader, local variables are:
	//
	//   0: gl_FragCoord
	//   1: Varying variables (vec2)
	//   2: gl_FragColor
	//   3: Actual local variables in the main function

	local := shaderir.Expr{
		Type:  shaderir.LocalVariable,
		Index: 3,
	}
	fragColor := shaderir.Expr{
		Type:  shaderir.LocalVariable,
		Index: 2,
	}
	texPos := shaderir.Expr{
		Type:  shaderir.LocalVariable,
		Index: 1,
	}

	var stmts []shaderir.Stmt
	for i := 0; i < imageNum; i++ {
		var rhs shaderir.Expr
		if i == 0 {
			rhs = shaderir.Expr{
				Type: shaderir.Call,
				Exprs: []shaderir.Expr{
					{
						Type:        shaderir.BuiltinFuncExpr,
						BuiltinFunc: shaderir.Texture2DF,
					},
					{
						Type:  shaderir.TextureVariable,
						Index: 0,
					},
					texPos,
				},
			}
		} else {
			texPos2 := shaderir.Expr{
				Type: shaderir.Binary,
				Op:   shaderir.Add,
				Exprs: []shaderir.Expr{
					texPos,
					{
						Type: shaderir.Index,
						Exprs: []shaderir.Expr{
							{
								Type:  shaderir.UniformVariable,
								Index: graphics.TextureOffsetsUniformVariableIndex,
							},
							{
								Type:      shaderir.NumberExpr,
								Const:     constant.MakeInt64(int64(i - 1)),
								ConstType: shaderir.ConstTypeInt,
							},
						},
					},
				},
			}
			rhs = shaderir.Expr{
				Type: shaderir.Binary,
				Op:   shaderir.Add,
				Exprs: []shaderir.Expr{
					local,
					{
						Type: shaderir.Call,
						Exprs: []shaderir.Expr{
							{
								Type:        shaderir.BuiltinFuncExpr,
								BuiltinFunc: shaderir.Texture2DF,
							},
							{
								Type:  shaderir.TextureVariable,
								Index: i,
							},
							texPos2,
						},
					},
				},
			}
		}
		stmts = append(stmts, shaderir.Stmt{
			Type: shaderir.Assign,
			Exprs: []shaderir.Expr{
				local,
				rhs,
			},
		})
	}

	stmts = append(stmts, shaderir.Stmt{
		Type: shaderir.Assign,
		Exprs: []shaderir.Expr{
			fragColor,
			local,
		},
	})

	p.FragmentFunc = shaderir.FragmentFunc{
		Block: shaderir.Block{
			LocalVars: []shaderir.Type{
				{Main: shaderir.Vec4},
			},
			Stmts: stmts,
		},
	}

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

package testing

import (
	"go/constant"

	"github.com/hajimehoshi/ebiten/internal/graphics"
	"github.com/hajimehoshi/ebiten/internal/shaderir"
)

var (
	projectionMatrix = shaderir.Expr{
		Type: shaderir.Call,
		Exprs: []shaderir.Expr{
			{
				Type:        shaderir.BuiltinFuncExpr,
				BuiltinFunc: shaderir.Mat4F,
			},
			{
				Type: shaderir.Binary,
				Op:   shaderir.Div,
				Exprs: []shaderir.Expr{
					{
						Type:      shaderir.NumberExpr,
						Const:     constant.MakeFloat64(2),
						ConstType: shaderir.ConstTypeFloat,
					},
					{
						Type: shaderir.FieldSelector,
						Exprs: []shaderir.Expr{
							{
								Type:  shaderir.UniformVariable,
								Index: 0,
							},
							{
								Type:      shaderir.SwizzlingExpr,
								Swizzling: "x",
							},
						},
					},
				},
			},
			{
				Type:      shaderir.NumberExpr,
				Const:     constant.MakeFloat64(0),
				ConstType: shaderir.ConstTypeFloat,
			},
			{
				Type:      shaderir.NumberExpr,
				Const:     constant.MakeFloat64(0),
				ConstType: shaderir.ConstTypeFloat,
			},
			{
				Type:      shaderir.NumberExpr,
				Const:     constant.MakeFloat64(0),
				ConstType: shaderir.ConstTypeFloat,
			},
			{
				Type:      shaderir.NumberExpr,
				Const:     constant.MakeFloat64(0),
				ConstType: shaderir.ConstTypeFloat,
			},
			{
				Type: shaderir.Binary,
				Op:   shaderir.Div,
				Exprs: []shaderir.Expr{
					{
						Type:      shaderir.NumberExpr,
						Const:     constant.MakeFloat64(2),
						ConstType: shaderir.ConstTypeFloat,
					},
					{
						Type: shaderir.FieldSelector,
						Exprs: []shaderir.Expr{
							{
								Type:  shaderir.UniformVariable,
								Index: 0,
							},
							{
								Type:      shaderir.SwizzlingExpr,
								Swizzling: "y",
							},
						},
					},
				},
			},
			{
				Type:      shaderir.NumberExpr,
				Const:     constant.MakeFloat64(0),
				ConstType: shaderir.ConstTypeFloat,
			},
			{
				Type:      shaderir.NumberExpr,
				Const:     constant.MakeFloat64(0),
				ConstType: shaderir.ConstTypeFloat,
			},
			{
				Type:      shaderir.NumberExpr,
				Const:     constant.MakeFloat64(0),
				ConstType: shaderir.ConstTypeFloat,
			},
			{
				Type:      shaderir.NumberExpr,
				Const:     constant.MakeFloat64(0),
				ConstType: shaderir.ConstTypeFloat,
			},
			{
				Type:      shaderir.NumberExpr,
				Const:     constant.MakeFloat64(1),
				ConstType: shaderir.ConstTypeFloat,
			},
			{
				Type:      shaderir.NumberExpr,
				Const:     constant.MakeFloat64(0),
				ConstType: shaderir.ConstTypeFloat,
			},
			{
				Type:      shaderir.NumberExpr,
				Const:     constant.MakeFloat64(-1),
				ConstType: shaderir.ConstTypeFloat,
			},
			{
				Type:      shaderir.NumberExpr,
				Const:     constant.MakeFloat64(-1),
				ConstType: shaderir.ConstTypeFloat,
			},
			{
				Type:      shaderir.NumberExpr,
				Const:     constant.MakeFloat64(0),
				ConstType: shaderir.ConstTypeFloat,
			},
			{
				Type:      shaderir.NumberExpr,
				Const:     constant.MakeFloat64(1),
				ConstType: shaderir.ConstTypeFloat,
			},
		},
	}
	vertexPosition = shaderir.Expr{
		Type: shaderir.Call,
		Exprs: []shaderir.Expr{
			{
				Type:        shaderir.BuiltinFuncExpr,
				BuiltinFunc: shaderir.Vec4F,
			},
			{
				Type:  shaderir.LocalVariable,
				Index: 0,
			},
			{
				Type:      shaderir.NumberExpr,
				Const:     constant.MakeFloat64(0),
				ConstType: shaderir.ConstTypeFloat,
			},
			{
				Type:      shaderir.NumberExpr,
				Const:     constant.MakeFloat64(1),
				ConstType: shaderir.ConstTypeFloat,
			},
		},
	}
	defaultVertexFunc = shaderir.VertexFunc{
		Block: shaderir.Block{
			Stmts: []shaderir.Stmt{
				{
					Type: shaderir.Assign,
					Exprs: []shaderir.Expr{
						{
							Type:  shaderir.LocalVariable,
							Index: 5, // the varying variable
						},
						{
							Type:  shaderir.LocalVariable,
							Index: 1, // the 2nd attribute variable
						},
					},
				},
				{
					Type: shaderir.Assign,
					Exprs: []shaderir.Expr{
						{
							Type:  shaderir.LocalVariable,
							Index: 4, // gl_Position in GLSL
						},
						{
							Type: shaderir.Binary,
							Op:   shaderir.Mul,
							Exprs: []shaderir.Expr{
								projectionMatrix,
								vertexPosition,
							},
						},
					},
				},
			},
		},
	}
)

func defaultProgram() shaderir.Program {
	p := shaderir.Program{
		Attributes: []shaderir.Type{
			{Main: shaderir.Vec2}, // Local var (0) in the vertex shader
			{Main: shaderir.Vec2}, // Local var (1) in the vertex shader
			{Main: shaderir.Vec4}, // Local var (2) in the vertex shader
			{Main: shaderir.Vec4}, // Local var (3) in the vertex shader
		},
		Varyings: []shaderir.Type{
			{Main: shaderir.Vec2}, // Local var (4) in the vertex shader, (1) in the fragment shader
		},
		VertexFunc: defaultVertexFunc,
	}

	p.Uniforms = make([]shaderir.Type, graphics.PreservedUniformVariablesNum)
	// Destination texture size
	p.Uniforms[0] = shaderir.Type{Main: shaderir.Vec2}
	// Source texture sizes
	p.Uniforms[1] = shaderir.Type{
		Main:   shaderir.Array,
		Length: graphics.ShaderImageNum,
		Sub:    []shaderir.Type{{Main: shaderir.Vec2}},
	}
	// Source texture offsets
	p.Uniforms[2] = shaderir.Type{
		Main:   shaderir.Array,
		Length: graphics.ShaderImageNum - 1,
		Sub:    []shaderir.Type{{Main: shaderir.Vec2}},
	}
	return p
}

// ShaderProgramFill returns a shader intermediate representation to fill the frambuffer.
//
// Uniform variable's index and its value are:
//
//   0: the framebuffer size (Vec2)
func ShaderProgramFill(r, g, b, a byte) shaderir.Program {
	clr := shaderir.Expr{
		Type: shaderir.Call,
		Exprs: []shaderir.Expr{
			{
				Type:        shaderir.BuiltinFuncExpr,
				BuiltinFunc: shaderir.Vec4F,
			},
			{
				Type:      shaderir.NumberExpr,
				Const:     constant.MakeFloat64(float64(r) / 0xff),
				ConstType: shaderir.ConstTypeFloat,
			},
			{
				Type:      shaderir.NumberExpr,
				Const:     constant.MakeFloat64(float64(g) / 0xff),
				ConstType: shaderir.ConstTypeFloat,
			},
			{
				Type:      shaderir.NumberExpr,
				Const:     constant.MakeFloat64(float64(b) / 0xff),
				ConstType: shaderir.ConstTypeFloat,
			},
			{
				Type:      shaderir.NumberExpr,
				Const:     constant.MakeFloat64(float64(a) / 0xff),
				ConstType: shaderir.ConstTypeFloat,
			},
		},
	}

	p := defaultProgram()
	p.FragmentFunc = shaderir.FragmentFunc{
		Block: shaderir.Block{
			Stmts: []shaderir.Stmt{
				{
					Type: shaderir.Assign,
					Exprs: []shaderir.Expr{
						{
							Type:  shaderir.LocalVariable,
							Index: 2,
						},
						clr,
					},
				},
			},
		},
	}

	return p
}

// ShaderProgramImages returns a shader intermediate representation to render the frambuffer with the given images.
//
// Uniform variables's indices and their values are:
//
//   0:  the framebuffer size (Vec2)
//
// The first image's size and region are represented in attribute variables.
//
// The size and region values are actually not used in this shader so far.
func ShaderProgramImages(imageNum int) shaderir.Program {
	if imageNum <= 0 {
		panic("testing: imageNum must be >= 1")
	}

	p := defaultProgram()
	p.TextureNum = imageNum

	// In the fragment shader, local variables are:
	//
	//   0: gl_FragCoord
	//   1: Varying variables (vec2)
	//   2: gl_FragColor
	//   3: Actual local variables in the main function

	local := shaderir.Expr{
		Type:  shaderir.LocalVariable,
		Index: 3,
	}
	fragColor := shaderir.Expr{
		Type:  shaderir.LocalVariable,
		Index: 2,
	}
	texPos := shaderir.Expr{
		Type:  shaderir.LocalVariable,
		Index: 1,
	}

	var stmts []shaderir.Stmt
	for i := 0; i < imageNum; i++ {
		var rhs shaderir.Expr
		if i == 0 {
			rhs = shaderir.Expr{
				Type: shaderir.Call,
				Exprs: []shaderir.Expr{
					{
						Type:        shaderir.BuiltinFuncExpr,
						BuiltinFunc: shaderir.Texture2DF,
					},
					{
						Type:  shaderir.TextureVariable,
						Index: 0,
					},
					texPos,
				},
			}
		} else {
			texPos2 := shaderir.Expr{
				Type: shaderir.Binary,
				Op:   shaderir.Add,
				Exprs: []shaderir.Expr{
					texPos,
					{
						Type: shaderir.Index,
						Exprs: []shaderir.Expr{
							{
								Type:  shaderir.UniformVariable,
								Index: graphics.TextureOffsetsUniformVariableIndex,
							},
							{
								Type:      shaderir.NumberExpr,
								Const:     constant.MakeInt64(int64(i - 1)),
								ConstType: shaderir.ConstTypeInt,
							},
						},
					},
				},
			}
			rhs = shaderir.Expr{
				Type: shaderir.Binary,
				Op:   shaderir.Add,
				Exprs: []shaderir.Expr{
					local,
					{
						Type: shaderir.Call,
						Exprs: []shaderir.Expr{
							{
								Type:        shaderir.BuiltinFuncExpr,
								BuiltinFunc: shaderir.Texture2DF,
							},
							{
								Type:  shaderir.TextureVariable,
								Index: i,
							},
							texPos2,
						},
					},
				},
			}
		}
		stmts = append(stmts, shaderir.Stmt{
			Type: shaderir.Assign,
			Exprs: []shaderir.Expr{
				local,
				rhs,
			},
		})
	}

	stmts = append(stmts, shaderir.Stmt{
		Type: shaderir.Assign,
		Exprs: []shaderir.Expr{
			fragColor,
			local,
		},
	})

	p.FragmentFunc = shaderir.FragmentFunc{
		Block: shaderir.Block{
			LocalVars: []shaderir.Type{
				{Main: shaderir.Vec4},
			},
			Stmts: stmts,
		},
	}

	return p
}
<|endoftext|>