<commit_before>package main

import "fmt"
import "io"
import "net/http"
import "os"
import "path/filepath"
import "regexp"
import "runtime"
import "sort"
import "strings"
import "github.com/google/go-github/github"
import "github.com/codegangsta/cli"
import "github.com/kardianos/osext"

var shell string
var dvmDir string
var debug bool
var silent bool

func main() {
  app := cli.NewApp()
  app.Name = "Docker Version Manager"
  app.Usage = "Manage multiple versions of the Docker client"
  app.EnableBashCompletion = true
  app.Flags = []cli.Flag{
    cli.StringFlag { Name: "dvm-dir", EnvVar: "DVM_DIR", Usage: "Specify an alternate DVM home directory, defaults to the current directory." },
    cli.StringFlag { Name: "shell", EnvVar: "SHELL", Usage: "Specify the shell format in which environment variables should be output, e.g. powershell, cmd or sh/bash. Defaults to sh/bash."},
    cli.BoolFlag { Name: "debug", Usage: "Print additional debug information." },
    cli.BoolFlag{ Name: "silent", EnvVar: "DVM_SILENT", Usage: "Suppress output. Errors will still be displayed."},
  }
  app.Commands = []cli.Command{
    {
      Name:    "install",
      Aliases: []string{"i"},
      Usage:   "dvm install <version>. Uses $DOCKER_VERSION if available",
      Action: func(c *cli.Context) {
        setGlobalVars(c)
        install(c.Args().First())
      },
    },
    {
      Name:    "use",
      Usage:   "dvm use <version>. Uses $DOCKER_VERSION if available",
      Action: func(c *cli.Context) {
        setGlobalVars(c)
        use(c.Args().First())
      },
    },
    {
      Name: "list-remote",
      Aliases: []string{"ls-remote"},
      Usage: "dvm list-remote [<pattern>]",
      Action: func(c *cli.Context) {
        setGlobalVars(c)
        listRemote(c.Args().First())
      },
    },
  }

  app.Run(os.Args)
}

func setGlobalVars(c *cli.Context) {
  debug = c.GlobalBool("debug")
  shell = c.GlobalString("shell")
  silent = c.GlobalBool("silent")
  dvmDir = c.GlobalString("dvm-dir")
  if dvmDir == "" {
    var err error
    dvmDir, err = osext.ExecutableFolder()
    if err != nil {
      fmt.Fprintln(os.Stderr, "Unable to determine DVM home directory")
      os.Exit(1)
    }
  }
}

func install(version string) {
  if version == "" {
    version = os.Getenv("DOCKER_VERSION")
  }

  if version == "" {
    fmt.Fprintln(os.Stderr, "The install command requires that a version is specified or the DOCKER_VERSION environment variable is set")
    os.Exit(127)
  }

  if !versionExists(version) {
    fmt.Fprintf(os.Stderr, "Version %s not found - try `dvm ls-remote` to browse available versions.\n", version)
    os.Exit(3)
  }

  versionDir := getVersionDir(version)

  // TODO: Support experimental

  if _, err := os.Stat(versionDir); err == nil {
    if !silent { fmt.Fprintf(os.Stderr, "%s is already installed\n", version) }
    use(version)
    return
  }

  if !silent { fmt.Printf("Installing %s\n", version) }

  url := fmt.Sprintf("https://get.docker.com/builds/%s/%s/%s", getDockerOS(), getDockerArch(), getDockerBinaryName(version))
  tmpPath := filepath.Join(getDvmDir(), ".tmp/docker", version, getBinaryName())
  downloadFile(url, tmpPath)
  binaryPath := filepath.Join(getDvmDir(), "bin/docker", version, getBinaryName())
  ensureParentDirectoryExists(binaryPath)
  err := os.Rename(tmpPath, binaryPath)
  if err != nil {
    fmt.Fprintf(os.Stderr, "Unable to copy %s to %s.\n%s\n", tmpPath, binaryPath, err)
  }

  if debug {
    fmt.Printf("Installed Docker %s to %s", version, binaryPath)
  }
}

func use(version string) {
  if version == "" {
    version = os.Getenv("DOCKER_VERSION")
  }

  if version == "" {
    fmt.Fprintln(os.Stderr, "The use command requires that a version is specified or the DOCKER_VERSION environment variable is set")
    os.Exit(127)
  }

  if !versionExists(version) {
    fmt.Fprintf(os.Stderr, "Version %s not found - try `dvm ls-remote` to browse available versions.\n", version)
    os.Exit(3)
  }

  // TODO: Handle system version

  ensureVersionIsInstalled(version)
  removePreviousDvmVersionFromPath()
  prependDvmVersionToPath(version)

  if !silent {
    fmt.Printf("Now using Docker %s\n", version)
  }
}

func getDvmDir() string {
  return dvmDir
}

func getDockerBinaryName(version string) string {
    if runtime.GOOS == "windows" {
      return fmt.Sprintf("docker-%s.exe", version)
    }
    return fmt.Sprintf("docker-%s", version)
}

func getBinaryName() string {
    if runtime.GOOS == "windows" {
      return "docker.exe"
    }
    return "docker"
}

func prependDvmVersionToPath(version string) {
    if runtime.GOOS == "windows" && shell == "" {
      fmt.Fprintf(os.Stderr, "The --shell flag or SHELL environment variable must be set when running on Windows. Available values are sh, powershell and cmd.")
      os.Exit(127)
    }
    versionDir := getVersionDir(version)
    path := os.Getenv("PATH")

    var shellScript string
    var shellScriptExt string
    if shell == "powershell" {
      shellScript = fmt.Sprintf(`$env:PATH="%s;%s"`, versionDir, path)
      shellScriptExt = "ps1"
    } else if shell == "cmd" {
      shellScript = fmt.Sprintf("PATH=%s;%s", versionDir, path)
      shellScriptExt = "cmd"
    } else { // default to bash
      shellScript = fmt.Sprintf("export PATH=%s:%s", versionDir, path)
      shellScriptExt = "sh"
    }

    writeShellScript(shellScript, shellScriptExt)
}

func writeShellScript(contents string, fileExtension string) {
    // Write to a shell script for the calling wrapper to execute
    scriptPath := filepath.Join(dvmDir, ".tmp", ("dvm-output." + fileExtension))

    if debug {
      fmt.Printf("Writing wrapper shell script to %s\n%s\n", scriptPath, contents)
    }

    ensureParentDirectoryExists(scriptPath)
    scriptFile, err := os.Create(scriptPath)
    if err != nil {
      fmt.Fprintf(os.Stderr, "Unable to create %s\n%s\n", scriptPath, err)
      os.Exit(1)
    }

    _, err = io.WriteString(scriptFile, contents)
    if err != nil {
      fmt.Fprintf(os.Stderr, "Unable to write to %s\n%s\n", scriptPath, err)
      os.Exit(1)
    }

    scriptFile.Close()
}

func removePreviousDvmVersionFromPath() {
  versionDir := getVersionDir("")

  var pathRegex string
  if runtime.GOOS == "windows" {
    escapedVersionDir := strings.Replace(versionDir, `\`, `\\`, -1)
    pathRegex = escapedVersionDir + `\\\d+\.\d+\.\d+;`
  } else {
    pathRegex = versionDir + `/\d+\.\d+\.\d+:`
  }

  regex, _ := regexp.Compile(pathRegex)
  path := regex.ReplaceAllString(os.Getenv("PATH"), "")
  os.Setenv("PATH", path)
}

func ensureVersionIsInstalled(version string) {
    versionDir := getVersionDir(version)
    if _, err := os.Stat(versionDir); err == nil {
      return
    }

    if !silent {
      fmt.Printf("%s is not installed. Installing now...\n", version)
      install(version)
    }
}

func downloadFile(url string, destPath string) {
  ensureParentDirectoryExists(destPath)

  destFile, err := os.Create(destPath)
  if err != nil {
    fmt.Fprintf(os.Stderr, "Unable to create to %s.\n%s\n", destPath, err)
    os.Exit(1)
  }
  defer destFile.Close()
  os.Chmod(destPath, 0755)

  if debug { fmt.Printf("Downloading %s\n", url) }

  response, err := http.Get(url)
  if err != nil {
    fmt.Fprintf(os.Stderr, "Unable to download %s.\n%s\n", url, err)
    os.Exit(1)
  }
  if response.StatusCode != 200 {
    fmt.Fprintf(os.Stderr, "Unable to download %s.\nStatus Code: %d\n", url, response.StatusCode)
    os.Exit(1)
  }
  defer response.Body.Close()

  _, err = io.Copy(destFile, response.Body)
  if err != nil {
    fmt.Fprintf(os.Stderr, "Unable to write to %s.\n%s\n", destPath, err)
    os.Exit(1)
  }
}

func versionExists(version string) bool {
  availableVersions := getAvailableVersions(version)

  for _,availableVersion := range availableVersions {
      if version == availableVersion {
          return true
      }
  }
  return false
}

func ensureParentDirectoryExists(filePath string) {
  dir := filepath.Dir(filePath)

  err := os.MkdirAll(dir, 0777)
  if err != nil {
    fmt.Fprintf(os.Stderr, "Unable to create directory %s\n", dir)
    os.Exit(1)
  }
}

func listRemote(pattern string) {
    versions := getAvailableVersions(pattern)
    for _, version := range versions {
      fmt.Println(version)
    }
}

func getAvailableVersions(pattern string) []string {
  gh := github.NewClient(nil)
	tags, response, err := gh.Repositories.ListTags("docker", "docker", nil)
  if err != nil {
    fmt.Fprintf(os.Stderr, "Unable to retrieve list of Docker tags from GitHub.\n%s\n", err)
    os.Exit(1)
  }
  if response.StatusCode != 200 {
    fmt.Fprintf(os.Stderr, "Unable to retrieve list of Docker tags from GitHub.\nStatus Code:%d\n", response.StatusCode)
    os.Exit(1)
  }

  versionRegex := regexp.MustCompile(`^v([1-9]+\.\d+\.\d+)$`)
  patternRegex, err := regexp.Compile(pattern)
  if err != nil {
    fmt.Fprintf(os.Stderr, "Invalid pattern.\n%s\n", err)
    os.Exit(3)
  }

  var results []string
  for _, tag := range tags {
    version := *tag.Name
    match := versionRegex.FindStringSubmatch(version)
    if len(match) > 1 && patternRegex.MatchString(version) {
      results = append(results, match[1])
    }
  }

  sort.Strings(results)
  return results
}

func getVersionDir(version string) string {
  return filepath.Join(dvmDir, "bin", "docker", version)
}

func getDockerOS() string {
  switch runtime.GOOS {
    case "windows":
      return "Windows"
    case "darwin":
      return "Darwin"
    case "linux":
      return "Linux"
    }

  fmt.Fprintf(os.Stderr, "Unsupported OS: %s\n", runtime.GOOS)
  os.Exit(1)
  return ""
}

func getDockerArch() string {
  switch runtime.GOARCH {
    case "amd64":
      return "x86_64"
    case "386":
      return "i386"
    }

  fmt.Fprintf(os.Stderr, "Unsupported ARCH: %s\n", runtime.GOARCH)
  os.Exit(1)
  return ""
}
/*
func help() {
  echo
  echo "Docker Version Manager"
  echo
  echo "Usage:"
  echo "  dvm help                              Show this message"
  echo "  dvm --version                         Print out the latest released version of dvm"
  echo "  dvm install <version>                 Download and install a <version>. Uses \$DOCKER_VERSION if available"
  echo "  dvm uninstall <version>               Uninstall a version"
  echo "  dvm use <version>                     Modify PATH to use <version>. Uses \$DOCKER_VERSION if available"
  echo "  dvm current                           Display currently activated version"
  echo "  dvm ls                                List installed versions"
  echo "  dvm ls <version>                      List versions matching a given description"
  echo "  dvm ls-remote                         List remote versions available for install"
  echo "  dvm deactivate                        Undo effects of \`dvm\` on current shell"
  echo "  dvm alias [<pattern>]                 Show all aliases beginning with <pattern>"
  echo "  dvm alias <name> <version>            Set an alias named <name> pointing to <version>"
  echo "  dvm unalias <name>                    Deletes the alias named <name>"
  echo "  dvm unload                            Unload \`dvm\` from shell"
  echo "  dvm which [<version>]                 Display path to installed docker version."
  echo
  echo "Example:"
  echo "  dvm install 1.8.1                     Install a specific version number"
  echo "  dvm use 1.6                           Use the latest available 1.6.x release"
  echo "  dvm alias default 1.8.1               Set default Docker version on a shell"
  echo
  echo "Note:"
  echo "  to remove, delete, or uninstall dvm - remove ~/.dvm"
  echo
}*/
<commit_msg>dvm deactivate<commit_after>package main

import "fmt"
import "io"
import "net/http"
import "os"
import "path/filepath"
import "regexp"
import "runtime"
import "sort"
import "strings"
import "github.com/google/go-github/github"
import "github.com/codegangsta/cli"
import "github.com/kardianos/osext"

var shell string
var dvmDir string
var debug bool
var silent bool

func main() {
  app := cli.NewApp()
  app.Name = "Docker Version Manager"
  app.Usage = "Manage multiple versions of the Docker client"
  app.EnableBashCompletion = true
  app.Flags = []cli.Flag{
    cli.StringFlag { Name: "dvm-dir", EnvVar: "DVM_DIR", Usage: "Specify an alternate DVM home directory, defaults to the current directory." },
    cli.StringFlag { Name: "shell", EnvVar: "SHELL", Usage: "Specify the shell format in which environment variables should be output, e.g. powershell, cmd or sh/bash. Defaults to sh/bash."},
    cli.BoolFlag { Name: "debug", Usage: "Print additional debug information." },
    cli.BoolFlag{ Name: "silent", EnvVar: "DVM_SILENT", Usage: "Suppress output. Errors will still be displayed."},
  }
  app.Commands = []cli.Command{
    {
      Name:    "install",
      Aliases: []string{"i"},
      Usage:   "dvm install <version>. Uses $DOCKER_VERSION if available",
      Action: func(c *cli.Context) {
        setGlobalVars(c)
        install(c.Args().First())
      },
    },
    {
      Name:    "use",
      Usage:   "dvm use <version>. Uses $DOCKER_VERSION if available",
      Action: func(c *cli.Context) {
        setGlobalVars(c)
        use(c.Args().First())
      },
    },
    {
      Name: "list-remote",
      Aliases: []string{"ls-remote"},
      Usage: "dvm list-remote [<pattern>]",
      Action: func(c *cli.Context) {
        setGlobalVars(c)
        listRemote(c.Args().First())
      },
    },
    {
      Name: "deactivate",
      Usage: "dvm deactivate. Undo effects of `dvm` on current shell",
      Action: func(c *cli.Context) {
        setGlobalVars(c)
        deactivate()
      },
    },
  }

  app.Run(os.Args)
}

func setGlobalVars(c *cli.Context) {
  debug = c.GlobalBool("debug")
  shell = c.GlobalString("shell")
  silent = c.GlobalBool("silent")
  dvmDir = c.GlobalString("dvm-dir")
  if dvmDir == "" {
    var err error
    dvmDir, err = osext.ExecutableFolder()
    if err != nil {
      fmt.Fprintln(os.Stderr, "Unable to determine DVM home directory")
      os.Exit(1)
    }
  }
}

func install(version string) {
  if version == "" {
    version = os.Getenv("DOCKER_VERSION")
  }

  if version == "" {
    fmt.Fprintln(os.Stderr, "The install command requires that a version is specified or the DOCKER_VERSION environment variable is set")
    os.Exit(127)
  }

  if !versionExists(version) {
    fmt.Fprintf(os.Stderr, "Version %s not found - try `dvm ls-remote` to browse available versions.\n", version)
    os.Exit(3)
  }

  versionDir := getVersionDir(version)

  // TODO: Support experimental

  if _, err := os.Stat(versionDir); err == nil {
    if !silent { fmt.Fprintf(os.Stderr, "%s is already installed\n", version) }
    use(version)
    return
  }

  if !silent { fmt.Printf("Installing %s\n", version) }

  url := fmt.Sprintf("https://get.docker.com/builds/%s/%s/%s", getDockerOS(), getDockerArch(), getDockerBinaryName(version))
  tmpPath := filepath.Join(getDvmDir(), ".tmp/docker", version, getBinaryName())
  downloadFile(url, tmpPath)
  binaryPath := filepath.Join(getDvmDir(), "bin/docker", version, getBinaryName())
  ensureParentDirectoryExists(binaryPath)
  err := os.Rename(tmpPath, binaryPath)
  if err != nil {
    fmt.Fprintf(os.Stderr, "Unable to copy %s to %s.\n%s\n", tmpPath, binaryPath, err)
  }

  if debug {
    fmt.Printf("Installed Docker %s to %s", version, binaryPath)
  }
}

func use(version string) {
  if version == "" {
    version = os.Getenv("DOCKER_VERSION")
  }

  if version == "" {
    fmt.Fprintln(os.Stderr, "The use command requires that a version is specified or the DOCKER_VERSION environment variable is set")
    os.Exit(127)
  }

  if !versionExists(version) {
    fmt.Fprintf(os.Stderr, "Version %s not found - try `dvm ls-remote` to browse available versions.\n", version)
    os.Exit(3)
  }

  // TODO: Handle system version

  ensureVersionIsInstalled(version)
  removePreviousDvmVersionFromPath()
  prependDvmVersionToPath(version)
  writeShellScript()

  if !silent {
    fmt.Printf("Now using Docker %s\n", version)
  }
}

func getDvmDir() string {
  return dvmDir
}

func getDockerBinaryName(version string) string {
    if runtime.GOOS == "windows" {
      return fmt.Sprintf("docker-%s.exe", version)
    }
    return fmt.Sprintf("docker-%s", version)
}

func getBinaryName() string {
    if runtime.GOOS == "windows" {
      return "docker.exe"
    }
    return "docker"
}

func deactivate() {
  removePreviousDvmVersionFromPath()
  writeShellScript()
}

func prependDvmVersionToPath(version string) {
  var pathSep string
  if runtime.GOOS == "windows" { pathSep = ";" } else { pathSep = ":" }
  versionDir := getVersionDir(version)
  path := fmt.Sprintf("%s%s%s", versionDir, pathSep, os.Getenv("PATH"))
  os.Setenv("PATH", path)
}

func writeShellScript() {
  if runtime.GOOS == "windows" && shell == "" {
    fmt.Fprintf(os.Stderr, "The --shell flag or SHELL environment variable must be set when running on Windows. Available values are sh, powershell and cmd.")
    os.Exit(127)
  }

  path := os.Getenv("PATH")

  var contents string
  var fileExtension string
  if shell == "powershell" {
    contents = fmt.Sprintf(`$env:PATH="%s"`, path)
    fileExtension = "ps1"
  } else if shell == "cmd" {
    contents = fmt.Sprintf("PATH=%s", path)
    fileExtension = "cmd"
  } else { // default to bash
    contents = fmt.Sprintf("export PATH=%s", path)
    fileExtension = "sh"
  }

  // Write to a shell script for the calling wrapper to execute
  scriptPath := filepath.Join(dvmDir, ".tmp", ("dvm-output." + fileExtension))

  if debug {
    fmt.Printf("Writing wrapper shell script to %s\n%s\n", scriptPath, contents)
  }

  ensureParentDirectoryExists(scriptPath)
  scriptFile, err := os.Create(scriptPath)
  if err != nil {
    fmt.Fprintf(os.Stderr, "Unable to create %s\n%s\n", scriptPath, err)
    os.Exit(1)
  }

  _, err = io.WriteString(scriptFile, contents)
  if err != nil {
    fmt.Fprintf(os.Stderr, "Unable to write to %s\n%s\n", scriptPath, err)
    os.Exit(1)
  }

  scriptFile.Close()
}

func removePreviousDvmVersionFromPath() {
  versionDir := getVersionDir("")

  var pathRegex string
  if runtime.GOOS == "windows" {
    escapedVersionDir := strings.Replace(versionDir, `\`, `\\`, -1)
    pathRegex = escapedVersionDir + `\\\d+\.\d+\.\d+;`
  } else {
    pathRegex = versionDir + `/\d+\.\d+\.\d+:`
  }

  regex, _ := regexp.Compile(pathRegex)
  path := regex.ReplaceAllString(os.Getenv("PATH"), "")
  os.Setenv("PATH", path)
}

func ensureVersionIsInstalled(version string) {
    versionDir := getVersionDir(version)
    if _, err := os.Stat(versionDir); err == nil {
      return
    }

    if !silent {
      fmt.Printf("%s is not installed. Installing now...\n", version)
      install(version)
    }
}

func downloadFile(url string, destPath string) {
  ensureParentDirectoryExists(destPath)

  destFile, err := os.Create(destPath)
  if err != nil {
    fmt.Fprintf(os.Stderr, "Unable to create to %s.\n%s\n", destPath, err)
    os.Exit(1)
  }
  defer destFile.Close()
  os.Chmod(destPath, 0755)

  if debug { fmt.Printf("Downloading %s\n", url) }

  response, err := http.Get(url)
  if err != nil {
    fmt.Fprintf(os.Stderr, "Unable to download %s.\n%s\n", url, err)
    os.Exit(1)
  }
  if response.StatusCode != 200 {
    fmt.Fprintf(os.Stderr, "Unable to download %s.\nStatus Code: %d\n", url, response.StatusCode)
    os.Exit(1)
  }
  defer response.Body.Close()

  _, err = io.Copy(destFile, response.Body)
  if err != nil {
    fmt.Fprintf(os.Stderr, "Unable to write to %s.\n%s\n", destPath, err)
    os.Exit(1)
  }
}

func versionExists(version string) bool {
  availableVersions := getAvailableVersions(version)

  for _,availableVersion := range availableVersions {
      if version == availableVersion {
          return true
      }
  }
  return false
}

func ensureParentDirectoryExists(filePath string) {
  dir := filepath.Dir(filePath)

  err := os.MkdirAll(dir, 0777)
  if err != nil {
    fmt.Fprintf(os.Stderr, "Unable to create directory %s\n", dir)
    os.Exit(1)
  }
}

func listRemote(pattern string) {
    versions := getAvailableVersions(pattern)
    for _, version := range versions {
      fmt.Println(version)
    }
}

func getAvailableVersions(pattern string) []string {
  gh := github.NewClient(nil)
	tags, response, err := gh.Repositories.ListTags("docker", "docker", nil)
  if err != nil {
    fmt.Fprintf(os.Stderr, "Unable to retrieve list of Docker tags from GitHub.\n%s\n", err)
    os.Exit(1)
  }
  if response.StatusCode != 200 {
    fmt.Fprintf(os.Stderr, "Unable to retrieve list of Docker tags from GitHub.\nStatus Code:%d\n", response.StatusCode)
    os.Exit(1)
  }

  versionRegex := regexp.MustCompile(`^v([1-9]+\.\d+\.\d+)$`)
  patternRegex, err := regexp.Compile(pattern)
  if err != nil {
    fmt.Fprintf(os.Stderr, "Invalid pattern.\n%s\n", err)
    os.Exit(3)
  }

  var results []string
  for _, tag := range tags {
    version := *tag.Name
    match := versionRegex.FindStringSubmatch(version)
    if len(match) > 1 && patternRegex.MatchString(version) {
      results = append(results, match[1])
    }
  }

  sort.Strings(results)
  return results
}

func getVersionDir(version string) string {
  return filepath.Join(dvmDir, "bin", "docker", version)
}

func getDockerOS() string {
  switch runtime.GOOS {
    case "windows":
      return "Windows"
    case "darwin":
      return "Darwin"
    case "linux":
      return "Linux"
    }

  fmt.Fprintf(os.Stderr, "Unsupported OS: %s\n", runtime.GOOS)
  os.Exit(1)
  return ""
}

func getDockerArch() string {
  switch runtime.GOARCH {
    case "amd64":
      return "x86_64"
    case "386":
      return "i386"
    }

  fmt.Fprintf(os.Stderr, "Unsupported ARCH: %s\n", runtime.GOARCH)
  os.Exit(1)
  return ""
}
/*
func help() {
  echo
  echo "Docker Version Manager"
  echo
  echo "Usage:"
  echo "  dvm help                              Show this message"
  echo "  dvm --version                         Print out the latest released version of dvm"
  echo "  dvm install <version>                 Download and install a <version>. Uses \$DOCKER_VERSION if available"
  echo "  dvm uninstall <version>               Uninstall a version"
  echo "  dvm use <version>                     Modify PATH to use <version>. Uses \$DOCKER_VERSION if available"
  echo "  dvm current                           Display currently activated version"
  echo "  dvm ls                                List installed versions"
  echo "  dvm ls <version>                      List versions matching a given description"
  echo "  dvm ls-remote                         List remote versions available for install"
  echo "  dvm deactivate                        Undo effects of \`dvm\` on current shell"
  echo "  dvm alias [<pattern>]                 Show all aliases beginning with <pattern>"
  echo "  dvm alias <name> <version>            Set an alias named <name> pointing to <version>"
  echo "  dvm unalias <name>                    Deletes the alias named <name>"
  echo "  dvm unload                            Unload \`dvm\` from shell"
  echo "  dvm which [<version>]                 Display path to installed docker version."
  echo
  echo "Example:"
  echo "  dvm install 1.8.1                     Install a specific version number"
  echo "  dvm use 1.6                           Use the latest available 1.6.x release"
  echo "  dvm alias default 1.8.1               Set default Docker version on a shell"
  echo
  echo "Note:"
  echo "  to remove, delete, or uninstall dvm - remove ~/.dvm"
  echo
}*/
<|endoftext|>


<commit_before>// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// 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. See the GNU
// Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public
// License along with this program. If not, see <http://www.gnu.org/licenses/>.

package url

import (
	"errors"
	"fmt"
	"github.com/nmeum/marvin/irc"
	"github.com/nmeum/marvin/modules"
	"golang.org/x/net/html"
	"io"
	"mime"
	"net/http"
	"regexp"
	"strconv"
	"strings"
)

var extractError = errors.New("couldn't extract title")

type Module struct {
	regex    *regexp.Regexp
	RegexStr string   `json:"regex"`
	Exclude  []string `json:"exclude"`
}

func Init(moduleSet *modules.ModuleSet) {
	moduleSet.Register(new(Module))
}

func (m *Module) Name() string {
	return "url"
}

func (m *Module) Help() string {
	return "Displays HTML titles for HTTP links."
}

func (m *Module) Defaults() {
	m.RegexStr = `(http|https)\://[a-zA-Z0-9\-\.]+\.[a-zA-Z]{2,3}(:[a-zA-Z0-9]*)?/?([a-zA-Z0-9\-\._\?\,\'/\\\+&%\$#\=~])*`
}

func (m *Module) Load(client *irc.Client) error {
	regex, err := regexp.Compile(m.RegexStr)
	if err != nil {
		return err
	}

	m.regex = regex
	client.CmdHook("privmsg", m.urlCmd)

	return nil
}

func (m *Module) urlCmd(client *irc.Client, msg irc.Message) error {
	url := m.regex.FindString(msg.Data)
	if len(url) <= 0 {
		return nil
	}

	resp, err := http.Get(url)
	if err != nil {
		return err
	}
	defer resp.Body.Close()

	info := m.infoString(resp)
	if len(info) <= 0 {
		return nil
	}

	return client.Write("NOTICE %s :%s", msg.Receiver, info)
}

func (m *Module) infoString(resp *http.Response) string {
	var mtype string
	var infos []string

	ctype := resp.Header.Get("Content-Type")
	if len(ctype) > 0 {
		m, _, err := mime.ParseMediaType(ctype)
		if err == nil {
			mtype = m
			infos = append(infos, fmt.Sprintf("Type: %s", mtype))
		}
	}

	csize := resp.Header.Get("Content-Length")
	if len(csize) > 0 {
		size, err := strconv.Atoi(csize)
		if err == nil {
			infos = append(infos, fmt.Sprintf("Size: %s", m.humanize(size)))
		}
	}

	if mtype == "text/html" {
		title, err := m.extractTitle(resp.Body)
		if err == nil {
			infos = append(infos, fmt.Sprintf("Title: %s", title))
		}
	}

	info := strings.Join(infos, " | ")
	if len(info) > 0 {
		info = fmt.Sprintf("%s -- %s", strings.ToUpper(m.Name()), info)
	}

	return info
}

func (m *Module) extractTitle(reader io.Reader) (title string, err error) {
	doc, err := html.Parse(reader)
	if err != nil {
		return
	}

	var parseFunc func(n *html.Node)
	parseFunc = func(n *html.Node) {
		if n.Type == html.ElementNode && n.Data == "title" {
			child := n.FirstChild
			if child != nil {
				title = html.UnescapeString(child.Data)
			} else {
				return
			}
		}

		for c := n.FirstChild; c != nil; c = c.NextSibling {
			parseFunc(c)
		}
	}

	parseFunc(doc)
	title = m.sanitize(title)

	if len(title) <= 0 {
		return "", extractError
	}

	return
}

func (m *Module) sanitize(title string) string {
	normalized := strings.Replace(title, "\n", " ", -1)
	for strings.Contains(normalized, "  ") {
		normalized = strings.Replace(normalized, "  ", " ", -1)
	}

	return strings.TrimSpace(normalized)
}

func (m *Module) humanize(c int) string {
	switch {
	case c > (1 << 40):
		return fmt.Sprintf("%v TiB", c/(1<<40))
	case c > (1 << 30):
		return fmt.Sprintf("%v GiB", c/(1<<30))
	case c > (1 << 20):
		return fmt.Sprintf("%v MiB", c/(1<<20))
	case c > (1 << 10):
		return fmt.Sprintf("%v KiB", c/(1<<10))
	default:
		return fmt.Sprintf("%v B", c)
	}
}
<commit_msg>url: style fixes<commit_after>// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// 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. See the GNU
// Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public
// License along with this program. If not, see <http://www.gnu.org/licenses/>.

package url

import (
	"errors"
	"fmt"
	"github.com/nmeum/marvin/irc"
	"github.com/nmeum/marvin/modules"
	"golang.org/x/net/html"
	"io"
	"mime"
	"net/http"
	"regexp"
	"strconv"
	"strings"
)

var extractError = errors.New("couldn't extract title")

type Module struct {
	regex    *regexp.Regexp
	RegexStr string   `json:"regex"`
	Exclude  []string `json:"exclude"`
}

func Init(moduleSet *modules.ModuleSet) {
	moduleSet.Register(new(Module))
}

func (m *Module) Name() string {
	return "url"
}

func (m *Module) Help() string {
	return "Displays HTML titles for HTTP links."
}

func (m *Module) Defaults() {
	m.RegexStr = `(http|https)\://[a-zA-Z0-9\-\.]+\.[a-zA-Z]{2,3}(:[a-zA-Z0-9]*)?/?([a-zA-Z0-9\-\._\?\,\'/\\\+&%\$#\=~])*`
}

func (m *Module) Load(client *irc.Client) error {
	regex, err := regexp.Compile(m.RegexStr)
	if err != nil {
		return err
	}

	m.regex = regex
	client.CmdHook("privmsg", m.urlCmd)

	return nil
}

func (m *Module) urlCmd(client *irc.Client, msg irc.Message) error {
	url := m.regex.FindString(msg.Data)
	if len(url) <= 0 {
		return nil
	}

	resp, err := http.Get(url)
	if err != nil {
		return err
	}
	defer resp.Body.Close()

	info := m.infoString(resp)
	if len(info) <= 0 {
		return nil
	}

	return client.Write("NOTICE %s :%s", msg.Receiver, info)
}

func (m *Module) infoString(resp *http.Response) string {
	var mtype string
	var infos []string

	ctype := resp.Header.Get("Content-Type")
	if len(ctype) > 0 {
		m, _, err := mime.ParseMediaType(ctype)
		if err == nil {
			mtype = m
			infos = append(infos, fmt.Sprintf("Type: %s", mtype))
		}
	}

	csize := resp.Header.Get("Content-Length")
	if len(csize) > 0 {
		size, err := strconv.Atoi(csize)
		if err == nil {
			infos = append(infos, fmt.Sprintf("Size: %s", m.humanize(size)))
		}
	}

	if mtype == "text/html" {
		title, err := m.extractTitle(resp.Body)
		if err == nil {
			infos = append(infos, fmt.Sprintf("Title: %s", title))
		}
	}

	info := strings.Join(infos, " | ")
	if len(info) > 0 {
		info = fmt.Sprintf("%s -- %s", strings.ToUpper(m.Name()), info)
	}

	return info
}

func (m *Module) extractTitle(reader io.Reader) (title string, err error) {
	doc, err := html.Parse(reader)
	if err != nil {
		return
	}

	var parseFunc func(n *html.Node)
	parseFunc = func(n *html.Node) {
		if n.Type == html.ElementNode && n.Data == "title" {
			child := n.FirstChild
			if child != nil {
				title = html.UnescapeString(child.Data)
			} else {
				return
			}
		}

		for c := n.FirstChild; c != nil; c = c.NextSibling {
			parseFunc(c)
		}
	}

	parseFunc(doc)
	title = m.sanitize(title)

	if len(title) <= 0 {
		return "", extractError
	}

	return
}

func (m *Module) sanitize(input string) string {
	normalized := strings.Replace(input, "\n", " ", -1)
	for strings.Contains(normalized, "  ") {
		normalized = strings.Replace(normalized, "  ", " ", -1)
	}

	return strings.TrimSpace(normalized)
}

func (m *Module) humanize(count int) string {
	switch {
	case count > (1 << 40):
		return fmt.Sprintf("%v TiB", count/(1<<40))
	case count > (1 << 30):
		return fmt.Sprintf("%v GiB", count/(1<<30))
	case count > (1 << 20):
		return fmt.Sprintf("%v MiB", count/(1<<20))
	case count > (1 << 10):
		return fmt.Sprintf("%v KiB", count/(1<<10))
	default:
		return fmt.Sprintf("%v B", count)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"errors"
	"fmt"
	"strconv"
	"encoding/json"
	"github.com/hyperledger/fabric/core/chaincode/shim"
	"github.com/hyperledger/fabric/core/util"
)

type Chaincode struct { }

type ChaincodeFunctions struct {
	stub shim.ChaincodeStubInterface
}

func main() {
	err := shim.Start(new(Chaincode))
	if err != nil {
		fmt.Printf("Error starting Simple chaincode: %s", err)
	}
}

func (t Chaincode) Init(stub shim.ChaincodeStubInterface, function string, args []string) ([]byte, error) {
	//fns := ChaincodeFunctions{stub}
	configJson := args[0]
	_ = args[1] // nonce to stop existing deal being returned
	_ = stub.PutState("dealConfig", []byte(configJson))
	_ = stub.PutState("dealStatus", []byte("draft")) // Possible Values [draft, open, closed, allocated]
	_ = stub.PutState("orderbook", []byte("{}"))
	return nil, nil
}

func (t Chaincode) Invoke(stub shim.ChaincodeStubInterface, function string, args []string) ([]byte, error) {
	fmt.Println("invoke is running " + function)
	fns := ChaincodeFunctions{stub}
	if function == "addOrder" {
		investor := args[0]
		ioi, err := strconv.ParseFloat(args[1], 64)
		if err != nil {
	        return nil, errors.New("Failed to parse " + args[1] + " as a float64")
    	}
		return fns.AddOrder(investor, ioi)
	} else if function == "allocateOrder" {
		investor := args[0]
		alloc, err := strconv.ParseFloat(args[1], 64)
		if err != nil {
	        return nil, errors.New("Failed to parse " + args[1] + " as a float64")
    	}
		return fns.AllocateOrder(investor, alloc)
	} else if function == "updateDealStatus" {
		status := args[0]
		return fns.UpdateDealStatus(status)
	} else if function == "confirmOrder" {
		investor := args[0]
		return fns.ConfirmOrder(investor)
	}
	fmt.Println("invoke did not find func: " + function)

	return nil, errors.New("Received unknown function invocation: " + function)
}

func (t Chaincode) Query(stub shim.ChaincodeStubInterface, function string, args []string) ([]byte, error) {
	fmt.Println("query is running " + function)
	fns := ChaincodeFunctions{stub}
	if function == "ping" {
		return fns.Ping()
	} else if function == "getDealConfig" {
		return fns.GetDealConfig()
	} else if function == "getOrder" {
		investor := args[0]
		return fns.GetOrder(investor)
	} else if function == "getOrderbook" {
		return fns.GetOrderbook()
	}
	fmt.Println("query did not find func: " + function)

	return nil, errors.New("Received unknown function query: " + function)
}

type DealConfig struct {
	Issuer 			string 		`json:"issuer"`
	Banks 			[]string 	`json:"banks"`
	BookStatus 		string 		`json:"bookStatus"`
	RequiredDocs	[]string	`json:"requiredDocs"`
	DocRegAddress 	string 		`json:"docRegAddress"`
}

type Order struct {
	Investor	string 		`json:"investor"`
	Ioi 		float64 	`json:"ioi"`
	Alloc 		float64		`json:"alloc"`
	Confirmed	bool		`json:"confirmed"`
}

// Public Functions

func (c ChaincodeFunctions) Ping() ([]byte, error) {
    return []byte("pong"), nil
}

func (c ChaincodeFunctions) GetDealConfig() ([]byte, error) {
	dealConfig, _ := c.stub.GetState("dealConfig")
	return dealConfig, nil
}

func (c ChaincodeFunctions) UpdateDealStatus(dealStatus string) ([]byte, error)  {
	dealConfig := c.getDealConfigFromBlockchain()
	dealConfig.BookStatus = dealStatus
	c.saveDealConfigToBlockchain(dealConfig)
	c.stub.SetEvent("Book Status Change", []byte("{\"status\":\"" + dealStatus + "\"}"))
	return nil, nil
}

func (c ChaincodeFunctions) AddOrder(investor string, ioi float64) ([]byte, error)  {
	dealConfig := c.getDealConfigFromBlockchain()
	if dealConfig.BookStatus != "open" {
		c.stub.SetEvent("Permission Denied", []byte("{\"reason\":\"book is not open\"}"))
		return nil, errors.New("Orders cannot be placed unless deal status is 'Open'")
	}
	hasReqDocs, reqDoc := c.checkInvestorHasRequiredDocs(dealConfig.DocRegAddress, investor, dealConfig.RequiredDocs)
	if !hasReqDocs {
		c.stub.SetEvent("Permission Denied", []byte("{\"reason\":\"" + investor + " does not have " + reqDoc +  "\"}"))
		return nil, errors.New("Order cannot be placed without " + reqDoc +  " status")
	}
	order := c.getOrderFromBlockChain(investor)
	if order.Investor == "" {
		order = Order{Investor: investor, Ioi: ioi, Alloc: 0.0, Confirmed: false}
	} else {
		order.Ioi = ioi
	}
	c.saveOrderToBlockChain(order)
	c.stub.SetEvent("Order Added", []byte("{\"investor\":\"" + investor + "\"}"))
	return nil, nil
}

func (c ChaincodeFunctions) ConfirmOrder(investor string) ([]byte, error) {
	dealConfig := c.getDealConfigFromBlockchain()
	if dealConfig.BookStatus != "allocated" {
		c.stub.SetEvent("Permission Denied", []byte("{\"reason\":\"book is not allocated\"}"))
		return nil, nil
	}
	order := c.getOrderFromBlockChain(investor)
	order.Confirmed = true
	c.saveOrderToBlockChain(order)
	c.stub.SetEvent("Order Confirmed", []byte("{\"investor\":\"" + investor + "\"}"))
	return nil, nil
}

func (c ChaincodeFunctions) GetOrder(investor string) ([]byte, error) {
	roleBytes, _ := c.stub.ReadCertAttribute("role")
	role := string(roleBytes)
	dealConfig := c.getDealConfigFromBlockchain()
	order := c.getOrderFromBlockChain(investor)
	if !canSeeAllocations(role, dealConfig) {
		order.Alloc = -1
	}
	orderJson, _ := json.Marshal(order)
	return []byte(orderJson), nil
}

func (c ChaincodeFunctions) GetOrderbook() ([]byte, error) {
	orderbookJson, _ := c.stub.GetState("orderbook")
	return []byte(orderbookJson), nil
}

func (c ChaincodeFunctions) AllocateOrder(investor string, alloc float64) ([]byte, error) {
	order := c.getOrderFromBlockChain(investor)
	order.Alloc = alloc
	c.saveOrderToBlockChain(order)
	c.stub.SetEvent("Order Allocated", []byte("{\"investor\":\"" + investor + "\"}"))
	return nil, nil
}

// Private Functions

func (c ChaincodeFunctions) getDealConfigFromBlockchain() DealConfig {
	dealConfigJson, _ := c.stub.GetState("dealConfig")
	var dealConfig DealConfig
	_ = json.Unmarshal(dealConfigJson, &dealConfig)
	return dealConfig
}

func (c ChaincodeFunctions) saveDealConfigToBlockchain(dealConfig DealConfig) {
	dealConfigJson, _ := json.Marshal(dealConfig)
	_ = c.stub.PutState("dealConfig", []byte(dealConfigJson))
}

func (c ChaincodeFunctions) getOrderAsJsonFromBlockchain(investor string) string {
	order := c.getOrderFromBlockChain(investor)
	orderJson, _ := json.Marshal(order)
	return string(orderJson)
}

func (c ChaincodeFunctions) getOrderFromBlockChain(investor string) Order {
	orderbook := c.getOrderbookFromBlockChain()
	return orderbook[investor]
}

func (c ChaincodeFunctions) saveOrderToBlockChain(order Order) {
	orderbook := c.getOrderbookFromBlockChain()
	orderbook[order.Investor] = order
	c.saveOrderbookToBlockChain(orderbook)
}

func (c ChaincodeFunctions) getOrderbookFromBlockChain() map[string]Order {
	orderbookJson, _ := c.stub.GetState("orderbook")
	var orderbook map[string]Order
	_ = json.Unmarshal(orderbookJson, &orderbook)
	return orderbook
}

func (c ChaincodeFunctions) saveOrderbookToBlockChain(orderbook map[string]Order) {
	orderbookJson, _ := json.Marshal(orderbook)
	_ = c.stub.PutState("orderbook", []byte(orderbookJson))
}

func (c ChaincodeFunctions) checkInvestorHasRequiredDocs(address string, company string,
		requiredDocs []string) (bool, string) {
	invokeArgs := util.ToChaincodeArgs("getDocs", company)
	docsJson, _ := c.stub.QueryChaincode(address, invokeArgs)
	var docs []string
	_ = json.Unmarshal(docsJson, &docs)
	for _, reqDoc := range requiredDocs {
		if !stringInSlice("qib", docs) {
			return false, reqDoc
		}
	}
	return true, ""
}

func stringInSlice(a string, list []string) bool {
    for _, b := range list {
        if b == a {
            return true
        }
    }
    return false
}

func canSeeAllocations(role string, dealConfig DealConfig) bool {
	if role != "investor" {
		return true
	} else if dealConfig.BookStatus == "draft" {
		return false
	} else if dealConfig.BookStatus == "open" {
		return false
	} else if dealConfig.BookStatus == "closed" {
		return false
	} else {
		return true
	}
}<commit_msg>batch check-in<commit_after>package main

import (
	"errors"
	"fmt"
	"strconv"
	"encoding/json"
	"github.com/hyperledger/fabric/core/chaincode/shim"
	"github.com/hyperledger/fabric/core/util"
)

type Chaincode struct { }

type ChaincodeFunctions struct {
	stub shim.ChaincodeStubInterface
}

func main() {
	err := shim.Start(new(Chaincode))
	if err != nil {
		fmt.Printf("Error starting Simple chaincode: %s", err)
	}
}

func (t Chaincode) Init(stub shim.ChaincodeStubInterface, function string, args []string) ([]byte, error) {
	//fns := ChaincodeFunctions{stub}
	configJson := args[0]
	_ = args[1] // nonce to stop existing deal being returned
	_ = stub.PutState("dealConfig", []byte(configJson))
	_ = stub.PutState("dealStatus", []byte("draft")) // Possible Values [draft, open, closed, allocated]
	_ = stub.PutState("orderbook", []byte("{}"))
	return nil, nil
}

func (t Chaincode) Invoke(stub shim.ChaincodeStubInterface, function string, args []string) ([]byte, error) {
	fmt.Println("invoke is running " + function)
	fns := ChaincodeFunctions{stub}
	if function == "addOrder" {
		investor := args[0]
		ioi, err := strconv.ParseFloat(args[1], 64)
		if err != nil {
	        return nil, errors.New("Failed to parse " + args[1] + " as a float64")
    	}
		return fns.AddOrder(investor, ioi)
	} else if function == "allocateOrder" {
		investor := args[0]
		alloc, err := strconv.ParseFloat(args[1], 64)
		if err != nil {
	        return nil, errors.New("Failed to parse " + args[1] + " as a float64")
    	}
		return fns.AllocateOrder(investor, alloc)
	} else if function == "updateDealStatus" {
		status := args[0]
		return fns.UpdateDealStatus(status)
	} else if function == "confirmOrder" {
		investor := args[0]
		return fns.ConfirmOrder(investor)
	}
	fmt.Println("invoke did not find func: " + function)

	return nil, errors.New("Received unknown function invocation: " + function)
}

func (t Chaincode) Query(stub shim.ChaincodeStubInterface, function string, args []string) ([]byte, error) {
	fmt.Println("query is running " + function)
	fns := ChaincodeFunctions{stub}
	if function == "ping" {
		return fns.Ping()
	} else if function == "getDealConfig" {
		return fns.GetDealConfig()
	} else if function == "getOrder" {
		investor := args[0]
		return fns.GetOrder(investor)
	} else if function == "getOrderbook" {
		return fns.GetOrderbook()
	}
	fmt.Println("query did not find func: " + function)

	return nil, errors.New("Received unknown function query: " + function)
}

type DealConfig struct {
	Issuer 			string 		`json:"issuer"`
	Banks 			[]string 	`json:"banks"`
	BookStatus 		string 		`json:"bookStatus"`
	RequiredDocs	[]string	`json:"requiredDocs"`
	DocRegAddress 	string 		`json:"docRegAddress"`
}

type Order struct {
	Investor	string 		`json:"investor"`
	Ioi 		float64 	`json:"ioi"`
	Alloc 		float64		`json:"alloc"`
	Confirmed	bool		`json:"confirmed"`
}

// Public Functions

func (c ChaincodeFunctions) Ping() ([]byte, error) {
    return []byte("pong"), nil
}

func (c ChaincodeFunctions) GetDealConfig() ([]byte, error) {
	dealConfig, _ := c.stub.GetState("dealConfig")
	return dealConfig, nil
}

func (c ChaincodeFunctions) UpdateDealStatus(dealStatus string) ([]byte, error)  {
	dealConfig := c.getDealConfigFromBlockchain()
	dealConfig.BookStatus = dealStatus
	c.saveDealConfigToBlockchain(dealConfig)
	c.stub.SetEvent("Book Status Change", []byte("{\"status\":\"" + dealStatus + "\"}"))
	return nil, nil
}

func (c ChaincodeFunctions) AddOrder(investor string, ioi float64) ([]byte, error)  {
	dealConfig := c.getDealConfigFromBlockchain()
	if dealConfig.BookStatus != "open" {
		c.stub.SetEvent("Permission Denied", []byte("{\"reason\":\"book is not open\"}"))
		return nil, errors.New("Orders cannot be placed unless deal status is 'Open'")
	}
	hasReqDocs, reqDoc := c.checkInvestorHasRequiredDocs(dealConfig.DocRegAddress, investor, dealConfig.RequiredDocs)
	if !hasReqDocs {
		c.stub.SetEvent("Permission Denied", []byte("{\"reason\":\"" + investor + " does not have " + reqDoc +  "\"}"))
		return nil, errors.New("Order cannot be placed without " + reqDoc +  " status")
	}
	order := c.getOrderFromBlockChain(investor)
	if order.Investor == "" {
		order = Order{Investor: investor, Ioi: ioi, Alloc: 0.0, Confirmed: false}
	} else {
		order.Ioi = ioi
	}
	c.saveOrderToBlockChain(order)
	c.stub.SetEvent("Order Added", []byte("{\"investor\":\"" + investor + "\"}"))
	return nil, nil
}

func (c ChaincodeFunctions) ConfirmOrder(investor string) ([]byte, error) {
	dealConfig := c.getDealConfigFromBlockchain()
	if dealConfig.BookStatus != "allocated" {
		c.stub.SetEvent("Permission Denied", []byte("{\"reason\":\"book is not allocated\"}"))
		return nil, nil
	}
	order := c.getOrderFromBlockChain(investor)
	order.Confirmed = true
	c.saveOrderToBlockChain(order)
	c.stub.SetEvent("Order Confirmed", []byte("{\"investor\":\"" + investor + "\"}"))
	return nil, nil
}

func (c ChaincodeFunctions) GetOrder(investor string) ([]byte, error) {
	roleBytes, _ := c.stub.ReadCertAttribute("role")
	role := string(roleBytes)
	dealConfig := c.getDealConfigFromBlockchain()
	order := c.getOrderFromBlockChain(investor)
	if !canSeeAllocations(role, dealConfig) {
		order.Alloc = -1
	}
	orderJson, _ := json.Marshal(order)
	return []byte(orderJson), nil
}

func (c ChaincodeFunctions) GetOrderbook() ([]byte, error) {
	orderbookJson, _ := c.stub.GetState("orderbook")
	return []byte(orderbookJson), nil
}

func (c ChaincodeFunctions) AllocateOrder(investor string, alloc float64) ([]byte, error) {
	order := c.getOrderFromBlockChain(investor)
	order.Alloc = alloc
	c.saveOrderToBlockChain(order)
	c.stub.SetEvent("Order Allocated", []byte("{\"investor\":\"" + investor + "\"}"))
	return nil, nil
}

// Private Functions

func (c ChaincodeFunctions) getDealConfigFromBlockchain() DealConfig {
	dealConfigJson, _ := c.stub.GetState("dealConfig")
	var dealConfig DealConfig
	_ = json.Unmarshal(dealConfigJson, &dealConfig)
	return dealConfig
}

func (c ChaincodeFunctions) saveDealConfigToBlockchain(dealConfig DealConfig) {
	dealConfigJson, _ := json.Marshal(dealConfig)
	_ = c.stub.PutState("dealConfig", []byte(dealConfigJson))
}

func (c ChaincodeFunctions) getOrderAsJsonFromBlockchain(investor string) string {
	order := c.getOrderFromBlockChain(investor)
	orderJson, _ := json.Marshal(order)
	return string(orderJson)
}

func (c ChaincodeFunctions) getOrderFromBlockChain(investor string) Order {
	orderbook := c.getOrderbookFromBlockChain()
	return orderbook[investor]
}

func (c ChaincodeFunctions) saveOrderToBlockChain(order Order) {
	orderbook := c.getOrderbookFromBlockChain()
	orderbook[order.Investor] = order
	c.saveOrderbookToBlockChain(orderbook)
}

func (c ChaincodeFunctions) getOrderbookFromBlockChain() map[string]Order {
	orderbookJson, _ := c.stub.GetState("orderbook")
	var orderbook map[string]Order
	_ = json.Unmarshal(orderbookJson, &orderbook)
	return orderbook
}

func (c ChaincodeFunctions) saveOrderbookToBlockChain(orderbook map[string]Order) {
	orderbookJson, _ := json.Marshal(orderbook)
	_ = c.stub.PutState("orderbook", []byte(orderbookJson))
}

func (c ChaincodeFunctions) checkInvestorHasRequiredDocs(address string, company string,
		requiredDocs []string) (bool, string) {
	invokeArgs := util.ToChaincodeArgs("getDocs", company)
	docsJson, _ := c.stub.QueryChaincode(address, invokeArgs)
	var docs []string
	_ = json.Unmarshal(docsJson, &docs)
	for _, reqDoc := range requiredDocs {
		if !stringInSlice(reqDoc, docs) {
			return false, string(docsJson)
		}
	}
	return true, ""
}

func stringInSlice(a string, list []string) bool {
    for _, b := range list {
        if b == a {
            return true
        }
    }
    return false
}

func canSeeAllocations(role string, dealConfig DealConfig) bool {
	if role != "investor" {
		return true
	} else if dealConfig.BookStatus == "draft" {
		return false
	} else if dealConfig.BookStatus == "open" {
		return false
	} else if dealConfig.BookStatus == "closed" {
		return false
	} else {
		return true
	}
}<|endoftext|>


<commit_before>package core

import (
	"bytes"
	"io"
	"os/exec"
	"strings"
	"unicode/utf8"

	"github.com/mibk/syd/ui"
)

type cmdContext interface {
	editor() (ed *Editor)
	column() (col *Column, ok bool)
	window() (win *Window, ok bool)
}

func execute(ctx cmdContext, command string) {
	if command == "" {
		return
	}
	// TODO: Print err if the context isn't sufficient.
	switch command {
	case "Exit":
		// TODO: This is just a temporary solution
		// until a proper solution is found.
		go func() {
			ui.Events <- ui.Quit
		}()

	case "Newcol":
		ctx.editor().NewColumn()

	case "Delcol", "New":
		col, ok := ctx.column()
		if !ok {
			return
		}
		switch command {
		case "Delcol":
			col.Close()
		case "New":
			col.NewWindow()
		}

	case "Del", "Put", "Undo", "Redo":
		fallthrough
	default:
		win, ok := ctx.window()
		if !ok {
			return
		}
		switch command {
		case "Del":
			win.Close()
		case "Put":
			win.saveFile()
			win.buf.Clean()
		case "Undo":
			win.buf.Undo()
		case "Redo":
			win.buf.Redo()
		default:
			ed := win.col.ed
			if ed.errWin == nil {
				ed.errWin = ed.recentCol().NewWindow()
				ed.errWin.SetFilename("+Errors")
				// TODO: This is just a hack because one
				// cannot write to a window until this method
				// is at least once called. Remove it.
				ed.errWin.win.Clear()
			}
			wout := ed.errWin

			var stdin io.Reader
			if command[0] == '|' {
				command = command[1:]

				// TODO: Implement this using io.Reader; read directly
				// from the buffer.
				q0, q1 := win.body.Selected()
				selected := win.body.SelectionToString(q0, q1)
				stdin = strings.NewReader(selected)
				wout = win
			} else {
				q := wout.body.buf.End()
				wout.body.q0, wout.body.q1 = q, q
			}

			var buf bytes.Buffer
			cmd := exec.Command(command)
			cmd.Stdin = stdin
			cmd.Stdout = &buf
			// TODO: Redirect stderr somewhere.
			switch err := cmd.Run(); err := err.(type) {
			case *exec.Error:
				if err.Err == exec.ErrNotFound {
					return
				}
				panic(err)
			case error:
				panic(err)
			}
			s := buf.String()
			q := wout.body.q0
			wout.body.Insert(s)
			wout.body.Select(q, q+int64(utf8.RuneCountInString(s)))

			// TODO: Come up with a better solution
			wout.buf.Commit()
		}
	}
}
<commit_msg>core: Enable execution of shell command from all contexts<commit_after>package core

import (
	"bytes"
	"io"
	"os/exec"
	"strings"
	"unicode/utf8"

	"github.com/mibk/syd/ui"
)

type cmdContext interface {
	editor() (ed *Editor)
	column() (col *Column, ok bool)
	window() (win *Window, ok bool)
}

func execute(ctx cmdContext, command string) {
	if command == "" {
		return
	}
	// TODO: Print err if the context isn't sufficient.
	switch command {
	case "Exit":
		// TODO: This is just a temporary solution
		// until a proper solution is found.
		go func() {
			ui.Events <- ui.Quit
		}()

	case "Newcol":
		ctx.editor().NewColumn()

	case "Delcol", "New":
		col, ok := ctx.column()
		if !ok {
			return
		}
		switch command {
		case "Delcol":
			col.Close()
		case "New":
			col.NewWindow()
		}

	case "Del", "Put", "Undo", "Redo":
		win, ok := ctx.window()
		if !ok {
			return
		}
		switch command {
		case "Del":
			win.Close()
		case "Put":
			win.saveFile()
			win.buf.Clean()
		case "Undo":
			win.buf.Undo()
		case "Redo":
			win.buf.Redo()
		}
	default:
		shell(ctx, command)
	}
}

func shell(ctx cmdContext, command string) {
	ed := ctx.editor()
	if ed.errWin == nil {
		ed.errWin = ed.recentCol().NewWindow()
		ed.errWin.SetFilename("+Errors")
		// TODO: This is just a hack because one
		// cannot write to a window until this method
		// is at least once called. Remove it.
		ed.errWin.win.Clear()
	}
	wout := ed.errWin

	var stdin io.Reader
	if command[0] == '|' {
		win, ok := ctx.window()
		if !ok {
			// TODO: Just print to +Errors window (like the rest of
			// the panics).
			panic("no current window")
		}
		command = command[1:]

		// TODO: Implement this using io.Reader; read directly
		// from the buffer.
		q0, q1 := win.body.Selected()
		selected := win.body.SelectionToString(q0, q1)
		stdin = strings.NewReader(selected)
		wout = win
	} else {
		q := wout.body.buf.End()
		wout.body.q0, wout.body.q1 = q, q
	}

	var buf bytes.Buffer
	cmd := exec.Command(command)
	cmd.Stdin = stdin
	cmd.Stdout = &buf
	// TODO: Redirect stderr somewhere.
	switch err := cmd.Run(); err := err.(type) {
	case *exec.Error:
		if err.Err == exec.ErrNotFound {
			return
		}
		panic(err)
	case error:
		panic(err)
	}
	s := buf.String()
	q := wout.body.q0
	wout.body.Insert(s)
	wout.body.Select(q, q+int64(utf8.RuneCountInString(s)))

	// TODO: Come up with a better solution
	wout.buf.Commit()
}
<|endoftext|>


<commit_before>package rpc

import "encoding/gob"

func init() {
	gob.Register(new(map[string]interface{}))
	gob.Register(new(map[string]string))
	gob.Register(make([]interface{}, 0))
	gob.Register(new(BasicError))
}
<commit_msg>remote duplicate gob.Register(new(map[string]interface{}))<commit_after>package rpc

import "encoding/gob"

func init() {
	gob.Register(new(map[string]string))
	gob.Register(make([]interface{}, 0))
	gob.Register(new(BasicError))
}
<|endoftext|>


<commit_before>// Copyright 2020 The Prometheus 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 httputil

import (
	"context"
	"net"
	"net/http"

	"github.com/prometheus/prometheus/promql"
)

type ctxParam int

var pathParam ctxParam

// ContextWithPath returns a new context with the given path to be used later
// when logging the query.
func ContextWithPath(ctx context.Context, path string) context.Context {
	return context.WithValue(ctx, pathParam, path)
}

// ContextFromRequest returns a new context from a requests with identifiers of
// the request to be used later when logging the query.
func ContextFromRequest(ctx context.Context, r *http.Request) context.Context {
	m := map[string]string{
		"method": r.Method,
	}

	// r.RemoteAddr has no defined format, so don't return error if we cannot split it into IP:Port.
	ip, _, _ := net.SplitHostPort(r.RemoteAddr)
	if ip != "" {
		m["clientIP"] = ip
	}

	var path string
	if v := ctx.Value(pathParam); v != nil {
		path = v.(string)
		m["path"] = path
	}

	return promql.NewOriginContext(ctx, map[string]interface{}{
		"httpRequest": m,
	})
}
<commit_msg>Changed var name.<commit_after>// Copyright 2020 The Prometheus 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 httputil

import (
	"context"
	"net"
	"net/http"

	"github.com/prometheus/prometheus/promql"
)

type ctxParam int

var pathParam ctxParam

// ContextWithPath returns a new context with the given path to be used later
// when logging the query.
func ContextWithPath(ctx context.Context, path string) context.Context {
	return context.WithValue(ctx, pathParam, path)
}

// ContextFromRequest returns a new context from a requests with identifiers of
// the request to be used later when logging the query.
func ContextFromRequest(ctx context.Context, r *http.Request) context.Context {
	reqCtxVal := map[string]string{
		"method": r.Method,
	}

	// r.RemoteAddr has no defined format, so don't return error if we cannot split it into IP:Port.
	ip, _, _ := net.SplitHostPort(r.RemoteAddr)
	if ip != "" {
		reqCtxVal["clientIP"] = ip
	}

	var path string
	if v := ctx.Value(pathParam); v != nil {
		path = v.(string)
		reqCtxVal["path"] = path
	}

	return promql.NewOriginContext(ctx, map[string]interface{}{
		"httpRequest": reqCtxVal,
	})
}
<|endoftext|>


<commit_before>package request
<commit_msg>test updates<commit_after>package request
import (
	"testing"
	"github.com/zubairhamed/canopus"
	"github.com/zubairhamed/betwixt"
	"github.com/stretchr/testify/assert"
)

func TestDefaultRequestObject(t *testing.T) {
	coapReq := canopus.NewRequest(canopus.TYPE_CONFIRMABLE, canopus.COAPCODE_204_CHANGED, 12345)
	coapReq.SetRequestURI("/rd")

	def := Default(coapReq, betwixt.OPERATIONTYPE_REGISTER)

	assert.NotNil(t, def.GetMessage())
	assert.Equal(t, uint16(12345), def.GetMessage().MessageId)
	assert.Equal(t, "/rd", def.GetPath())
	assert.Equal(t, betwixt.OPERATIONTYPE_REGISTER, def.GetOperationType())

	assert.NotNil(t, def.GetCoapRequest())
}

func TestNilRequestObject(t *testing.T) {
	nil := Nil(betwixt.OPERATIONTYPE_REGISTER)

	assert.Nil(t, nil.GetMessage())
	assert.Nil(t, nil.GetCoapRequest())
	assert.Equal(t, nil.GetOperationType(), betwixt.OPERATIONTYPE_REGISTER)
	assert.Equal(t, "", nil.GetPath())
}
<|endoftext|>


<commit_before>package zbibot

import (
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"net/url"
	"strings"
	"time"

	"github.com/Zaibon/ircbot"
	db "github.com/Zaibon/ircbot/database"
)

const (
	apiRoot = "http://lmk.zaibon.be/"
)

// var tokens map[string]string

type LetMeKnow struct {
	dbConn *db.DB

	tokens map[string]string
}

func NewLetMeKnow(bot *ircbot.IrcBot) *LetMeKnow {
	conn, err := bot.DBConnection()
	if err != nil {
		panic(err)
	}

	initDB(conn)
	return &LetMeKnow{
		dbConn: conn,
		tokens: map[string]string{},
	}
}

func initDB(db *db.DB) {
	if err := db.Exec(`CREATE TABLE IF NOT EXISTS lmk_tokens(
		id INTEGER CONSTRAINT line_PK PRIMARY KEY,
		prefix string,
		token,
		timestamp INTEGER)`); err != nil {

		panic(err)
	}
}

func (l *LetMeKnow) Command() []string {
	return []string{".lmk"}
}

func (l *LetMeKnow) Usage() string {
	return fmt.Sprintf(".lmk list|add")
}

func (l *LetMeKnow) Do(b *ircbot.IrcBot, msg *ircbot.IrcMsg) {
	if len(msg.Trailing) < 2 {
		b.Say(msg.Channel(), "shows cmd:")
		b.Say(msg.Channel(), "list | search :title | ep :season :episode :title | add :title")
		b.Say(msg.Channel(), "users cmd:")
		b.Say(msg.Channel(), "signup :mail :username :password | signin :username :password")

		return
	}

	cmd := msg.Trailing[1]

	//check if token is available if the cmd requiest it
	var (
		token string
		err   error
	)
	if cmd != "signup" && cmd != "signin" {
		token, err = l.getToken(msg.Prefix)
		if err != nil {
			if err == io.EOF {
				err = fmt.Errorf("token non disponible, veuillez vous authentifier")
			}
			b.Say(msg.Channel(), err.Error())
			return
		}
	}

	switch cmd {
	case "list":
		l.doShowsList(b, msg, token)

	case "search":
		l.doShowsSearch(b, msg, token)

	case "ep":
		l.doShowsSearchEp(b, msg, token)

	case "add":
		l.doShowsAdd(b, msg, token)

	case "signup":
		l.doUsersSignUp(b, msg)

	case "signin":
		l.doUsersSignIn(b, msg)
	}
}

type APIResp struct {
	Status  string          `json:"status"`
	Payload json.RawMessage `json:"msg"`
}

func (l *LetMeKnow) doShowsAdd(b *ircbot.IrcBot, msg *ircbot.IrcMsg, token string) error {
	if len(msg.Trailing) < 3 {
		b.Say(msg.Channel(), "missing parameter")
		return nil
	}

	title := url.QueryEscape(strings.Join(msg.Trailing[2:], " "))
	apiURL := fmt.Sprintf("%s%s/%s?token=%s", apiRoot, "shows/add", title, token)
	resp, err := http.Post(apiURL, "text/html", nil)
	if err != nil {
		fmt.Println("error post: ", err)
		return err
	}
	defer resp.Body.Close()

	apiResp := &APIResp{}
	if err := json.NewDecoder(resp.Body).Decode(&apiResp); err != nil {
		fmt.Println("error decoding : ", err)
		return err
	}

	if err := checkApiRespError(apiResp, b, msg); err != nil {
		fmt.Println("error decode :", err)
		return err
	}

	if apiResp.Status == "ok" {
		var addMsg string
		if err := json.Unmarshal(apiResp.Payload, &addMsg); err != nil {
			fmt.Println("error decode : ", err)
			return err
		}
		b.Say(msg.Channel(), addMsg)
	}
	return nil
}

type showsList []struct {
	Title string `json:"title"`
}

func (l *LetMeKnow) doShowsList(b *ircbot.IrcBot, msg *ircbot.IrcMsg, token string) error {
	url := fmt.Sprintf("%s%s?token=%s", apiRoot, "shows/list", token)
	resp, err := http.Get(url)
	if err != nil {
		fmt.Println("error : ", err)
		return err
	}
	defer resp.Body.Close()

	apiResp := &APIResp{}
	if err := json.NewDecoder(resp.Body).Decode(apiResp); err != nil {
		fmt.Println("list error : ", err)
		return err
	}
	if err := checkApiRespError(apiResp, b, msg); err != nil {
		return err
	}

	if apiResp.Status == "ok" {
		shows := showsList{}
		if err := json.Unmarshal(apiResp.Payload, &shows); err != nil {
			fmt.Println("list error :", err)
			return err
		}
		for _, title := range shows {
			b.Say(msg.Channel(), title.Title)
		}
	}
	return err
}

type showsSearchResp []struct {
	ID struct {
		ID string `json:"$oid"`
	} `json:"_id"`
	BannerURL string  `json:"banner_url"`
	BeginYear float64 `json:"begin_year"`
	CreatedAt string  `json:"created_at"`
	Overview  string  `json:"overview"`
	PosterURL string  `json:"poster_url"`
	Slug      string  `json:"slug"`
	Title     string  `json:"title"`
	UpdatedAt string  `json:"updated_at"`
}

func (l *LetMeKnow) doShowsSearch(b *ircbot.IrcBot, msg *ircbot.IrcMsg, token string) error {
	if len(msg.Trailing) < 3 {
		b.Say(msg.Channel(), "missing parameter")
		return nil
	}

	title := url.QueryEscape(strings.Join(msg.Trailing[2:], " "))
	apiURL := fmt.Sprintf("%s%s/%s?token=%s", apiRoot, "shows/search", title, token)
	resp, err := http.Get(apiURL)
	if err != nil {
		fmt.Println("search error get :", err)
		return err
	}
	defer resp.Body.Close()

	apiResp := &APIResp{}
	if err := json.NewDecoder(resp.Body).Decode(apiResp); err != nil {
		fmt.Println("search error decode :", err)
		return err
	}

	if err := checkApiRespError(apiResp, b, msg); err != nil {
		return err
	}

	if apiResp.Status == "ok" {
		resp := showsSearchResp{}
		if err := json.Unmarshal(apiResp.Payload, &resp); err != nil {
			fmt.Println("search decode error :", err)
			return err
		}

		for _, show := range resp {
			b.Say(msg.Channel(), fmt.Sprintf("title : %s", show.Title))
			b.Say(msg.Channel(), fmt.Sprintf("Overview : %s", show.Overview))
		}
	}
	return nil
}

type showsSearchEpResp struct {
	ID struct {
		_Oid string `json:"$oid"`
	} `json:"_id"`
	CreatedAt   string      `json:"created_at"`
	DownloadURL interface{} `json:"download_url"`
	Note        float64     `json:"note"`
	Number      float64     `json:"number"`
	Overview    string      `json:"overview"`
	ReleasedOn  string      `json:"released_on"`
	Season      float64     `json:"season"`
	ShowID      struct {
		_Oid string `json:"$oid"`
	} `json:"show_id"`
	Title     string `json:"title"`
	UpdatedAt string `json:"updated_at"`
}

func (l *LetMeKnow) doShowsSearchEp(b *ircbot.IrcBot, msg *ircbot.IrcMsg, token string) error {
	if len(msg.Trailing) < 5 {
		b.Say(msg.Channel(), "missing parameter")
		return nil
	}

	season := msg.Trailing[2]
	number := msg.Trailing[3]
	title := url.QueryEscape(strings.Join(msg.Trailing[4:], " "))
	apiURL := fmt.Sprintf("%s%s/%s/%s/%s/%s?token=%s", apiRoot, "shows/search", title, "episodes", season, number, token)
	resp, err := http.Get(apiURL)
	if err != nil {
		fmt.Println("search error get :", err)
		return err
	}
	defer resp.Body.Close()

	apiResp := &APIResp{}
	if err := json.NewDecoder(resp.Body).Decode(apiResp); err != nil {
		fmt.Println("search error decode :", err)
		return err
	}

	if err := checkApiRespError(apiResp, b, msg); err != nil {
		return err
	}

	if apiResp.Status == "ok" {
		resp := showsSearchEpResp{}
		if err := json.Unmarshal(apiResp.Payload, &resp); err != nil {
			fmt.Println("search decode error :", err)
			return err
		}

		b.Say(msg.Channel(), fmt.Sprintf("title : %s", resp.Title))
		b.Say(msg.Channel(), fmt.Sprintf("Season : %.0f", resp.Season))
		b.Say(msg.Channel(), fmt.Sprintf("Episode : %.0f", resp.Number))
		b.Say(msg.Channel(), fmt.Sprintf("Overview : %s", resp.Overview))

	}
	return nil
}

func (l *LetMeKnow) doUsersSignUp(b *ircbot.IrcBot, msg *ircbot.IrcMsg) error {
	if len(msg.Trailing) < 5 {
		b.Say(msg.Channel(), "missing parameter")
		return nil
	}

	mail := msg.Trailing[2]
	username := msg.Trailing[3]
	password := msg.Trailing[4]

	url := fmt.Sprintf("%s%s?mail=%s&username=%s&password=%s", apiRoot, "users/sign_up", mail, username, password)
	resp, err := http.Post(url, "application/json", nil)
	if err != nil {
		fmt.Println("sign_up error get :", err)
		return err
	}
	defer resp.Body.Close()

	apiResp := &APIResp{}
	if err := json.NewDecoder(resp.Body).Decode(apiResp); err != nil {
		fmt.Println("sign_up error decode :", err)
		return err
	}

	if err := checkApiRespError(apiResp, b, msg); err != nil {
		return err
	}

	if apiResp.Status == "ok" {
		resp := ""
		if err := json.Unmarshal(apiResp.Payload, &resp); err != nil {
			fmt.Println("sign_up decode error :", err)
			return err
		}
		b.Say(msg.Channel(), resp)
	}
	return nil
}

func (l *LetMeKnow) doUsersSignIn(b *ircbot.IrcBot, msg *ircbot.IrcMsg) error {
	if len(msg.Trailing) < 4 {
		b.Say(msg.Channel(), "missing parameter")
		return nil
	}

	username := msg.Trailing[2]
	password := msg.Trailing[3]

	url := fmt.Sprintf("%s%s?username=%s&password=%s", apiRoot, "users/sign_in", username, password)
	fmt.Println("DEBUG :", url)
	resp, err := http.Get(url)
	if err != nil {
		fmt.Println("sign_in error get :", err)
		return err
	}
	defer resp.Body.Close()

	apiResp := &APIResp{}
	if err := json.NewDecoder(resp.Body).Decode(apiResp); err != nil {
		fmt.Println("sign_in error decode :", err)
		return err
	}

	if err := checkApiRespError(apiResp, b, msg); err != nil {
		return err
	}

	if apiResp.Status == "ok" {
		token := ""
		if err := json.Unmarshal(apiResp.Payload, &token); err != nil {
			fmt.Println("sign_in decode error :", err)
			return err
		}

		sql := "INSERT INTO lmk_tokens(prefix,token,timestamp) VALUES ($prefix,$token,$timestamp)"
		if err := l.dbConn.Exec(sql, msg.Prefix, token, time.Now()); err != nil {
			b.Say(msg.Nick(), err.Error())
		}

		//save token in memory for next use
		l.tokens[msg.Prefix] = token
		b.Say(msg.Channel(), "token send in query")
		b.Say(msg.Nick(), fmt.Sprintf("your token : %s", token))
	}
	return nil
}

func checkApiRespError(apiResp *APIResp, b *ircbot.IrcBot, m *ircbot.IrcMsg) error {
	if apiResp.Status == "error" {
		var errMsg string
		if err := json.Unmarshal(apiResp.Payload, &errMsg); err != nil {
			fmt.Println("error decode :", err)
			return err
		}
		b.Say(m.Channel(), errMsg)
	}
	return nil
}

// func isAuthentificated(b *ircbot.IrcBot, msg *ircbot.IrcMsg) bool {
// 	if _, ok := tokens[msg.Prefix]; !ok {
// 		b.Say(msg.Channel(), "vous devez vous authentifier avant de faire cette commande")
// 		return false
// 	}
// 	return true
// }

func (l *LetMeKnow) getToken(prefix string) (string, error) {
	//test if token is in memory
	token, ok := l.tokens[prefix]
	if ok {
		return token, nil
	}

	//if not, try to retreive from database
	sql := "SELECT token FROM lmk_tokens WHERE prefix=$prefix"
	stmt, err := l.dbConn.Query(sql, prefix)
	if err != nil {
		return "", err
	}
	err = stmt.Scan(&token)
	if err == nil {
		l.tokens[prefix] = token
	}

	if err := stmt.Close(); err != nil {
		fmt.Printf("ERROR close statement query : %s\n", err)
		return "", err
	}
	return token, nil
}
<commit_msg>change api url of let_me_know + fix sign up<commit_after>package zbibot

import (
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"net/url"
	"strings"
	"time"

	"github.com/Zaibon/ircbot"
	db "github.com/Zaibon/ircbot/database"
)

const (
	apiRoot = "http://lmk.hito.be/"
)

// var tokens map[string]string

type LetMeKnow struct {
	dbConn *db.DB

	tokens map[string]string
}

func NewLetMeKnow(bot *ircbot.IrcBot) *LetMeKnow {
	conn, err := bot.DBConnection()
	if err != nil {
		panic(err)
	}

	initDB(conn)
	return &LetMeKnow{
		dbConn: conn,
		tokens: map[string]string{},
	}
}

func initDB(db *db.DB) {
	if err := db.Exec(`CREATE TABLE IF NOT EXISTS lmk_tokens(
		id INTEGER CONSTRAINT line_PK PRIMARY KEY,
		prefix string,
		token,
		timestamp INTEGER)`); err != nil {

		panic(err)
	}
}

func (l *LetMeKnow) Command() []string {
	return []string{".lmk"}
}

func (l *LetMeKnow) Usage() string {
	return fmt.Sprintf(".lmk list|add")
}

func (l *LetMeKnow) Do(b *ircbot.IrcBot, msg *ircbot.IrcMsg) {
	if len(msg.Trailing) < 2 {
		b.Say(msg.Channel(), "shows cmd:")
		b.Say(msg.Channel(), "list | search :title | ep :season :episode :title | add :title")
		b.Say(msg.Channel(), "users cmd:")
		b.Say(msg.Channel(), "signup :mail :username :password | signin :username :password")

		return
	}

	cmd := msg.Trailing[1]

	//check if token is available if the cmd requiest it
	var (
		token string
		err   error
	)
	if cmd != "signup" && cmd != "signin" {
		token, err = l.getToken(msg.Prefix)
		if err != nil {
			if err == io.EOF {
				err = fmt.Errorf("token non disponible, veuillez vous authentifier")
			}
			b.Say(msg.Channel(), err.Error())
			return
		}
	}

	switch cmd {
	case "list":
		l.doShowsList(b, msg, token)

	case "search":
		l.doShowsSearch(b, msg, token)

	case "ep":
		l.doShowsSearchEp(b, msg, token)

	case "add":
		l.doShowsAdd(b, msg, token)

	case "signup":
		l.doUsersSignUp(b, msg)

	case "signin":
		l.doUsersSignIn(b, msg)
	}
}

type APIResp struct {
	Status  string          `json:"status"`
	Payload json.RawMessage `json:"msg"`
}

func (l *LetMeKnow) doShowsAdd(b *ircbot.IrcBot, msg *ircbot.IrcMsg, token string) error {
	if len(msg.Trailing) < 3 {
		b.Say(msg.Channel(), "missing parameter")
		return nil
	}

	title := url.QueryEscape(strings.Join(msg.Trailing[2:], " "))
	apiURL := fmt.Sprintf("%s%s/%s?token=%s", apiRoot, "shows/add", title, token)
	resp, err := http.Post(apiURL, "text/html", nil)
	if err != nil {
		fmt.Println("error post: ", err)
		return err
	}
	defer resp.Body.Close()

	apiResp := &APIResp{}
	if err := json.NewDecoder(resp.Body).Decode(&apiResp); err != nil {
		fmt.Println("error decoding : ", err)
		return err
	}

	if err := checkApiRespError(apiResp, b, msg); err != nil {
		fmt.Println("error decode :", err)
		return err
	}

	if apiResp.Status == "ok" {
		var addMsg string
		if err := json.Unmarshal(apiResp.Payload, &addMsg); err != nil {
			fmt.Println("error decode : ", err)
			return err
		}
		b.Say(msg.Channel(), addMsg)
	}
	return nil
}

type showsList []struct {
	Title string `json:"title"`
}

func (l *LetMeKnow) doShowsList(b *ircbot.IrcBot, msg *ircbot.IrcMsg, token string) error {
	url := fmt.Sprintf("%s%s?token=%s", apiRoot, "shows/list", token)
	resp, err := http.Get(url)
	if err != nil {
		fmt.Println("error : ", err)
		return err
	}
	defer resp.Body.Close()

	apiResp := &APIResp{}
	if err := json.NewDecoder(resp.Body).Decode(apiResp); err != nil {
		fmt.Println("list error : ", err)
		return err
	}
	if err := checkApiRespError(apiResp, b, msg); err != nil {
		return err
	}

	if apiResp.Status == "ok" {
		shows := showsList{}
		if err := json.Unmarshal(apiResp.Payload, &shows); err != nil {
			fmt.Println("list error :", err)
			return err
		}
		for _, title := range shows {
			b.Say(msg.Channel(), title.Title)
		}
	}
	return err
}

type showsSearchResp []struct {
	ID struct {
		ID string `json:"$oid"`
	} `json:"_id"`
	BannerURL string  `json:"banner_url"`
	BeginYear float64 `json:"begin_year"`
	CreatedAt string  `json:"created_at"`
	Overview  string  `json:"overview"`
	PosterURL string  `json:"poster_url"`
	Slug      string  `json:"slug"`
	Title     string  `json:"title"`
	UpdatedAt string  `json:"updated_at"`
}

func (l *LetMeKnow) doShowsSearch(b *ircbot.IrcBot, msg *ircbot.IrcMsg, token string) error {
	if len(msg.Trailing) < 3 {
		b.Say(msg.Channel(), "missing parameter")
		return nil
	}

	title := url.QueryEscape(strings.Join(msg.Trailing[2:], " "))
	apiURL := fmt.Sprintf("%s%s/%s?token=%s", apiRoot, "shows/search", title, token)
	resp, err := http.Get(apiURL)
	if err != nil {
		fmt.Println("search error get :", err)
		return err
	}
	defer resp.Body.Close()

	apiResp := &APIResp{}
	if err := json.NewDecoder(resp.Body).Decode(apiResp); err != nil {
		fmt.Println("search error decode :", err)
		return err
	}

	if err := checkApiRespError(apiResp, b, msg); err != nil {
		return err
	}

	if apiResp.Status == "ok" {
		resp := showsSearchResp{}
		if err := json.Unmarshal(apiResp.Payload, &resp); err != nil {
			fmt.Println("search decode error :", err)
			return err
		}

		for _, show := range resp {
			b.Say(msg.Channel(), fmt.Sprintf("title : %s", show.Title))
			b.Say(msg.Channel(), fmt.Sprintf("Overview : %s", show.Overview))
		}
	}
	return nil
}

type showsSearchEpResp struct {
	ID struct {
		_Oid string `json:"$oid"`
	} `json:"_id"`
	CreatedAt   string      `json:"created_at"`
	DownloadURL interface{} `json:"download_url"`
	Note        float64     `json:"note"`
	Number      float64     `json:"number"`
	Overview    string      `json:"overview"`
	ReleasedOn  string      `json:"released_on"`
	Season      float64     `json:"season"`
	ShowID      struct {
		_Oid string `json:"$oid"`
	} `json:"show_id"`
	Title     string `json:"title"`
	UpdatedAt string `json:"updated_at"`
}

func (l *LetMeKnow) doShowsSearchEp(b *ircbot.IrcBot, msg *ircbot.IrcMsg, token string) error {
	if len(msg.Trailing) < 5 {
		b.Say(msg.Channel(), "missing parameter")
		return nil
	}

	season := msg.Trailing[2]
	number := msg.Trailing[3]
	title := url.QueryEscape(strings.Join(msg.Trailing[4:], " "))
	apiURL := fmt.Sprintf("%s%s/%s/%s/%s/%s?token=%s", apiRoot, "shows/search", title, "episodes", season, number, token)
	resp, err := http.Get(apiURL)
	if err != nil {
		fmt.Println("search error get :", err)
		return err
	}
	defer resp.Body.Close()

	apiResp := &APIResp{}
	if err := json.NewDecoder(resp.Body).Decode(apiResp); err != nil {
		fmt.Println("search error decode :", err)
		return err
	}

	if err := checkApiRespError(apiResp, b, msg); err != nil {
		return err
	}

	if apiResp.Status == "ok" {
		resp := showsSearchEpResp{}
		if err := json.Unmarshal(apiResp.Payload, &resp); err != nil {
			fmt.Println("search decode error :", err)
			return err
		}

		b.Say(msg.Channel(), fmt.Sprintf("title : %s", resp.Title))
		b.Say(msg.Channel(), fmt.Sprintf("Season : %.0f", resp.Season))
		b.Say(msg.Channel(), fmt.Sprintf("Episode : %.0f", resp.Number))
		b.Say(msg.Channel(), fmt.Sprintf("Overview : %s", resp.Overview))

	}
	return nil
}

func (l *LetMeKnow) doUsersSignUp(b *ircbot.IrcBot, msg *ircbot.IrcMsg) error {
	if len(msg.Trailing) < 5 {
		b.Say(msg.Channel(), "missing parameter")
		return nil
	}

	mail := msg.Trailing[2]
	username := msg.Trailing[3]
	password := msg.Trailing[4]

	url := fmt.Sprintf("%s%s?email=%s&username=%s&password=%s", apiRoot, "users/sign_up", mail, username, password)
	resp, err := http.Post(url, "text/html", nil)
	if err != nil {
		fmt.Println("sign_up error get :", err)
		return err
	}
	defer resp.Body.Close()

	apiResp := &APIResp{}
	if err := json.NewDecoder(resp.Body).Decode(apiResp); err != nil {
		fmt.Println("sign_up error decode :", err)
		return err
	}

	if err := checkApiRespError(apiResp, b, msg); err != nil {
		return err
	}

	if apiResp.Status == "ok" {
		resp := ""
		if err := json.Unmarshal(apiResp.Payload, &resp); err != nil {
			fmt.Println("sign_up decode error :", err)
			return err
		}
		b.Say(msg.Channel(), resp)
	}
	return nil
}

func (l *LetMeKnow) doUsersSignIn(b *ircbot.IrcBot, msg *ircbot.IrcMsg) error {
	if len(msg.Trailing) < 4 {
		b.Say(msg.Channel(), "missing parameter")
		return nil
	}

	username := msg.Trailing[2]
	password := msg.Trailing[3]

	url := fmt.Sprintf("%s%s?username=%s&password=%s", apiRoot, "users/sign_in", username, password)
	fmt.Println("DEBUG :", url)
	resp, err := http.Get(url)
	if err != nil {
		fmt.Println("sign_in error get :", err)
		return err
	}
	defer resp.Body.Close()

	apiResp := &APIResp{}
	if err := json.NewDecoder(resp.Body).Decode(apiResp); err != nil {
		fmt.Println("sign_in error decode :", err)
		return err
	}

	if err := checkApiRespError(apiResp, b, msg); err != nil {
		return err
	}

	if apiResp.Status == "ok" {
		token := ""
		if err := json.Unmarshal(apiResp.Payload, &token); err != nil {
			fmt.Println("sign_in decode error :", err)
			return err
		}

		sql := "INSERT INTO lmk_tokens(prefix,token,timestamp) VALUES ($prefix,$token,$timestamp)"
		if err := l.dbConn.Exec(sql, msg.Prefix, token, time.Now()); err != nil {
			b.Say(msg.Nick(), err.Error())
		}

		//save token in memory for next use
		l.tokens[msg.Prefix] = token
		b.Say(msg.Channel(), "token send in query")
		b.Say(msg.Nick(), fmt.Sprintf("your token : %s", token))
	}
	return nil
}

func checkApiRespError(apiResp *APIResp, b *ircbot.IrcBot, m *ircbot.IrcMsg) error {
	if apiResp.Status == "error" {
		var errMsg string
		if err := json.Unmarshal(apiResp.Payload, &errMsg); err != nil {
			fmt.Println("error decode :", err)
			return err
		}
		b.Say(m.Channel(), errMsg)
	}
	return nil
}

// func isAuthentificated(b *ircbot.IrcBot, msg *ircbot.IrcMsg) bool {
// 	if _, ok := tokens[msg.Prefix]; !ok {
// 		b.Say(msg.Channel(), "vous devez vous authentifier avant de faire cette commande")
// 		return false
// 	}
// 	return true
// }

func (l *LetMeKnow) getToken(prefix string) (string, error) {
	//test if token is in memory
	token, ok := l.tokens[prefix]
	if ok {
		return token, nil
	}

	//if not, try to retreive from database
	sql := "SELECT token FROM lmk_tokens WHERE prefix=$prefix"
	stmt, err := l.dbConn.Query(sql, prefix)
	if err != nil {
		return "", err
	}
	err = stmt.Scan(&token)
	if err == nil {
		l.tokens[prefix] = token
	}

	if err := stmt.Close(); err != nil {
		fmt.Printf("ERROR close statement query : %s\n", err)
		return "", err
	}
	return token, nil
}
<|endoftext|>


<commit_before>package main_test

import (
	"os"
	"path/filepath"

	cli "github.com/heroku/cli"

	. "github.com/onsi/ginkgo"
	"github.com/onsi/ginkgo/reporters"
	. "github.com/onsi/gomega"

	"testing"
)

func TestCLI(t *testing.T) {
	os.Setenv("TESTING", "1")
	RegisterFailHandler(Fail)
	testReports := os.Getenv("CIRCLE_TEST_REPORTS")
	if testReports != "" {
		path := filepath.Join(testReports, "go", "results.xml")
		os.MkdirAll(filepath.Dir(path), 0755)
		junitReporter := reporters.NewJUnitReporter(path)
		RunSpecsWithDefaultAndCustomReporters(t, "CLI Suite", []Reporter{junitReporter})
	} else {
		RunSpecs(t, "CLI Suite")
	}
}

var errLogPath = filepath.Join("tmp", "error.log")
var _ = BeforeSuite(func() {
	cli.ErrLogPath = errLogPath
	cli.ErrorArrow = "!"
})

var _ = AfterSuite(func() {
	os.Remove(errLogPath)
})
<commit_msg>ensure log dir is created<commit_after>package main_test

import (
	"os"
	"path/filepath"

	cli "github.com/heroku/cli"

	. "github.com/onsi/ginkgo"
	"github.com/onsi/ginkgo/reporters"
	. "github.com/onsi/gomega"

	"testing"
)

func TestCLI(t *testing.T) {
	os.Setenv("TESTING", "1")
	RegisterFailHandler(Fail)
	testReports := os.Getenv("CIRCLE_TEST_REPORTS")
	if testReports != "" {
		path := filepath.Join(testReports, "go", "results.xml")
		os.MkdirAll(filepath.Dir(path), 0755)
		junitReporter := reporters.NewJUnitReporter(path)
		RunSpecsWithDefaultAndCustomReporters(t, "CLI Suite", []Reporter{junitReporter})
	} else {
		RunSpecs(t, "CLI Suite")
	}
}

var errLogPath = filepath.Join("tmp", "error.log")
var _ = BeforeSuite(func() {
	os.MkdirAll(filepath.Dir(errLogPath), 0755)
	cli.ErrLogPath = errLogPath
	cli.ErrorArrow = "!"
})

var _ = AfterSuite(func() {
	os.Remove(errLogPath)
})
<|endoftext|>