<commit_before>package main

import (
  "strings"
  "log"
  // "fmt"
//  "regexp"
  "bytes"
  "encoding/json"
  "os"
  "strconv"
  "regexp"
  "github.com/lookify/town/cluster"
  dockerapi "github.com/fsouza/go-dockerclient"
)

const DEFAULT_ENDPOINT = "unix:///var/run/docker.sock"

var (
  SCALE_NUM_REG, _ = regexp.Compile("\\$\\{SCALE_NUM:(.+)\\}")
//  SCALE_TOTAL_REG, _ = regexp.Compile("\\$\\{SCALE_NUM:(.+)\\}")
  HOSTS_REG, _ = regexp.Compile("\\$\\{(.+)_HOSTS\\}")
)

type Town struct {
  cluster *cluster.Cluster
  docker *dockerapi.Client

//  containers []*dockerapi.Container
}

func NewTown() *Town {
  return &Town{
    cluster: nil,
    docker: nil,
    // containers: []*dockerapi.Container{}
  }
}

func (t *Town) ReadFile() {
  t.cluster = cluster.NewCluster()
  t.cluster.ReadFile()
}

func (t *Town) Connect() {
  envHost := os.Getenv("DOCKER_HOST")
  endpoint := DEFAULT_ENDPOINT
  if (envHost != "") {
    endpoint = envHost;
  }
  log.Println("Using Docker API endpont: ", endpoint)
  docker, err := dockerapi.NewClient( endpoint )
  if err != nil {
    log.Println("Can't connect to the docker")
  }
  t.docker = docker
}

func (t *Town) Provision(checkChanged bool) {
  allContainers, err := t.docker.ListContainers(dockerapi.ListContainersOptions{
    All: true,
  })
  if err == nil {
    for _, listing := range allContainers {
      container, err := t.docker.InspectContainer(listing.ID)
      if err == nil {
        name := container.Name[1:]
        node, index := t.cluster.FindNodeByName(name)
        if node != nil && index > 0 {
          if node.Container.Exist == nil {
            node.Container.Exist = []cluster.ExistContainer{}
          }
          runningContainer := cluster.NewExistContainer(listing.ID, name, index, container.State.Running)
          if checkChanged {
            node.Container.Changed = t.isChangedImage(node, container)
          }
          node.Container.Exist = append(node.Container.Exist, runningContainer);
        }
      } else {
        log.Println("[ERROR] Unable to inspect container:", listing.ID[:12], err)
      }
    }

    if checkChanged {
      t.cluster.AddChangeDependant()
    }
    } else {
      log.Println("[ERROR] Can't start provision")
    }
}

/**
 * Check node and running container for changes.
 * TODO: add cache to docker call.
 **/
func (t *Town) isChangedImage(node *cluster.Node, container *dockerapi.Container) bool {
  var imageName = container.Image
  image , error := t.docker.InspectImage(imageName)
  if error == nil {
    secondImage , secondError := t.docker.InspectImage(node.Container.Image)
    if secondError == nil {
      return secondImage.Created.After(image.Created)
    } else {
      log.Println("[ERROR] Could not inspect image ", node.Container.Name)
    }
  } else {
    log.Println("[ERROR] Could not inspect image ", imageName)
  }
  return false
}

func (t *Town) StopContainers(checkChanged bool) {
  log.Println("Stop...")
  //for node := range t.cluster.nodes {
  for i := len(t.cluster.Nodes) - 1; i >= 0; i-- {
    node := t.cluster.Nodes[i]
    if (!checkChanged || node.Container.Changed) && len(node.Container.Exist) > 0 {
      for _, container := range node.Container.Exist {
        if container.Running {
          err := t.docker.StopContainer(container.ID, 10)
          if err == nil {
            log.Println("   -  ", container.Name)
          } else {
            log.Println("   -  ", container.Name, " failed ", err)
          }
        }
      }
    }
  }
  log.Println("=============================")
}

func (t *Town) RemoveContainers(checkChanged bool) {
  log.Println("Remove...")
  //for node := range t.cluster.nodes {
  for i := len(t.cluster.Nodes) - 1; i >= 0; i-- {
    node := t.cluster.Nodes[i]
    if (!checkChanged || node.Container.Changed) && len(node.Container.Exist) > 0 {
      for _, container := range node.Container.Exist {
        err := t.docker.RemoveContainer(dockerapi.RemoveContainerOptions{
          ID: container.ID,
          RemoveVolumes: false,
        })
        if err == nil {
          log.Println("   -  ", container.Name)
        } else {
          log.Println("   -  ", container.Name, " failed ", err)
        }
      }
    }
  }
  log.Println("=============================")
}

func (t *Town) CreateContainer(node *cluster.Node, index int) (string, string) {
  containerName := node.Container.Name + "-" + strconv.Itoa(index)

  log.Println("   -  ", containerName)

  node.Container.Hostname = containerName // ?? Help !!!!

  env :=  make([]string, 0, cap(node.Container.Environment))
  for _, e := range node.Container.Environment {
    env = append(env, t.exec(e, index))
  }

  volumes := make(map[string]struct{})
  binds := make([]string, 0, cap(node.Container.Volumes))
  if len(node.Container.Volumes) > 0 {
    for _, volume := range node.Container.Volumes {
      volume = t.exec(volume, index)
      vol := strings.Split(volume, ":")
      if len(vol) > 1 {
        volumes[vol[1]] = struct{}{}
      } else {
        volumes[vol[0]] = struct{}{}
      }
      binds = append(binds, volume)
    }
  }

  dockerConfig := dockerapi.Config{
      Image: node.Container.Image,
      Hostname: node.Container.Hostname,
      PortSpecs: node.Container.Ports,
      Env: env,
      Volumes: volumes,

      AttachStdout: false,
      AttachStdin: false,
      AttachStderr: false,

      Tty: false,

      //Cmd: []
  }

  if len(node.Container.Command) > 0 {
    cmd := t.exec(node.Container.Command, index)
    dockerConfig.Cmd = []string{ cmd }
  }

  // just info
  //for _, l := range node.status.links {
  //  log.Println("     * ", l)
  //}

  // create links
  links := t.cluster.GetLinks(node)

  portBindings := map[dockerapi.Port][]dockerapi.PortBinding{}
  // create ports
  for _, ports := range node.Container.Ports {

    port := strings.Split(ports, ":")
    var p dockerapi.Port

    if len(port) > 1 {
      p = dockerapi.Port(port[1] + "/tcp")
    } else {
      p = dockerapi.Port(port[0] + "/tcp")
    }

    if portBindings[p] == nil {
      portBindings[p] = [] dockerapi.PortBinding {}
    }

    portBindings[p] = append(portBindings[p], dockerapi.PortBinding{
      HostIP: "",
      HostPort: port[0],
    })
  }

  hostConfig := dockerapi.HostConfig{
    Binds: binds,
    Links: links, //, [],
    PortBindings: portBindings,
    NetworkMode: "bridge",
    PublishAllPorts: false,
    Privileged: node.Container.Privileged,
  }

  opts := dockerapi.CreateContainerOptions{Name: containerName, Config: &dockerConfig, HostConfig: &hostConfig}
  container, err := t.docker.CreateContainer(opts)
  if err == nil {
    retry := 5
    for retry > 0 {
      error := t.docker.StartContainer(container.ID, &hostConfig)
      if error != nil {
        // log.Println("start error: ", error);

        out, err := json.Marshal(container)
        if err != nil {
            panic (err)
        }
        // fmt.Println(string(out))

        retry--;
        if retry == 0 {
          log.Println(" Strat failed after 5 retries: ", string(out))
        }
        // log.Println("retry: ", retry);
      } else {
        inspect, inspectError := t.docker.InspectContainer(container.ID)
        if inspectError == nil {
          //links = append(links, inspect.NetworkSettings.IPAddress + "  " + containerName)
          //ids = append(ids, container.ID)
          return container.ID, inspect.NetworkSettings.IPAddress + "  " + containerName
        } else {
          log.Println("Inpect ", container.ID, " error ", inspectError)
        }
        //retry = 0
        break;
      }
    }
  } else {
    log.Println("error: ", err);
  }

  return "", ""
}

func (t *Town) CreateContainers(checkChanged bool) {
  log.Println("Create...")
  for _, node := range t.cluster.Nodes {

    if !checkChanged || node.Container.Changed {
      ids := make([]string, 0, node.Container.Scale )

      hosts := make([]string, 0, node.Container.Scale)

      for i := 1; i <= node.Container.Scale; i++ {
        log.Println(node.Container.Name, "  image: ", node.Container.Image)
        id, host := t.CreateContainer(node, i)
        ids = append(ids, id)
        hosts = append(hosts, host)
      }

      if len(ids) > 1 {
        for index, id := range ids {
          var buffer bytes.Buffer

          buffer.WriteString("echo -e '")
          for i := 0; i < len(hosts); i++ {
            if i != index {
              buffer.WriteString("\n")
              buffer.WriteString(hosts[i])
            }
          }
          buffer.WriteString("' >> /etc/hosts; touch /tmp/host-generated")

          config := dockerapi.CreateExecOptions{
            Container:    id,
            AttachStdin:  true,
            AttachStdout: true,
            AttachStderr: false,
            Tty:          false,
            Cmd:          []string{"bash", "-c", buffer.String()},
          }
          execObj, err := t.docker.CreateExec(config)
          if err == nil {
            config := dockerapi.StartExecOptions{
              Detach: true,
            }
            err := t.docker.StartExec(execObj.ID, config)
            if err != nil {
              log.Println("Start exec failed ", id, " error: ", err)
            }
          } else {
            log.Println("Create exec failed ", id, " error: ", err)
          }
        }
      }
    }
  }
}

func (t *Town) exec(text string, scale int) string {
  replace := strings.Replace(text, "${SCALE_NUM}", strconv.Itoa(scale), -1)
  match := SCALE_NUM_REG.FindAllStringSubmatch(replace, -1)
  hostMatch := HOSTS_REG.FindAllStringSubmatch(replace, -1)
  if len(match) > 0 {
    if len(match[0]) > 1 {
      nums := strings.Split(match[0][1], ",")
      if len(nums) > (scale - 1) {
        replace = strings.Replace(replace, match[0][0], nums[scale - 1], -1)
      }
    }
  }
  if len(hostMatch) > 0 {
    if len(hostMatch[0]) > 1 {
      //nums := strings.Split(, ",")
      name := strings.ToLower(hostMatch[0][1])
      node := t.cluster.FindNodeByID(name)

      var buffer bytes.Buffer
      for i := 1; i <= node.Container.Scale; i++ {
        buffer.WriteString(name)
        buffer.WriteString("-")
        buffer.WriteString(strconv.Itoa( i ))
        if i != node.Container.Scale {
          buffer.WriteString(",")
        }
      }
      replace = strings.Replace(replace, hostMatch[0][0], buffer.String(), -1)
    }
  }
  return replace
}
<commit_msg>check provision<commit_after>package main

import (
  "strings"
  "log"
  // "fmt"
//  "regexp"
  "bytes"
  "encoding/json"
  "os"
  "strconv"
  "regexp"
  "github.com/lookify/town/cluster"
  dockerapi "github.com/fsouza/go-dockerclient"
)

const DEFAULT_ENDPOINT = "unix:///var/run/docker.sock"

var (
  SCALE_NUM_REG, _ = regexp.Compile("\\$\\{SCALE_NUM:(.+)\\}")
//  SCALE_TOTAL_REG, _ = regexp.Compile("\\$\\{SCALE_NUM:(.+)\\}")
  HOSTS_REG, _ = regexp.Compile("\\$\\{(.+)_HOSTS\\}")
)

type Town struct {
  cluster *cluster.Cluster
  docker *dockerapi.Client

//  containers []*dockerapi.Container
}

func NewTown() *Town {
  return &Town{
    cluster: nil,
    docker: nil,
    // containers: []*dockerapi.Container{}
  }
}

func (t *Town) ReadFile() {
  t.cluster = cluster.NewCluster()
  t.cluster.ReadFile()
}

func (t *Town) Connect() {
  envHost := os.Getenv("DOCKER_HOST")
  endpoint := DEFAULT_ENDPOINT
  if (envHost != "") {
    endpoint = envHost;
  }
  log.Println("Using Docker API endpont: ", endpoint)
  docker, err := dockerapi.NewClient( endpoint )
  if err != nil {
    log.Println("Can't connect to the docker")
  }
  t.docker = docker
}

func (t *Town) Provision(checkChanged bool) {
  allContainers, err := t.docker.ListContainers(dockerapi.ListContainersOptions{
    All: true,
  })
  if err == nil {
    for _, listing := range allContainers {
      container, err := t.docker.InspectContainer(listing.ID)
      if err == nil {
        name := container.Name[1:]
        node, index := t.cluster.FindNodeByName(name)
        if node != nil && index > 0 {
          if node.Container.Exist == nil {
            node.Container.Exist = []cluster.ExistContainer{}
          }
          runningContainer := cluster.NewExistContainer(listing.ID, name, index, container.State.Running)
          if checkChanged {
            node.Container.Changed = t.isChangedImage(node, container)
          } else {
            node.Container.Changed = true
          }
          node.Container.Exist = append(node.Container.Exist, runningContainer);
          log.Println("add provision ", name)
        }
      } else {
        log.Println("[ERROR] Unable to inspect container:", listing.ID[:12], err)
      }
    }

    if checkChanged {
      t.cluster.AddChangeDependant()
    }
  } else {
    log.Println("[ERROR] Can't start provision")
  }
}

/**
 * Check node and running container for changes.
 * TODO: add cache to docker call.
 **/
func (t *Town) isChangedImage(node *cluster.Node, container *dockerapi.Container) bool {
  var imageName = container.Image
  image , error := t.docker.InspectImage(imageName)
  if error == nil {
    secondImage , secondError := t.docker.InspectImage(node.Container.Image)
    if secondError == nil {
      return secondImage.Created.After(image.Created)
    } else {
      log.Println("[ERROR] Could not inspect image ", node.Container.Name)
    }
  } else {
    log.Println("[ERROR] Could not inspect image ", imageName)
  }
  return false
}

func (t *Town) StopContainers(checkChanged bool) {
  log.Println("Stop...")
  //for node := range t.cluster.nodes {
  for i := len(t.cluster.Nodes) - 1; i >= 0; i-- {
    node := t.cluster.Nodes[i]
    if (!checkChanged || node.Container.Changed) && len(node.Container.Exist) > 0 {
      for _, container := range node.Container.Exist {
        if container.Running {
          err := t.docker.StopContainer(container.ID, 10)
          if err == nil {
            log.Println("   -  ", container.Name)
          } else {
            log.Println("   -  ", container.Name, " failed ", err)
          }
        }
      }
    }
  }
  log.Println("=============================")
}

func (t *Town) RemoveContainers(checkChanged bool) {
  log.Println("Remove...")
  //for node := range t.cluster.nodes {
  for i := len(t.cluster.Nodes) - 1; i >= 0; i-- {
    node := t.cluster.Nodes[i]
    if (!checkChanged || node.Container.Changed) && len(node.Container.Exist) > 0 {
      for _, container := range node.Container.Exist {
        err := t.docker.RemoveContainer(dockerapi.RemoveContainerOptions{
          ID: container.ID,
          RemoveVolumes: false,
        })
        if err == nil {
          log.Println("   -  ", container.Name)
        } else {
          log.Println("   -  ", container.Name, " failed ", err)
        }
      }
    }
  }
  log.Println("=============================")
}

func (t *Town) CreateContainer(node *cluster.Node, index int) (string, string) {
  containerName := node.Container.Name + "-" + strconv.Itoa(index)

  log.Println("   -  ", containerName)

  node.Container.Hostname = containerName // ?? Help !!!!

  env :=  make([]string, 0, cap(node.Container.Environment))
  for _, e := range node.Container.Environment {
    env = append(env, t.exec(e, index))
  }

  volumes := make(map[string]struct{})
  binds := make([]string, 0, cap(node.Container.Volumes))
  if len(node.Container.Volumes) > 0 {
    for _, volume := range node.Container.Volumes {
      volume = t.exec(volume, index)
      vol := strings.Split(volume, ":")
      if len(vol) > 1 {
        volumes[vol[1]] = struct{}{}
      } else {
        volumes[vol[0]] = struct{}{}
      }
      binds = append(binds, volume)
    }
  }

  dockerConfig := dockerapi.Config{
      Image: node.Container.Image,
      Hostname: node.Container.Hostname,
      PortSpecs: node.Container.Ports,
      Env: env,
      Volumes: volumes,

      AttachStdout: false,
      AttachStdin: false,
      AttachStderr: false,

      Tty: false,

      //Cmd: []
  }

  if len(node.Container.Command) > 0 {
    cmd := t.exec(node.Container.Command, index)
    dockerConfig.Cmd = []string{ cmd }
  }

  // just info
  //for _, l := range node.status.links {
  //  log.Println("     * ", l)
  //}

  // create links
  links := t.cluster.GetLinks(node)

  portBindings := map[dockerapi.Port][]dockerapi.PortBinding{}
  // create ports
  for _, ports := range node.Container.Ports {

    port := strings.Split(ports, ":")
    var p dockerapi.Port

    if len(port) > 1 {
      p = dockerapi.Port(port[1] + "/tcp")
    } else {
      p = dockerapi.Port(port[0] + "/tcp")
    }

    if portBindings[p] == nil {
      portBindings[p] = [] dockerapi.PortBinding {}
    }

    portBindings[p] = append(portBindings[p], dockerapi.PortBinding{
      HostIP: "",
      HostPort: port[0],
    })
  }

  hostConfig := dockerapi.HostConfig{
    Binds: binds,
    Links: links, //, [],
    PortBindings: portBindings,
    NetworkMode: "bridge",
    PublishAllPorts: false,
    Privileged: node.Container.Privileged,
  }

  opts := dockerapi.CreateContainerOptions{Name: containerName, Config: &dockerConfig, HostConfig: &hostConfig}
  container, err := t.docker.CreateContainer(opts)
  if err == nil {
    retry := 5
    for retry > 0 {
      error := t.docker.StartContainer(container.ID, &hostConfig)
      if error != nil {
        // log.Println("start error: ", error);

        out, err := json.Marshal(container)
        if err != nil {
            panic (err)
        }
        // fmt.Println(string(out))

        retry--;
        if retry == 0 {
          log.Println(" Strat failed after 5 retries: ", string(out))
        }
        // log.Println("retry: ", retry);
      } else {
        inspect, inspectError := t.docker.InspectContainer(container.ID)
        if inspectError == nil {
          //links = append(links, inspect.NetworkSettings.IPAddress + "  " + containerName)
          //ids = append(ids, container.ID)
          return container.ID, inspect.NetworkSettings.IPAddress + "  " + containerName
        } else {
          log.Println("Inpect ", container.ID, " error ", inspectError)
        }
        //retry = 0
        break;
      }
    }
  } else {
    log.Println("error: ", err);
  }

  return "", ""
}

func (t *Town) CreateContainers(checkChanged bool) {
  log.Println("Create...")
  for _, node := range t.cluster.Nodes {

    if !checkChanged || node.Container.Changed {
      ids := make([]string, 0, node.Container.Scale )

      hosts := make([]string, 0, node.Container.Scale)

      for i := 1; i <= node.Container.Scale; i++ {
        log.Println(node.Container.Name, "  image: ", node.Container.Image)
        id, host := t.CreateContainer(node, i)
        ids = append(ids, id)
        hosts = append(hosts, host)
      }

      if len(ids) > 1 {
        for index, id := range ids {
          var buffer bytes.Buffer

          buffer.WriteString("echo -e '")
          for i := 0; i < len(hosts); i++ {
            if i != index {
              buffer.WriteString("\n")
              buffer.WriteString(hosts[i])
            }
          }
          buffer.WriteString("' >> /etc/hosts; touch /tmp/host-generated")

          config := dockerapi.CreateExecOptions{
            Container:    id,
            AttachStdin:  true,
            AttachStdout: true,
            AttachStderr: false,
            Tty:          false,
            Cmd:          []string{"bash", "-c", buffer.String()},
          }
          execObj, err := t.docker.CreateExec(config)
          if err == nil {
            config := dockerapi.StartExecOptions{
              Detach: true,
            }
            err := t.docker.StartExec(execObj.ID, config)
            if err != nil {
              log.Println("Start exec failed ", id, " error: ", err)
            }
          } else {
            log.Println("Create exec failed ", id, " error: ", err)
          }
        }
      }
    }
  }
}

func (t *Town) exec(text string, scale int) string {
  replace := strings.Replace(text, "${SCALE_NUM}", strconv.Itoa(scale), -1)
  match := SCALE_NUM_REG.FindAllStringSubmatch(replace, -1)
  hostMatch := HOSTS_REG.FindAllStringSubmatch(replace, -1)
  if len(match) > 0 {
    if len(match[0]) > 1 {
      nums := strings.Split(match[0][1], ",")
      if len(nums) > (scale - 1) {
        replace = strings.Replace(replace, match[0][0], nums[scale - 1], -1)
      }
    }
  }
  if len(hostMatch) > 0 {
    if len(hostMatch[0]) > 1 {
      //nums := strings.Split(, ",")
      name := strings.ToLower(hostMatch[0][1])
      node := t.cluster.FindNodeByID(name)

      var buffer bytes.Buffer
      for i := 1; i <= node.Container.Scale; i++ {
        buffer.WriteString(name)
        buffer.WriteString("-")
        buffer.WriteString(strconv.Itoa( i ))
        if i != node.Container.Scale {
          buffer.WriteString(",")
        }
      }
      replace = strings.Replace(replace, hostMatch[0][0], buffer.String(), -1)
    }
  }
  return replace
}
<|endoftext|>


<commit_before>package git

/*
#include <git2.h>

extern int _go_git_treewalk(git_tree *tree, git_treewalk_mode mode, void *ptr);
*/
import "C"

import (
	"runtime"
	"unsafe"
)

type Filemode int

const (
	FilemodeTree           Filemode = C.GIT_FILEMODE_TREE
	FilemodeBlob           Filemode = C.GIT_FILEMODE_BLOB
	FilemodeBlobExecutable Filemode = C.GIT_FILEMODE_BLOB_EXECUTABLE
	FilemodeLink           Filemode = C.GIT_FILEMODE_LINK
	FilemodeCommit         Filemode = C.GIT_FILEMODE_COMMIT
)

type Tree struct {
	Object
	cast_ptr *C.git_tree
}

func (t *Tree) AsObject() *Object {
	return &t.Object
}

type TreeEntry struct {
	Name     string
	Id       *Oid
	Type     ObjectType
	Filemode Filemode
}

func newTreeEntry(entry *C.git_tree_entry) *TreeEntry {
	return &TreeEntry{
		C.GoString(C.git_tree_entry_name(entry)),
		newOidFromC(C.git_tree_entry_id(entry)),
		ObjectType(C.git_tree_entry_type(entry)),
		Filemode(C.git_tree_entry_filemode(entry)),
	}
}

func (t Tree) EntryByName(filename string) *TreeEntry {
	cname := C.CString(filename)
	defer C.free(unsafe.Pointer(cname))

	entry := C.git_tree_entry_byname(t.cast_ptr, cname)
	runtime.KeepAlive(t)
	if entry == nil {
		return nil
	}

	return newTreeEntry(entry)
}

// EntryById performs a lookup for a tree entry with the given SHA value.
//
// It returns a *TreeEntry that is owned by the Tree. You don't have to
// free it, but you must not use it after the Tree is freed.
//
// Warning: this must examine every entry in the tree, so it is not fast.
func (t Tree) EntryById(id *Oid) *TreeEntry {
	runtime.LockOSThread()
	defer runtime.UnlockOSThread()

	entry := C.git_tree_entry_byid(t.cast_ptr, id.toC())
	runtime.KeepAlive(t)
	runtime.KeepAlive(id)
	if entry == nil {
		return nil
	}

	return newTreeEntry(entry)
}

// EntryByPath looks up an entry by its full path, recursing into
// deeper trees if necessary (i.e. if there are slashes in the path)
func (t Tree) EntryByPath(path string) (*TreeEntry, error) {
	cpath := C.CString(path)
	defer C.free(unsafe.Pointer(cpath))
	var entry *C.git_tree_entry

	runtime.LockOSThread()
	defer runtime.UnlockOSThread()

	ret := C.git_tree_entry_bypath(&entry, t.cast_ptr, cpath)
	runtime.KeepAlive(t)
	if ret < 0 {
		return nil, MakeGitError(ret)
	}
	defer C.git_tree_entry_free(entry)

	return newTreeEntry(entry), nil
}

func (t Tree) EntryByIndex(index uint64) *TreeEntry {
	entry := C.git_tree_entry_byindex(t.cast_ptr, C.size_t(index))
	runtime.KeepAlive(t)
	if entry == nil {
		return nil
	}

	return newTreeEntry(entry)
}

func (t Tree) EntryCount() uint64 {
	num := C.git_tree_entrycount(t.cast_ptr)
	runtime.KeepAlive(t)
	return uint64(num)
}

type TreeWalkCallback func(string, *TreeEntry) int

//export CallbackGitTreeWalk
func CallbackGitTreeWalk(_root *C.char, _entry unsafe.Pointer, ptr unsafe.Pointer) C.int {
	root := C.GoString(_root)
	entry := (*C.git_tree_entry)(_entry)

	if callback, ok := pointerHandles.Get(ptr).(TreeWalkCallback); ok {
		return C.int(callback(root, newTreeEntry(entry)))
	} else {
		panic("invalid treewalk callback")
	}
}

func (t Tree) Walk(callback TreeWalkCallback) error {
	runtime.LockOSThread()
	defer runtime.UnlockOSThread()

	ptr := pointerHandles.Track(callback)
	defer pointerHandles.Untrack(ptr)

	err := C._go_git_treewalk(
		t.cast_ptr,
		C.GIT_TREEWALK_PRE,
		ptr,
	)
	runtime.KeepAlive(t)
	if err < 0 {
		return MakeGitError(err)
	}

	return nil
}

type TreeBuilder struct {
	ptr  *C.git_treebuilder
	repo *Repository
}

func (v *TreeBuilder) Free() {
	runtime.SetFinalizer(v, nil)
	C.git_treebuilder_free(v.ptr)
}

func (v *TreeBuilder) Insert(filename string, id *Oid, filemode Filemode) error {
	cfilename := C.CString(filename)
	defer C.free(unsafe.Pointer(cfilename))

	runtime.LockOSThread()
	defer runtime.UnlockOSThread()

	err := C.git_treebuilder_insert(nil, v.ptr, cfilename, id.toC(), C.git_filemode_t(filemode))
	runtime.KeepAlive(v)
	runtime.KeepAlive(id)
	if err < 0 {
		return MakeGitError(err)
	}

	return nil
}

func (v *TreeBuilder) Remove(filename string) error {
	cfilename := C.CString(filename)
	defer C.free(unsafe.Pointer(cfilename))

	runtime.LockOSThread()
	defer runtime.UnlockOSThread()

	err := C.git_treebuilder_remove(v.ptr, cfilename)
	runtime.KeepAlive(v)
	if err < 0 {
		return MakeGitError(err)
	}

	return nil
}

func (v *TreeBuilder) Write() (*Oid, error) {
	oid := new(Oid)

	runtime.LockOSThread()
	defer runtime.UnlockOSThread()

	err := C.git_treebuilder_write(oid.toC(), v.ptr)
	runtime.KeepAlive(v)
	if err < 0 {
		return nil, MakeGitError(err)
	}

	return oid, nil
}
<commit_msg>tree: keep tree receiver alive as long as dependent entry is used<commit_after>package git

/*
#include <git2.h>

extern int _go_git_treewalk(git_tree *tree, git_treewalk_mode mode, void *ptr);
*/
import "C"

import (
	"runtime"
	"unsafe"
)

type Filemode int

const (
	FilemodeTree           Filemode = C.GIT_FILEMODE_TREE
	FilemodeBlob           Filemode = C.GIT_FILEMODE_BLOB
	FilemodeBlobExecutable Filemode = C.GIT_FILEMODE_BLOB_EXECUTABLE
	FilemodeLink           Filemode = C.GIT_FILEMODE_LINK
	FilemodeCommit         Filemode = C.GIT_FILEMODE_COMMIT
)

type Tree struct {
	Object
	cast_ptr *C.git_tree
}

func (t *Tree) AsObject() *Object {
	return &t.Object
}

type TreeEntry struct {
	Name     string
	Id       *Oid
	Type     ObjectType
	Filemode Filemode
}

func newTreeEntry(entry *C.git_tree_entry) *TreeEntry {
	return &TreeEntry{
		C.GoString(C.git_tree_entry_name(entry)),
		newOidFromC(C.git_tree_entry_id(entry)),
		ObjectType(C.git_tree_entry_type(entry)),
		Filemode(C.git_tree_entry_filemode(entry)),
	}
}

func (t Tree) EntryByName(filename string) *TreeEntry {
	cname := C.CString(filename)
	defer C.free(unsafe.Pointer(cname))

	entry := C.git_tree_entry_byname(t.cast_ptr, cname)
	if entry == nil {
		return nil
	}

	goEntry := newTreeEntry(entry)
	runtime.KeepAlive(t)
	return goEntry
}

// EntryById performs a lookup for a tree entry with the given SHA value.
//
// It returns a *TreeEntry that is owned by the Tree. You don't have to
// free it, but you must not use it after the Tree is freed.
//
// Warning: this must examine every entry in the tree, so it is not fast.
func (t Tree) EntryById(id *Oid) *TreeEntry {
	runtime.LockOSThread()
	defer runtime.UnlockOSThread()

	entry := C.git_tree_entry_byid(t.cast_ptr, id.toC())
	runtime.KeepAlive(id)
	if entry == nil {
		return nil
	}

	goEntry := newTreeEntry(entry)
	runtime.KeepAlive(t)
	return goEntry
}

// EntryByPath looks up an entry by its full path, recursing into
// deeper trees if necessary (i.e. if there are slashes in the path)
func (t Tree) EntryByPath(path string) (*TreeEntry, error) {
	cpath := C.CString(path)
	defer C.free(unsafe.Pointer(cpath))
	var entry *C.git_tree_entry

	runtime.LockOSThread()
	defer runtime.UnlockOSThread()

	ret := C.git_tree_entry_bypath(&entry, t.cast_ptr, cpath)
	runtime.KeepAlive(t)
	if ret < 0 {
		return nil, MakeGitError(ret)
	}
	defer C.git_tree_entry_free(entry)

	return newTreeEntry(entry), nil
}

func (t Tree) EntryByIndex(index uint64) *TreeEntry {
	entry := C.git_tree_entry_byindex(t.cast_ptr, C.size_t(index))
	if entry == nil {
		return nil
	}

	goEntry := newTreeEntry(entry)
	runtime.KeepAlive(t)
	return goEntry
}

func (t Tree) EntryCount() uint64 {
	num := C.git_tree_entrycount(t.cast_ptr)
	runtime.KeepAlive(t)
	return uint64(num)
}

type TreeWalkCallback func(string, *TreeEntry) int

//export CallbackGitTreeWalk
func CallbackGitTreeWalk(_root *C.char, _entry unsafe.Pointer, ptr unsafe.Pointer) C.int {
	root := C.GoString(_root)
	entry := (*C.git_tree_entry)(_entry)

	if callback, ok := pointerHandles.Get(ptr).(TreeWalkCallback); ok {
		return C.int(callback(root, newTreeEntry(entry)))
	} else {
		panic("invalid treewalk callback")
	}
}

func (t Tree) Walk(callback TreeWalkCallback) error {
	runtime.LockOSThread()
	defer runtime.UnlockOSThread()

	ptr := pointerHandles.Track(callback)
	defer pointerHandles.Untrack(ptr)

	err := C._go_git_treewalk(
		t.cast_ptr,
		C.GIT_TREEWALK_PRE,
		ptr,
	)
	runtime.KeepAlive(t)
	if err < 0 {
		return MakeGitError(err)
	}

	return nil
}

type TreeBuilder struct {
	ptr  *C.git_treebuilder
	repo *Repository
}

func (v *TreeBuilder) Free() {
	runtime.SetFinalizer(v, nil)
	C.git_treebuilder_free(v.ptr)
}

func (v *TreeBuilder) Insert(filename string, id *Oid, filemode Filemode) error {
	cfilename := C.CString(filename)
	defer C.free(unsafe.Pointer(cfilename))

	runtime.LockOSThread()
	defer runtime.UnlockOSThread()

	err := C.git_treebuilder_insert(nil, v.ptr, cfilename, id.toC(), C.git_filemode_t(filemode))
	runtime.KeepAlive(v)
	runtime.KeepAlive(id)
	if err < 0 {
		return MakeGitError(err)
	}

	return nil
}

func (v *TreeBuilder) Remove(filename string) error {
	cfilename := C.CString(filename)
	defer C.free(unsafe.Pointer(cfilename))

	runtime.LockOSThread()
	defer runtime.UnlockOSThread()

	err := C.git_treebuilder_remove(v.ptr, cfilename)
	runtime.KeepAlive(v)
	if err < 0 {
		return MakeGitError(err)
	}

	return nil
}

func (v *TreeBuilder) Write() (*Oid, error) {
	oid := new(Oid)

	runtime.LockOSThread()
	defer runtime.UnlockOSThread()

	err := C.git_treebuilder_write(oid.toC(), v.ptr)
	runtime.KeepAlive(v)
	if err < 0 {
		return nil, MakeGitError(err)
	}

	return oid, nil
}
<|endoftext|>


<commit_before>package hpcloud

/* Identity */
var REGION_URL = "https://region-b.geo-1.identity.hpcloudsvc.com:35357/v2.0/"
var TOKEN_URL = REGION_URL + "tokens"
var TENANT_URL = REGION_URL + "tenants"

/* Object store */
var OBJECT_STORE = "https://region-b.geo-1.objects.hpcloudsvc.com/v1.0/"

/* CDN */
var CDN_URL = "https://region-b.geo-1.cdnmgmt.hpcloudsvc.com/v1.0/"

/* Compute */
var COMPUTE_URL = "https://az-1.region-a.geo-1.compute.hpcloudsvc.com/v1.1/"

/* RDB */
var RDB_URL = "https://region-a.geo-1.cdnmgmt.hpcloudsvc.com/v1.0/"
<commit_msg>Added the DNS url.<commit_after>package hpcloud

/* Identity */
var REGION_URL = "https://region-b.geo-1.identity.hpcloudsvc.com:35357/v2.0/"
var TOKEN_URL = REGION_URL + "tokens"
var TENANT_URL = REGION_URL + "tenants"

/* Object store */
var OBJECT_STORE = "https://region-b.geo-1.objects.hpcloudsvc.com/v1.0/"

/* CDN */
var CDN_URL = "https://region-b.geo-1.cdnmgmt.hpcloudsvc.com/v1.0/"

/* Compute */
var COMPUTE_URL = "https://az-1.region-a.geo-1.compute.hpcloudsvc.com/v1.1/"

/* RDB */
var RDB_URL = "https://region-a.geo-1.cdnmgmt.hpcloudsvc.com/v1.0/"

/* DNS */

var DNS_URL = "https://region-a.geo-1.dns.hpcloudsvc.com/v1/"
<|endoftext|>


<commit_before>// Package urlx parses and normalizes URLs. It favors absolute paths.
package urlx

import (
	"errors"
	"net/url"
	"strings"

	"github.com/PuerkitoBio/purell"
)

var (
	ErrInvalidURL       = errors.New("invalid URL")
	ErrInvalidURLHost   = errors.New("invalid hostname")
	ErrInvalidURLScheme = errors.New("invalid URL scheme")
)

func NormalizeString(s string) (string, error) {
	// Hack for "localhost", as net/url can't handle it.
	if len(s) == 9 && s == "localhost" ||
		len(s) > 9 && (s[0:10] == "localhost:" || s[0:10] == "localhost/") {
		s = "http://" + s
	}

	u, err := url.Parse(s)
	if err != nil {
		return s, err
	}
	if u.Host == "" {
		// url.Parse("example.com") returns Host="", Path="example.com", eh..
		i := strings.IndexByte(u.Path, '/')
		if i == -1 {
			i = len(u.Path)
		}
		if i < 3 {
			// Path too short to contain the actual Host
			return s, ErrInvalidURLHost
		}
		// Move the actual host from Path to Host field
		u.Host = u.Path[:i]
		u.Path = u.Path[i:]
	}
	switch u.Scheme {
	case "http", "https", "HTTP", "HTTPS":
		// nop
	case "":
		// AnyScheme => http
		u.Scheme = "http"
	default:
		return s, ErrInvalidURLScheme
	}
	return purell.NormalizeURL(u, purell.FlagsUsuallySafeGreedy|purell.FlagRemoveDuplicateSlashes|purell.FlagLowercaseScheme|purell.FlagLowercaseHost), nil
}
<commit_msg>Add Validate/Find/Extract/Linkify functions<commit_after>// Package urlx parses and normalizes URLs. It favors absolute paths.
package urlx

import (
	"errors"
	"net"
	"net/http"
	"net/url"
	"regexp"
	"strings"

	"github.com/PuerkitoBio/purell"
)

var (
	ErrInvalidURL       = errors.New("invalid URL")
	ErrInvalidURLHost   = errors.New("invalid hostname")
	ErrInvalidURLScheme = errors.New("invalid URL scheme")
)

func NormalizeString(s string) (string, error) {
	// Hack for "localhost", as net/url can't handle it.
	if len(s) == 9 && s == "localhost" ||
		len(s) > 9 && (s[0:10] == "localhost:" || s[0:10] == "localhost/") {
		s = "http://" + s
	}

	u, err := url.Parse(s)
	if err != nil {
		return s, err
	}
	if u.Host == "" {
		// url.Parse("example.com") returns Host="", Path="example.com", eh..
		i := strings.IndexByte(u.Path, '/')
		if i == -1 {
			i = len(u.Path)
		}
		if i < 3 {
			// Path too short to contain the actual Host
			return s, ErrInvalidURLHost
		}
		// Move the actual host from Path to Host field
		u.Host = u.Path[:i]
		u.Path = u.Path[i:]
	}
	switch u.Scheme {
	case "http", "https", "HTTP", "HTTPS":
		// nop
	case "":
		// AnyScheme => http
		u.Scheme = "http"
	default:
		return s, ErrInvalidURLScheme
	}
	return purell.NormalizeURL(u, purell.FlagsUsuallySafeGreedy|purell.FlagRemoveDuplicateSlashes|purell.FlagLowercaseScheme|purell.FlagLowercaseHost), nil
}

func Validate(rawURL string, dnsCheck bool) error {
	parsed, err := url.Parse(rawURL)
	if err != nil {
		return ErrInvalidURL
	}
	if parsed.Scheme == "" {
		return ErrInvalidURL
	}

	hostPort := strings.Split(parsed.Host, ":")
	hostname := hostPort[0]

	reg := regexp.MustCompile(`[\w\.\-]{2,64}\.[a-zA-Z0-9\-]{2,64}$`)

	if !reg.Match([]byte(hostname)) {
		return ErrInvalidURLHost
	}

	if dnsCheck {
		if _, err := net.ResolveIPAddr("ip", hostname); err != nil {
			return err
		}
	}

	return nil
}

func FindFinal(originalURL string) (string, error) {
	resp, err := http.Get(originalURL)
	if err != nil {
		return "", err
	}

	return resp.Request.URL.String(), nil
}

func Extract(content string, maxURLs int) []string {
	reg := regexp.MustCompile(`(?:(?:https?:\/\/)|(?:www\.))[-a-zA-Z0-9@:%._\+~#=]{2,256}\.[a-z]{2,4}\b(?:[-a-zA-Z0-9@:%_\+.~#?&/=]*)`)
	return reg.FindAllString(content, maxURLs)
}

func Linkify(content string) string {
	reg := regexp.MustCompile(`(?:(?:https?:\/\/)|(?:www\.))[-a-zA-Z0-9@:%._\+~#=]{2,256}\.[a-z]{2,4}\b(?:[-a-zA-Z0-9@:%_\+.~#?&/=]*)`)
	return reg.ReplaceAllString(content, `<a href="$0" target="_blank">$0</a>`)
}
<|endoftext|>


<commit_before>package patreon

import "time"

// UserDefaultRelations specifies default includes for User.
const UserDefaultRelations = "campaign,pledges"

// User represents a Patreon's user.
// Valid relationships: pledges, cards, follows, campaign, presence, session, locations, current_user_follow, pledge_to_current_user.
type User struct {
	Type       string `json:"type"`
	Id         string `json:"id"`
	Attributes struct {
		FirstName       string    `json:"first_name"`
		LastName        string    `json:"last_name"`
		FullName        string    `json:"full_name"`
		Vanity          string    `json:"vanity"`
		Email           string    `json:"email"`
		About           string    `json:"about"`
		FacebookId      string    `json:"facebook_id"`
		Gender          int       `json:"gender"`
		HasPassword     bool      `json:"has_password"`
		ImageURL        string    `json:"image_url"`
		ThumbURL        string    `json:"thumb_url"`
		YouTube         string    `json:"youtube"`
		Twitter         string    `json:"twitter"`
		Facebook        string    `json:"facebook"`
		IsEmailVerified bool      `json:"is_email_verified"`
		IsSuspended     bool      `json:"is_suspended"`
		IsDeleted       bool      `json:"is_deleted"`
		IsNuked         bool      `json:"is_nuked"`
		Created         time.Time `json:"created"`
		URL             string    `json:"url"`
	} `json:"attributes"`
	Relationships struct {
		Pledges *PledgesRelationship `json:"pledges,omitempty"`
	} `json:"relationships"`
}

// UserResponse wraps Patreon's fetch user API response
type UserResponse struct {
	Data  User `json:"data"`
	Links struct {
		Self string `json:"self"`
	} `json:"links"`
}
<commit_msg>Add 'included' field to user's response<commit_after>package patreon

import "time"

// UserDefaultRelations specifies default includes for User.
const UserDefaultRelations = "campaign,pledges"

// User represents a Patreon's user.
// Valid relationships: pledges, cards, follows, campaign, presence, session, locations, current_user_follow, pledge_to_current_user.
type User struct {
	Type       string `json:"type"`
	Id         string `json:"id"`
	Attributes struct {
		FirstName       string    `json:"first_name"`
		LastName        string    `json:"last_name"`
		FullName        string    `json:"full_name"`
		Vanity          string    `json:"vanity"`
		Email           string    `json:"email"`
		About           string    `json:"about"`
		FacebookId      string    `json:"facebook_id"`
		Gender          int       `json:"gender"`
		HasPassword     bool      `json:"has_password"`
		ImageURL        string    `json:"image_url"`
		ThumbURL        string    `json:"thumb_url"`
		YouTube         string    `json:"youtube"`
		Twitter         string    `json:"twitter"`
		Facebook        string    `json:"facebook"`
		IsEmailVerified bool      `json:"is_email_verified"`
		IsSuspended     bool      `json:"is_suspended"`
		IsDeleted       bool      `json:"is_deleted"`
		IsNuked         bool      `json:"is_nuked"`
		Created         time.Time `json:"created"`
		URL             string    `json:"url"`
	} `json:"attributes"`
	Relationships struct {
		Pledges *PledgesRelationship `json:"pledges,omitempty"`
	} `json:"relationships"`
}

// UserResponse wraps Patreon's fetch user API response
type UserResponse struct {
	Data     User     `json:"data"`
	Included Includes `json:"included"`
	Links    struct {
		Self string `json:"self"`
	} `json:"links"`
}
<|endoftext|>


<commit_before>// Copyright 2016 Albert Nigmatzianov. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.

package id3v2

import (
	"bufio"
	"bytes"
	"errors"
	"io"
)

const (
	// id3SizeLen is length of ID3v2 size format (4 * 0b0xxxxxxx).
	id3SizeLen = 4

	maxSize  = 268435455 // == 0b00001111 11111111 11111111 11111111
	sizeBase = 7         // == 0b01111111
)

var (
	ErrSizeOverflow      = errors.New("size of tag/frame is greater than allowed in id3 tag")
	ErrInvalidSizeFormat = errors.New("invalid format of tag's/frame's size")
)

// writeBytesSize writes size to bw in form of ID3v2 size format (4 * 0b0xxxxxxx).
//
// If size is greater than allowed (256MB), then it returns ErrSizeOverflow.
func writeBytesSize(bw *bufio.Writer, size uint) error {
	if size > maxSize {
		return ErrSizeOverflow
	}

	// First 4 bits of size are always "0", because size should be smaller
	// as maxSize. So skip them.
	size <<= 4

	// Let's explain the algorithm on example.
	// E.g. size is 32-bit integer and after the skip of first 4 bits
	// its value is "10100111 01110101 01010010 11110000".
	// In loop we should write every first 7 bits to bw.
	mask := uint(254 << (3 * 8)) // 11111110 000000000 000000000 000000000
	for i := 0; i < id3SizeLen; i++ {
		// To take first 7 bits we should do `size&mask`.
		firstBits := size & mask
		// firstBits is "10100110 00000000 00000000 00000000" now.
		// firstBits has int type, but we should have a byte.
		// To have a byte we should move first 7 bits to the end of firstBits,
		// because by converting int to byte only last 8 bits are taken.
		firstBits >>= (3*8 + 1)
		// firstBits is "00000000 00000000 00000000 01010011" now.
		bSize := byte(firstBits)
		// Now in bSize we have only "01010011". We can write it to bw.
		bw.WriteByte(bSize)
		// Do the same with next 7 bits.
		size <<= sizeBase
	}

	return nil
}

// parseSize parses data in form of ID3v2 size specification format (4 * 0b0xxxxxxx)
// and returns parsed int64 number.
//
// If length of data is greater than 4 or if there is invalid size format (e.g.
// one byte in data is like 0b1xxxxxxx), then it returns ErrInvalidSizeFormat.
func parseSize(data []byte) (int64, error) {
	if len(data) > id3SizeLen {
		return 0, ErrInvalidSizeFormat
	}

	var size int64
	for _, b := range data {
		if b&128 > 0 { // 128 = 0b1000_0000
			return 0, ErrInvalidSizeFormat
		}

		size = (size << sizeBase) | int64(b)
	}

	return size, nil
}

// readAll reads from r until an error or EOF and returns the data it read.
// A successful call returns err == nil, not err == EOF.
// Because ReadAll is defined to read from src until EOF,
// it does not treat an EOF from Read as an error to be reported.
func readAll(rd io.Reader) ([]byte, error) {
	if lr, ok := rd.(*io.LimitedReader); ok {
		buf := make([]byte, lr.N)
		_, err := lr.R.Read(buf)
		return buf, err
	}

	buf := bytes.NewBuffer(make([]byte, 0, bytes.MinRead))
	_, err := buf.ReadFrom(rd)
	return buf.Bytes(), err
}
<commit_msg>Add resolveBufioWriter<commit_after>// Copyright 2016 Albert Nigmatzianov. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.

package id3v2

import (
	"bufio"
	"bytes"
	"errors"
	"io"
)

const (
	// id3SizeLen is length of ID3v2 size format (4 * 0b0xxxxxxx).
	id3SizeLen = 4

	maxSize  = 268435455 // == 0b00001111 11111111 11111111 11111111
	sizeBase = 7         // == 0b01111111
)

var (
	ErrSizeOverflow      = errors.New("size of tag/frame is greater than allowed in id3 tag")
	ErrInvalidSizeFormat = errors.New("invalid format of tag's/frame's size")
)

// writeBytesSize writes size to bw in form of ID3v2 size format (4 * 0b0xxxxxxx).
//
// If size is greater than allowed (256MB), then it returns ErrSizeOverflow.
func writeBytesSize(bw *bufio.Writer, size uint) error {
	if size > maxSize {
		return ErrSizeOverflow
	}

	// First 4 bits of size are always "0", because size should be smaller
	// as maxSize. So skip them.
	size <<= 4

	// Let's explain the algorithm on example.
	// E.g. size is 32-bit integer and after the skip of first 4 bits
	// its value is "10100111 01110101 01010010 11110000".
	// In loop we should write every first 7 bits to bw.
	mask := uint(254 << (3 * 8)) // 11111110 000000000 000000000 000000000
	for i := 0; i < id3SizeLen; i++ {
		// To take first 7 bits we should do `size&mask`.
		firstBits := size & mask
		// firstBits is "10100110 00000000 00000000 00000000" now.
		// firstBits has int type, but we should have a byte.
		// To have a byte we should move first 7 bits to the end of firstBits,
		// because by converting int to byte only last 8 bits are taken.
		firstBits >>= (3*8 + 1)
		// firstBits is "00000000 00000000 00000000 01010011" now.
		bSize := byte(firstBits)
		// Now in bSize we have only "01010011". We can write it to bw.
		bw.WriteByte(bSize)
		// Do the same with next 7 bits.
		size <<= sizeBase
	}

	return nil
}

// parseSize parses data in form of ID3v2 size specification format (4 * 0b0xxxxxxx)
// and returns parsed int64 number.
//
// If length of data is greater than 4 or if there is invalid size format (e.g.
// one byte in data is like 0b1xxxxxxx), then it returns ErrInvalidSizeFormat.
func parseSize(data []byte) (int64, error) {
	if len(data) > id3SizeLen {
		return 0, ErrInvalidSizeFormat
	}

	var size int64
	for _, b := range data {
		if b&128 > 0 { // 128 = 0b1000_0000
			return 0, ErrInvalidSizeFormat
		}

		size = (size << sizeBase) | int64(b)
	}

	return size, nil
}

// readAll reads from r until an error or EOF and returns the data it read.
// A successful call returns err == nil, not err == EOF.
// Because ReadAll is defined to read from src until EOF,
// it does not treat an EOF from Read as an error to be reported.
func readAll(rd io.Reader) ([]byte, error) {
	if lr, ok := rd.(*io.LimitedReader); ok {
		buf := make([]byte, lr.N)
		_, err := lr.R.Read(buf)
		return buf, err
	}

	buf := bytes.NewBuffer(make([]byte, 0, bytes.MinRead))
	_, err := buf.ReadFrom(rd)
	return buf.Bytes(), err
}

func resolveBufioWriter(w io.Writer) (bw *bufio.Writer, ok bool) {
	bw, ok = w.(*bufio.Writer)
	if !ok {
		bw = getBufioWriter(w)
	}
	return
}
<|endoftext|>


<commit_before>package main

import (

	"fmt"
	"os"
	"path/filepath"
	"strings"
)

func CollectExcludes(excludePaths []string) ([]string){

	excludes := make([]string, 1, 1)

	for i := 0; i < len(excludePaths); i++ {
		exclude := excludePaths[i]
		err := filepath.Walk(exclude, func(path string, info os.FileInfo, err error) (error) {
			if (strings.HasPrefix(path, exclude)) {
				excludes = append(excludes, path)
			}
			return err
		})

		if err != nil {
			fmt.Println("Error collecting excludes: ", err)
		}
	}
	return excludes
}

func HasMember(arr []string, item string) (bool) {
	for i := 0; i < len(arr); i++ {
		if arr[i] == item {
			return true
		}
	}
	return false
}
<commit_msg>changed function name.<commit_after>package main

import (

	"fmt"
	"os"
	"path/filepath"
	"strings"
)

func CollectExcludes(excludePaths []string) ([]string){

	excludes := make([]string, 1, 1)

	for i := 0; i < len(excludePaths); i++ {
		exclude := excludePaths[i]
		err := filepath.Walk(exclude, func(path string, info os.FileInfo, err error) (error) {
			if (strings.HasPrefix(path, exclude)) {
				excludes = append(excludes, path)
			}
			return err
		})

		if err != nil {
			fmt.Println("Error collecting excludes: ", err)
		}
	}
	return excludes
}

func IsSubDir(arr []string, item string) (bool) {
	for i := 0; i < len(arr); i++ {
		if arr[i] == item {
			return true
		}
	}
	return false
}
<|endoftext|>


<commit_before>package chi

import (
	"fmt"
	"net/http"

	"golang.org/x/net/context"
)

// Build a chained chi.Handler from a list of middlewares
func chain(middlewares []interface{}, handlers ...interface{}) Handler {
	// join a middleware stack with inline middlewares
	mws := append(middlewares, handlers[:len(handlers)-1]...)

	// request handler
	handler := handlers[len(handlers)-1]

	// Assert the types in the middleware chain
	for _, mw := range mws {
		assertMiddleware(mw)
	}

	// Set the request handler to a context handler type
	var cxh Handler
	switch t := handler.(type) {
	default:
		panic(fmt.Sprintf("chi: unsupported handler signature: %T", t))
	case http.Handler:
		cxh = HandlerFunc(func(ctx context.Context, w http.ResponseWriter, r *http.Request) {
			t.ServeHTTP(w, r)
		})
	case Handler:
		cxh = t
	case func(http.ResponseWriter, *http.Request):
		cxh = HandlerFunc(func(ctx context.Context, w http.ResponseWriter, r *http.Request) {
			t(w, r)
		})
	case func(context.Context, http.ResponseWriter, *http.Request):
		cxh = HandlerFunc(t)
	}

	// Return ahead of time if there aren't any middlewares for the chain
	if len(mws) == 0 {
		return cxh
	}

	// Wrap the end handler with the middleware chain
	h := mwrap(mws[len(mws)-1])(cxh)
	for i := len(mws) - 2; i >= 0; i-- {
		f := mwrap(mws[i])
		h = f(h)
	}

	return h
}

// Wrap http.Handler middleware to chi.Handler middlewares
func mwrap(middleware interface{}) func(Handler) Handler {
	mw := func(cxh Handler) Handler {
		return HandlerFunc(func(ctx context.Context, w http.ResponseWriter, r *http.Request) {
			wFn := func(ww http.ResponseWriter, rr *http.Request) {
				cxh.ServeHTTPC(ctx, ww, rr)
			}
			wFnC := func(ctx context.Context, ww http.ResponseWriter, rr *http.Request) {
				cxh.ServeHTTPC(ctx, ww, rr)
			}

			switch mw := middleware.(type) {
			default:
				panic(fmt.Sprintf("chi: unsupported handler signature: %T", mw))
			case func(http.Handler) http.Handler:
				h := mw(http.HandlerFunc(wFn)).ServeHTTP
				h(w, r)
			case func(Handler) Handler:
				h := mw(HandlerFunc(wFnC)).ServeHTTPC
				h(ctx, w, r)
			}
		})
	}
	return mw
}

// Runtime type checking of the middleware signature
func assertMiddleware(middleware interface{}) interface{} {
	switch t := middleware.(type) {
	default:
		panic(fmt.Sprintf("chi: unsupported middleware signature: %T", t))
	case func(http.Handler) http.Handler:
	case func(Handler) Handler:
	}
	return middleware
}
<commit_msg>Rearrange handler type tests<commit_after>package chi

import (
	"fmt"
	"net/http"

	"golang.org/x/net/context"
)

// Build a chained chi.Handler from a list of middlewares
func chain(middlewares []interface{}, handlers ...interface{}) Handler {
	// join a middleware stack with inline middlewares
	mws := append(middlewares, handlers[:len(handlers)-1]...)

	// request handler
	handler := handlers[len(handlers)-1]

	// Assert the types in the middleware chain
	for _, mw := range mws {
		assertMiddleware(mw)
	}

	// Set the request handler to a context handler type
	var cxh Handler
	switch t := handler.(type) {
	default:
		panic(fmt.Sprintf("chi: unsupported handler signature: %T", t))
	case Handler:
		cxh = t
	case func(context.Context, http.ResponseWriter, *http.Request):
		cxh = HandlerFunc(t)
	case http.Handler:
		cxh = HandlerFunc(func(ctx context.Context, w http.ResponseWriter, r *http.Request) {
			t.ServeHTTP(w, r)
		})
	case func(http.ResponseWriter, *http.Request):
		cxh = HandlerFunc(func(ctx context.Context, w http.ResponseWriter, r *http.Request) {
			t(w, r)
		})
	}

	// Return ahead of time if there aren't any middlewares for the chain
	if len(mws) == 0 {
		return cxh
	}

	// Wrap the end handler with the middleware chain
	h := mwrap(mws[len(mws)-1])(cxh)
	for i := len(mws) - 2; i >= 0; i-- {
		f := mwrap(mws[i])
		h = f(h)
	}

	return h
}

// Wrap http.Handler middleware to chi.Handler middlewares
func mwrap(middleware interface{}) func(Handler) Handler {
	mw := func(cxh Handler) Handler {
		return HandlerFunc(func(ctx context.Context, w http.ResponseWriter, r *http.Request) {
			wFn := func(ww http.ResponseWriter, rr *http.Request) {
				cxh.ServeHTTPC(ctx, ww, rr)
			}
			wFnC := func(ctx context.Context, ww http.ResponseWriter, rr *http.Request) {
				cxh.ServeHTTPC(ctx, ww, rr)
			}

			switch mw := middleware.(type) {
			default:
				panic(fmt.Sprintf("chi: unsupported handler signature: %T", mw))
			case func(http.Handler) http.Handler:
				h := mw(http.HandlerFunc(wFn)).ServeHTTP
				h(w, r)
			case func(Handler) Handler:
				h := mw(HandlerFunc(wFnC)).ServeHTTPC
				h(ctx, w, r)
			}
		})
	}
	return mw
}

// Runtime type checking of the middleware signature
func assertMiddleware(middleware interface{}) interface{} {
	switch t := middleware.(type) {
	default:
		panic(fmt.Sprintf("chi: unsupported middleware signature: %T", t))
	case func(http.Handler) http.Handler:
	case func(Handler) Handler:
	}
	return middleware
}
<|endoftext|>


<commit_before>// To the extent possible under law, Authors have waived all copyright and
// related or neighboring rights to 'freecrypto'.

package freecrypto

// Turns from bits to bytes of different sizes.

func BitsToBytes(n uint) uint {
	return n >> 3 // n / 8
}

func BitsToWords16(n uint) uint {
	return n >> 4 // n / 16
}

func BitsToWords32(n uint) uint {
	return n >> 5 // n / 32
}

func BitsToWords64(n uint) uint {
	return n >> 6 // n / 64
}

// Turns from bytes of different sizes to bits.

func BytesToBits(n uint) uint {
	return n << 3 // * 8
}

<commit_msg>Added little utility functions<commit_after>// To the extent possible under law, Authors have waived all copyright and
// related or neighboring rights to 'freecrypto'.

package freecrypto

import (
	"encoding/binary"
)

// Turns from bits.

func BitToByte(n uint) uint {
	return n >> 3 // n / 8
}

func BitToWord16(n uint) uint {
	return n >> 4 // n / 16
}

func BitToWord32(n uint) uint {
	return n >> 5 // n / 32
}

func BitToWord64(n uint) uint {
	return n >> 6 // n / 64
}

// Turns to bits.

func ByteToBit(n uint) uint {
	return n << 3 // * 8
}

func IsPowerOf2(n uint) bool {
	return n > 0 && (n & (n-1)) == 0
}

<|endoftext|>


<commit_before>// Package str provides some routines to convert an unsigned integer value to
// its English textual representation. This facilitates database testing by
// supporting the generation of a large number of records with two generally
// unrelated sort orders.
package str

import (
	"bytes"
	"fmt"
	"strings"
)

// Delimit converts 'ABCDEFG' to, for example, 'A,BCD,EFG'
func Delimit(str string, sepstr string, sepcount int) string {
	pos := len(str) - sepcount
	for pos > 0 {
		str = str[:pos] + sepstr + str[pos:]
		pos = pos - sepcount
	}
	return str
}

var lookup = [...]string{
	"",           // 0
	"eight ",     // 1
	"eighteen ",  // 2
	"eighty ",    // 3
	"eleven ",    // 4
	"fifteen ",   // 5
	"fifty ",     // 6
	"five ",      // 7
	"forty ",     // 8
	"four ",      // 9
	"fourteen ",  // 10
	"hundred ",   // 11
	"million ",   // 12
	"nine ",      // 13
	"nineteen ",  // 14
	"ninety ",    // 15
	"one ",       // 16
	"seven ",     // 17
	"seventeen ", // 18
	"seventy ",   // 19
	"six ",       // 20
	"sixteen ",   // 21
	"sixty ",     // 22
	"ten ",       // 23
	"ten ",       // 24
	"thirteen ",  // 25
	"thirty ",    // 26
	"thousand ",  // 27
	"three ",     // 28
	"twelve ",    // 29
	"twenty ",    // 30
	"two ",       // 31
	"zero ",      // 32
}

// QuantityDecode returns the textual expansion of the byte sequence specified
// by sl. See QuantityEncode for more details.
func QuantityDecode(sl []byte) string {
	var buf bytes.Buffer
	for _, c := range sl {
		if c < 33 {
			buf.WriteString(lookup[c])
		}
	}
	return strings.TrimSpace(buf.String())
}

func quantityByte(buf *bytes.Buffer, val uint) {
	var numList = [...]byte{0, 16, 31, 28, 9, 7, 20, 17, 1, 13, 24, 4, 29,
		25, 10, 5, 21, 18, 2, 14}
	var tenList = [...]byte{23, 30, 26, 8, 6, 22, 19, 3, 15}

	if val >= 1000000 {
		quantityByte(buf, val/1000000)
		buf.WriteByte(12)
		quantityByte(buf, val%1000000)
	} else if val >= 1000 {
		quantityByte(buf, val/1000)
		buf.WriteByte(27)
		quantityByte(buf, val%1000)
	} else if val >= 100 {
		quantityByte(buf, val/100)
		buf.WriteByte(11)
		quantityByte(buf, val%100)
	} else if val >= 20 {
		buf.WriteByte(tenList[val/10-1])
		quantityByte(buf, val%10)
	} else {
		buf.WriteByte(numList[val])
	}
}

// QuantityEncode returns the English text equivalent, in byte-encoded form, of
// the number specified by val. For example, if val is 21, the return value is
// a compact byte slice that, when unencoded with QuantityDecode(), is "twenty
// one". Sorting encoded values for various values produces the same order as
// sorting decoded values. QuantityDecode() decodes the packed byte sequence
// into English words. val must be a value less than or equal to 999,999,999.
func QuantityEncode(val uint) (sl []byte, err error) {
	const limit = 1000000000
	if val < limit {
		var buf bytes.Buffer
		if val > 0 {
			quantityByte(&buf, val)
		} else {
			buf.WriteByte(32)
		}
		sl = buf.Bytes()
	} else {
		err = fmt.Errorf("expecting val (%d) to be less than %d", val, limit)
	}
	return
}
func quantity(buf *bytes.Buffer, val uint) {
	var numList = [...]string{"", "one ", "two ", "three ", "four ",
		"five ", "six ", "seven ", "eight ", "nine ", "ten ", "eleven ", "twelve ",
		"thirteen ", "fourteen ", "fifteen ", "sixteen ", "seventeen ", "eighteen ",
		"nineteen "}
	var tenList = [...]string{"ten ", "twenty ", "thirty ", "forty ",
		"fifty ", "sixty ", "seventy ", "eighty ", "ninety "}

	if val >= 1000000 {
		quantity(buf, val/1000000)
		fmt.Fprint(buf, "million ")
		quantity(buf, val%1000000)
	} else if val >= 1000 {
		quantity(buf, val/1000)
		fmt.Fprint(buf, "thousand ")
		quantity(buf, val%1000)
	} else if val >= 100 {
		quantity(buf, val/100)
		fmt.Fprint(buf, "hundred ")
		quantity(buf, val%100)
	} else if val >= 20 {
		fmt.Fprint(buf, tenList[val/10-1])
		quantity(buf, val%10)
	} else {
		fmt.Fprint(buf, numList[val])
	}
}

// Quantity returns the English text equivalent of the number specified by
// val. For example, if val is 35 the return value is "thirty five".
func Quantity(val uint) string {
	if val == 0 {
		return "zero"
	} else if val >= 1000000000 {
		return fmt.Sprintf("%d", val)
	} else {
		var buf bytes.Buffer
		quantity(&buf, val)
		return strings.TrimSpace(buf.String())
	}
}
<commit_msg>Factor constant limit<commit_after>// Package str provides some routines to convert an unsigned integer value to
// its English textual representation. This facilitates database testing by
// supporting the generation of a large number of records with two generally
// unrelated sort orders.
package str

import (
	"bytes"
	"fmt"
	"strings"
)

const limit = 1000000000

// Delimit converts 'ABCDEFG' to, for example, 'A,BCD,EFG'
func Delimit(str string, sepstr string, sepcount int) string {
	pos := len(str) - sepcount
	for pos > 0 {
		str = str[:pos] + sepstr + str[pos:]
		pos = pos - sepcount
	}
	return str
}

var lookup = [...]string{
	"",           // 0
	"eight ",     // 1
	"eighteen ",  // 2
	"eighty ",    // 3
	"eleven ",    // 4
	"fifteen ",   // 5
	"fifty ",     // 6
	"five ",      // 7
	"forty ",     // 8
	"four ",      // 9
	"fourteen ",  // 10
	"hundred ",   // 11
	"million ",   // 12
	"nine ",      // 13
	"nineteen ",  // 14
	"ninety ",    // 15
	"one ",       // 16
	"seven ",     // 17
	"seventeen ", // 18
	"seventy ",   // 19
	"six ",       // 20
	"sixteen ",   // 21
	"sixty ",     // 22
	"ten ",       // 23
	"ten ",       // 24
	"thirteen ",  // 25
	"thirty ",    // 26
	"thousand ",  // 27
	"three ",     // 28
	"twelve ",    // 29
	"twenty ",    // 30
	"two ",       // 31
	"zero ",      // 32
}

// QuantityDecode returns the textual expansion of the byte sequence specified
// by sl. See QuantityEncode for more details.
func QuantityDecode(sl []byte) string {
	var buf bytes.Buffer
	for _, c := range sl {
		if c < 33 {
			buf.WriteString(lookup[c])
		}
	}
	return strings.TrimSpace(buf.String())
}

func quantityByte(buf *bytes.Buffer, val uint) {
	var numList = [...]byte{0, 16, 31, 28, 9, 7, 20, 17, 1, 13, 24, 4, 29,
		25, 10, 5, 21, 18, 2, 14}
	var tenList = [...]byte{23, 30, 26, 8, 6, 22, 19, 3, 15}

	if val >= 1000000 {
		quantityByte(buf, val/1000000)
		buf.WriteByte(12)
		quantityByte(buf, val%1000000)
	} else if val >= 1000 {
		quantityByte(buf, val/1000)
		buf.WriteByte(27)
		quantityByte(buf, val%1000)
	} else if val >= 100 {
		quantityByte(buf, val/100)
		buf.WriteByte(11)
		quantityByte(buf, val%100)
	} else if val >= 20 {
		buf.WriteByte(tenList[val/10-1])
		quantityByte(buf, val%10)
	} else {
		buf.WriteByte(numList[val])
	}
}

// QuantityEncode returns the English text equivalent, in byte-encoded form, of
// the number specified by val. For example, if val is 21, the return value is
// a compact byte slice that, when unencoded with QuantityDecode(), is "twenty
// one". Sorting encoded values for various values produces the same order as
// sorting decoded values. QuantityDecode() decodes the packed byte sequence
// into English words. val must be a value less than or equal to 999,999,999.
func QuantityEncode(val uint) (sl []byte, err error) {
	if val < limit {
		var buf bytes.Buffer
		if val > 0 {
			quantityByte(&buf, val)
		} else {
			buf.WriteByte(32)
		}
		sl = buf.Bytes()
	} else {
		err = fmt.Errorf("expecting val (%d) to be less than %d", val, limit)
	}
	return
}
func quantity(buf *bytes.Buffer, val uint) {
	var numList = [...]string{"", "one ", "two ", "three ", "four ",
		"five ", "six ", "seven ", "eight ", "nine ", "ten ", "eleven ", "twelve ",
		"thirteen ", "fourteen ", "fifteen ", "sixteen ", "seventeen ", "eighteen ",
		"nineteen "}
	var tenList = [...]string{"ten ", "twenty ", "thirty ", "forty ",
		"fifty ", "sixty ", "seventy ", "eighty ", "ninety "}

	if val >= 1000000 {
		quantity(buf, val/1000000)
		fmt.Fprint(buf, "million ")
		quantity(buf, val%1000000)
	} else if val >= 1000 {
		quantity(buf, val/1000)
		fmt.Fprint(buf, "thousand ")
		quantity(buf, val%1000)
	} else if val >= 100 {
		quantity(buf, val/100)
		fmt.Fprint(buf, "hundred ")
		quantity(buf, val%100)
	} else if val >= 20 {
		fmt.Fprint(buf, tenList[val/10-1])
		quantity(buf, val%10)
	} else {
		fmt.Fprint(buf, numList[val])
	}
}

// Quantity returns the English text equivalent of the number specified by
// val. For example, if val is 35 the return value is "thirty five".
func Quantity(val uint) string {
	if val == 0 {
		return "zero"
	} else if val >= limit {
		return fmt.Sprintf("%d", val)
	} else {
		var buf bytes.Buffer
		quantity(&buf, val)
		return strings.TrimSpace(buf.String())
	}
}
<|endoftext|>


<commit_before>// Copyright 2013 Canonical Ltd.
// Licensed under the LGPLv3, see LICENCE file for details.

package utils

import (
	"crypto/rand"
	"encoding/hex"
	"fmt"
	"io"
	"regexp"
	"strings"
)

// UUID represent a universal identifier with 16 octets.
type UUID [16]byte

// regex for validating that the UUID matches RFC 4122.
// This package specifically generates and accepts version 4 UUIDs
// where the string representation has the digit 4 at the beginning of
// the third grouping, and one of the hex digits 8 through b at the
// beginning of the fourth grouping.
// http://www.ietf.org/rfc/rfc4122.txt
var (
	block1  = "[0-9a-f]{8}"
	block2  = "[0-9a-f]{4}"
	version = "4"
	block3  = "[0-9a-f]{3}"
	variant = "[8,9,a,b]"
	block4  = "[0-9a-f]{3}"
	block5  = "[0-9a-f]{12}"

	validUUID = regexp.MustCompile("^" + block1 + "-" + block2 + "-" + version + block3 + "-" + variant + block4 + "-" + block5 + "$")
)

func UUIDFromString(s string) (UUID, error) {
	if !IsValidUUIDString(s) {
		return UUID{}, fmt.Errorf("invalid UUID: %q", s)
	}
	s = strings.Replace(s, "-", "", 4)
	raw, err := hex.DecodeString(s)
	if err != nil {
		return UUID{}, err
	}
	var uuid UUID
	copy(uuid[:], raw)
	return uuid, nil
}

// IsValidUUIDString returns true, if the given string matches a valid UUID (version 4, variant 2).
func IsValidUUIDString(s string) bool {
	return validUUID.MatchString(s)
}

// MustNewUUID returns a new uuid, if an error occurs it panics.
func MustNewUUID() UUID {
	uuid, err := NewUUID()
	if err != nil {
		panic(err)
	}
	return uuid
}

// NewUUID generates a new version 4 UUID relying only on random numbers.
func NewUUID() (UUID, error) {
	uuid := UUID{}
	if _, err := io.ReadFull(rand.Reader, []byte(uuid[0:16])); err != nil {
		return UUID{}, err
	}
	// Set version (4) and variant (2) according to RfC 4122.
	var version byte = 4 << 4
	var variant byte = 8 << 4
	uuid[6] = version | (uuid[6] & 15)
	uuid[8] = variant | (uuid[8] & 15)
	return uuid, nil
}

// Copy returns a copy of the UUID.
func (uuid UUID) Copy() UUID {
	uuidCopy := uuid
	return uuidCopy
}

// Raw returns a copy of the UUID bytes.
func (uuid UUID) Raw() [16]byte {
	return [16]byte(uuid)
}

// String returns a hexadecimal string representation with
// standardized separators.
func (uuid UUID) String() string {
	return fmt.Sprintf("%x-%x-%x-%x-%x", uuid[0:4], uuid[4:6], uuid[6:8], uuid[8:10], uuid[10:16])
}
<commit_msg>Export the UUID regular expression snippet.<commit_after>// Copyright 2013 Canonical Ltd.
// Licensed under the LGPLv3, see LICENCE file for details.

package utils

import (
	"crypto/rand"
	"encoding/hex"
	"fmt"
	"io"
	"regexp"
	"strings"
)

// UUID represent a universal identifier with 16 octets.
type UUID [16]byte

// regex for validating that the UUID matches RFC 4122.
// This package specifically generates and accepts version 4 UUIDs
// where the string representation has the digit 4 at the beginning of
// the third grouping, and one of the hex digits 8 through b at the
// beginning of the fourth grouping.
// http://www.ietf.org/rfc/rfc4122.txt
var (
	block1  = "[0-9a-f]{8}"
	block2  = "[0-9a-f]{4}"
	version = "4"
	block3  = "[0-9a-f]{3}"
	variant = "[8,9,a,b]"
	block4  = "[0-9a-f]{3}"
	block5  = "[0-9a-f]{12}"

	UUIDSnippet = block1 + "-" + block2 + "-" + version + block3 + "-" + variant + block4 + "-" + block5
	validUUID   = regexp.MustCompile("^" + UUIDSnippet + "$")
)

func UUIDFromString(s string) (UUID, error) {
	if !IsValidUUIDString(s) {
		return UUID{}, fmt.Errorf("invalid UUID: %q", s)
	}
	s = strings.Replace(s, "-", "", 4)
	raw, err := hex.DecodeString(s)
	if err != nil {
		return UUID{}, err
	}
	var uuid UUID
	copy(uuid[:], raw)
	return uuid, nil
}

// IsValidUUIDString returns true, if the given string matches a valid UUID (version 4, variant 2).
func IsValidUUIDString(s string) bool {
	return validUUID.MatchString(s)
}

// MustNewUUID returns a new uuid, if an error occurs it panics.
func MustNewUUID() UUID {
	uuid, err := NewUUID()
	if err != nil {
		panic(err)
	}
	return uuid
}

// NewUUID generates a new version 4 UUID relying only on random numbers.
func NewUUID() (UUID, error) {
	uuid := UUID{}
	if _, err := io.ReadFull(rand.Reader, []byte(uuid[0:16])); err != nil {
		return UUID{}, err
	}
	// Set version (4) and variant (2) according to RfC 4122.
	var version byte = 4 << 4
	var variant byte = 8 << 4
	uuid[6] = version | (uuid[6] & 15)
	uuid[8] = variant | (uuid[8] & 15)
	return uuid, nil
}

// Copy returns a copy of the UUID.
func (uuid UUID) Copy() UUID {
	uuidCopy := uuid
	return uuidCopy
}

// Raw returns a copy of the UUID bytes.
func (uuid UUID) Raw() [16]byte {
	return [16]byte(uuid)
}

// String returns a hexadecimal string representation with
// standardized separators.
func (uuid UUID) String() string {
	return fmt.Sprintf("%x-%x-%x-%x-%x", uuid[0:4], uuid[4:6], uuid[6:8], uuid[8:10], uuid[10:16])
}
<|endoftext|>


<commit_before>package main

import (
	"github.com/pborman/uuid"
	"fmt"
	"os"
)

func usage() {
	fmt.Printf("usage:\n")
	fmt.Printf("    uuid -h            show this help message\n")
	fmt.Printf("    uuid               generate and show a Version 1 UUID (time based) for the current time\n")
	fmt.Printf("    uuid <url>         generate and show a Version 3 UUID in the URL namespace for the given URL\n")
	fmt.Printf("    uuid <ns> <name>   show Version 3 UUID for namespace/name. The namespace can be a uuid or URL\n")
	os.Exit(1)
}

func main() {
	var u uuid.UUID
	switch len(os.Args) {
	case 1:
		u = uuid.NewUUID()
	case 2:
		if os.Args[1] == "-h" {
			usage()
		}
		u = uuid.NewMD5(uuid.NameSpace_URL, []byte(os.Args[1]))
	case 3:
		ns := uuid.Parse(os.Args[1])
		if ns == nil {
			ns = uuid.NewMD5(uuid.NameSpace_URL, []byte(os.Args[1]))
		}
		u = uuid.NewMD5(ns, []byte(os.Args[2]))
	default:
		usage()
	}
	fmt.Printf("%v\n", u)
}
<commit_msg>go fmt<commit_after>package main

import (
	"fmt"
	"os"

	"github.com/pborman/uuid"
)

func usage() {
	fmt.Printf("usage:\n")
	fmt.Printf("    uuid -h            show this help message\n")
	fmt.Printf("    uuid               generate and show a Version 1 UUID (time based) for the current time\n")
	fmt.Printf("    uuid <url>         generate and show a Version 3 UUID in the URL namespace for the given URL\n")
	fmt.Printf("    uuid <ns> <name>   show Version 3 UUID for namespace/name. The namespace can be a uuid or URL\n")
	os.Exit(1)
}

func main() {
	var u uuid.UUID
	switch len(os.Args) {
	case 1:
		u = uuid.NewUUID()
	case 2:
		if os.Args[1] == "-h" {
			usage()
		}
		u = uuid.NewMD5(uuid.NameSpace_URL, []byte(os.Args[1]))
	case 3:
		ns := uuid.Parse(os.Args[1])
		if ns == nil {
			ns = uuid.NewMD5(uuid.NameSpace_URL, []byte(os.Args[1]))
		}
		u = uuid.NewMD5(ns, []byte(os.Args[2]))
	default:
		usage()
	}
	fmt.Printf("%v\n", u)
}
<|endoftext|>


<commit_before>package sofa

import (
	"bytes"
	"encoding/json"
	"fmt"
)

// conflicts (boolean) – Includes conflicts information in response. Ignored if include_docs isn’t true. Default is false
// descending (boolean) – Return the documents in descending by key order. Default is false
// endkey (json) – Stop returning records when the specified key is reached. Optional
// end_key (json) – Alias for endkey param
// endkey_docid (string) – Stop returning records when the specified document ID is reached. Requires endkey to be specified for this to have any effect. Optional
// end_key_doc_id (string) – Alias for endkey_docid param
// group (boolean) – Group the results using the reduce function to a group or single row. Default is false
// group_level (number) – Specify the group level to be used. Optional
// include_docs (boolean) – Include the associated document with each row. Default is false.
// attachments (boolean) – Include the Base64-encoded content of attachments in the documents that are included if include_docs is true. Ignored if include_docs isn’t true. Default is false.
// att_encoding_info (boolean) – Include encoding information in attachment stubs if include_docs is true and the particular attachment is compressed. Ignored if include_docs isn’t true. Default is false.
// inclusive_end (boolean) – Specifies whether the specified end key should be included in the result. Default is true
// key (json) – Return only documents that match the specified key. Optional
// keys (json-array) – Return only documents where the key matches one of the keys specified in the array. Optional
// limit (number) – Limit the number of the returned documents to the specified number. Optional
// reduce (boolean) – Use the reduction function. Default is true
// skip (number) – Skip this number of records before starting to return the results. Default is 0
// sorted (boolean) – Sort returned rows (see Sorting Returned Rows). Setting this to false offers a performance boost. The total_rows and offset fields are not available when this is set to false. Default is true
// stale (string) – Allow the results from a stale view to be used. Supported values: ok and update_after. Optional
// startkey (json) – Return records starting with the specified key. Optional
// start_key (json) – Alias for startkey param
// startkey_docid (string) – Return records starting with the specified document ID. Requires startkey to be specified for this to have any effect. Optional
// start_key_doc_id (string) – Alias for startkey_docid param
// update_seq (boolean) – Response includes an update_seq value indicating which sequence id of the database the view reflects. Default is false
type ViewParams struct {
	Conflicts              bool          `url:"conflicts,omitempty"`
	Descending             bool          `url:"descending,omitempty"`
	EndKey                 interface{}   `url:"endkey,omitempty"`
	EndKeyDocID            string        `url:"endkey_docid,omitempty"`
	Group                  bool          `url:"group,omitempty"`
	GroupLevel             float64       `url:"group_level,omitempty"`
	IncludeDocs            bool          `url:"include_docs,omitempty"`
	Attachments            bool          `url:"attachments,omitempty"`
	AttachmentEncodingInfo bool          `url:"att_encoding_info,omitempty"`
	InclusiveEnd           bool          `url:"inclusive_end,omitempty"`
	Key                    interface{}   `url:"key,omitempty"`
	Keys                   []interface{} `url:"keys,omitempty"`
	Limit                  float64       `url:"limit,omitempty"`
	Reduce                 bool          `url:"reduce,omitempty"`
	Skip                   float64       `url:"skip,omitempty"`
	Sorted                 bool          `url:"sorted,omitempty"`
	Stale                  string        `url:"stale,omitempty"`
	StartKey               interface{}   `url:"startkey,omitempty"`
	StartKeyDocID          string        `url:"startkey_docid,omitempty"`
	UpdateSeq              bool          `url:"update_seq,omitempty"`
}

type View interface {
	Execute(Options) (DocumentList, error)
}

type TemporaryView struct {
	Map    string `json:"map,omitempty"`
	Reduce string `json:"reduce,omitempty"`

	db *Database
}

func (d *Database) TemporaryView(mapFunc string) TemporaryView {
	return TemporaryView{
		Map: mapFunc,

		db: d,
	}
}

func (v TemporaryView) Execute(opts URLOptions) (DocumentList, error) {
	jsString, err := json.Marshal(v)
	if err != nil {
		return DocumentList{}, err
	}

	var docs DocumentList
	_, err = v.db.con.unmarshalRequest("POST", v.db.ViewPath("_temp_view"), opts, bytes.NewBuffer(jsString), &docs)
	if err != nil {
		return DocumentList{}, err
	}

	return docs, nil
}

type NamedView struct {
	DesignDoc string
	Name      string

	db *Database
}

func (d *Database) NamedView(design, name string) NamedView {
	return NamedView{
		DesignDoc: design,
		Name:      name,

		db: d,
	}
}

func (v NamedView) Execute(opts URLOptions) (DocumentList, error) {
	var docs DocumentList
	if _, err := v.db.con.unmarshalRequest("GET", v.db.ViewPath(v.Path()), opts, nil, &docs); err != nil {
		return DocumentList{}, err
	}

	return docs, nil
}

func (v NamedView) Path() string {
	return fmt.Sprintf("_design/%s/_view/%s", v.DesignDoc, v.Name)
}
<commit_msg>Also add a method for getting the full path including the DB<commit_after>package sofa

import (
	"bytes"
	"encoding/json"
	"fmt"
)

// conflicts (boolean) – Includes conflicts information in response. Ignored if include_docs isn’t true. Default is false
// descending (boolean) – Return the documents in descending by key order. Default is false
// endkey (json) – Stop returning records when the specified key is reached. Optional
// end_key (json) – Alias for endkey param
// endkey_docid (string) – Stop returning records when the specified document ID is reached. Requires endkey to be specified for this to have any effect. Optional
// end_key_doc_id (string) – Alias for endkey_docid param
// group (boolean) – Group the results using the reduce function to a group or single row. Default is false
// group_level (number) – Specify the group level to be used. Optional
// include_docs (boolean) – Include the associated document with each row. Default is false.
// attachments (boolean) – Include the Base64-encoded content of attachments in the documents that are included if include_docs is true. Ignored if include_docs isn’t true. Default is false.
// att_encoding_info (boolean) – Include encoding information in attachment stubs if include_docs is true and the particular attachment is compressed. Ignored if include_docs isn’t true. Default is false.
// inclusive_end (boolean) – Specifies whether the specified end key should be included in the result. Default is true
// key (json) – Return only documents that match the specified key. Optional
// keys (json-array) – Return only documents where the key matches one of the keys specified in the array. Optional
// limit (number) – Limit the number of the returned documents to the specified number. Optional
// reduce (boolean) – Use the reduction function. Default is true
// skip (number) – Skip this number of records before starting to return the results. Default is 0
// sorted (boolean) – Sort returned rows (see Sorting Returned Rows). Setting this to false offers a performance boost. The total_rows and offset fields are not available when this is set to false. Default is true
// stale (string) – Allow the results from a stale view to be used. Supported values: ok and update_after. Optional
// startkey (json) – Return records starting with the specified key. Optional
// start_key (json) – Alias for startkey param
// startkey_docid (string) – Return records starting with the specified document ID. Requires startkey to be specified for this to have any effect. Optional
// start_key_doc_id (string) – Alias for startkey_docid param
// update_seq (boolean) – Response includes an update_seq value indicating which sequence id of the database the view reflects. Default is false
type ViewParams struct {
	Conflicts              bool          `url:"conflicts,omitempty"`
	Descending             bool          `url:"descending,omitempty"`
	EndKey                 interface{}   `url:"endkey,omitempty"`
	EndKeyDocID            string        `url:"endkey_docid,omitempty"`
	Group                  bool          `url:"group,omitempty"`
	GroupLevel             float64       `url:"group_level,omitempty"`
	IncludeDocs            bool          `url:"include_docs,omitempty"`
	Attachments            bool          `url:"attachments,omitempty"`
	AttachmentEncodingInfo bool          `url:"att_encoding_info,omitempty"`
	InclusiveEnd           bool          `url:"inclusive_end,omitempty"`
	Key                    interface{}   `url:"key,omitempty"`
	Keys                   []interface{} `url:"keys,omitempty"`
	Limit                  float64       `url:"limit,omitempty"`
	Reduce                 bool          `url:"reduce,omitempty"`
	Skip                   float64       `url:"skip,omitempty"`
	Sorted                 bool          `url:"sorted,omitempty"`
	Stale                  string        `url:"stale,omitempty"`
	StartKey               interface{}   `url:"startkey,omitempty"`
	StartKeyDocID          string        `url:"startkey_docid,omitempty"`
	UpdateSeq              bool          `url:"update_seq,omitempty"`
}

type View interface {
	Execute(Options) (DocumentList, error)
}

type TemporaryView struct {
	Map    string `json:"map,omitempty"`
	Reduce string `json:"reduce,omitempty"`

	db *Database
}

func (d *Database) TemporaryView(mapFunc string) TemporaryView {
	return TemporaryView{
		Map: mapFunc,

		db: d,
	}
}

func (v TemporaryView) Execute(opts URLOptions) (DocumentList, error) {
	jsString, err := json.Marshal(v)
	if err != nil {
		return DocumentList{}, err
	}

	var docs DocumentList
	_, err = v.db.con.unmarshalRequest("POST", v.db.ViewPath("_temp_view"), opts, bytes.NewBuffer(jsString), &docs)
	if err != nil {
		return DocumentList{}, err
	}

	return docs, nil
}

type NamedView struct {
	DesignDoc string
	Name      string

	db *Database
}

func (d *Database) NamedView(design, name string) NamedView {
	return NamedView{
		DesignDoc: design,
		Name:      name,

		db: d,
	}
}

func (v NamedView) Execute(opts URLOptions) (DocumentList, error) {
	var docs DocumentList
	if _, err := v.db.con.unmarshalRequest("GET", v.db.ViewPath(v.Path()), opts, nil, &docs); err != nil {
		return DocumentList{}, err
	}

	return docs, nil
}

func (v NamedView) Path() string {
	return fmt.Sprintf("_design/%s/_view/%s", v.DesignDoc, v.Name)
}

func (v NamedView) FullPath() string {
	return urlConcat(v.db.Name(), v.Path())
}
<|endoftext|>


<commit_before>// Package implements creation of XLSX simple spreadsheet files

package xlsx

import (
	"archive/zip"
	"bufio"
	"fmt"
	"html"
	"io"
	"os"
	"strconv"
	"time"
)

type CellType uint

// Basic spreadsheet cell types
const (
	CellTypeNumber CellType = iota
	CellTypeString
	CellTypeDate
	CellTypeDatetime
	CellTypeInlineString
)

// XLSX Spreadsheet Cell
type Cell struct {
	Type    CellType
	Value   string
	Colspan uint64
}

// XLSX Spreadsheet Row
type Row struct {
	Cells []Cell
}

// XLSX Spreadsheet Column
type Column struct {
	Name  string
	Width uint64
}

// XLSX Workbook Document Properties
type DocumentInfo struct {
	CreatedBy  string
	ModifiedBy string
	CreatedAt  time.Time
	ModifiedAt time.Time
}

// XLSX Spreadsheet
type Sheet struct {
	Title           string
	columns         []Column
	rows            []Row
	sharedStringMap map[string]int
	sharedStrings   []string
	DocumentInfo    DocumentInfo
}

// Create a sheet with no dimensions
func NewSheet() Sheet {
	c := make([]Column, 0)
	r := make([]Row, 0)
	ssm := make(map[string]int)
	sst := make([]string, 0)

	s := Sheet{
		Title:           "Data",
		columns:         c,
		rows:            r,
		sharedStringMap: ssm,
		sharedStrings:   sst,
	}

	return s
}

// Create a sheet with dimensions derived from the given columns
func NewSheetWithColumns(c []Column) Sheet {
	r := make([]Row, 0)
	ssm := make(map[string]int)
	sst := make([]string, 0)

	s := Sheet{
		Title:           "Data",
		columns:         c,
		rows:            r,
		sharedStringMap: ssm,
		sharedStrings:   sst,
	}

	s.DocumentInfo.CreatedBy = "xlsx.go"
	s.DocumentInfo.CreatedAt = time.Now()

	s.DocumentInfo.ModifiedBy = s.DocumentInfo.CreatedBy
	s.DocumentInfo.ModifiedAt = s.DocumentInfo.CreatedAt

	return s
}

// Create a new row with a length caculated by the sheets known column count
func (s *Sheet) NewRow() Row {
	c := make([]Cell, len(s.columns))
	r := Row{
		Cells: c,
	}
	return r
}

// Append a row to the sheet
func (s *Sheet) AppendRow(r Row) error {
	if len(r.Cells) != len(s.columns) {
		return fmt.Errorf("the given row has %d cells and %d were expected", len(r.Cells), len(s.columns))
	}

	cells := make([]Cell, len(s.columns))

	for n, c := range r.Cells {
		cells[n].Type = c.Type
		cells[n].Value = c.Value

		if cells[n].Type == CellTypeString {
			// calculate string reference
			cells[n].Value = html.EscapeString(cells[n].Value)
			i, exists := s.sharedStringMap[cells[n].Value]
			if !exists {
				i = len(s.sharedStrings)
				s.sharedStringMap[cells[n].Value] = i
				s.sharedStrings = append(s.sharedStrings, cells[n].Value)
			}
			cells[n].Value = strconv.Itoa(i)
		}
	}

	row := s.NewRow()
	row.Cells = cells

	s.rows = append(s.rows, row)

	return nil
}

// Get the Shared Strings in the order they were added to the map
func (s *Sheet) SharedStrings() []string {
	return s.sharedStrings
}

// Given zero-based array indices output the Excel cell reference. For
// example (0,0) => "A1"; (2,2) => "C3"; (26,45) => "AA46"
func CellIndex(x, y uint64) (string, uint64) {
	return colName(x), (y + 1)
}

// From a zero-based column number return the Excel column name.
// For example: 0 => "A"; 2 => "C"; 26 => "AA"
func colName(n uint64) string {
	var s string
	n += 1

	for n > 0 {
		n -= 1
		s = string(65+(n%26)) + s
		n /= 26
	}

	return s
}

// Convert time to the OLE Automation format.
func OADate(d time.Time) string {
	epoch := time.Date(1899, 12, 30, 0, 0, 0, 0, time.UTC)
	nsPerDay := 24 * time.Hour

	v := -1 * float64(epoch.Sub(d)) / float64(nsPerDay)

	// TODO: deal with dates before epoch
	// e.g. http://stackoverflow.com/questions/15549823/oadate-to-milliseconds-timestamp-in-javascript/15550284#15550284

	if d.Hour() == 0 && d.Minute() == 0 && d.Second() == 0 {
		return fmt.Sprintf("%d", int64(v))
	} else {
		return fmt.Sprintf("%f", v)
	}
}

// Create filename and save the XLSX file
func (s *Sheet) SaveToFile(filename string) error {
	outputfile, err := os.Create(filename)
	if err != nil {
		return err
	}
	w := bufio.NewWriter(outputfile)
	err = s.SaveToWriter(w)
	defer w.Flush()
	return err
}

// Save the XLSX file to the given writer
func (s *Sheet) SaveToWriter(w io.Writer) error {

	ww := NewWorkbookWriter(w)

	sw, err := ww.NewSheetWriter(s)
	if err != nil {
		return err
	}

	err = sw.WriteRows(s.rows)
	if err != nil {
		return err
	}

	ww.SharedStrings = s.sharedStrings

	err = ww.Close()

	return err
}

// Write the header files of the workbook
func (ww *WorkbookWriter) WriteHeader() error {
	if ww.headerWritten {
		panic("Workbook header already written")
	}

	z := ww.zipWriter

	f, err := z.Create("[Content_Types].xml")
	err = TemplateContentTypes.Execute(f, ww.sheetNames)
	if err != nil {
		return err
	}

	f, err = z.Create("docProps/app.xml")
	err = TemplateApp.Execute(f, ww.sheetNames)
	if err != nil {
		return err
	}

	f, err = z.Create("docProps/core.xml")
	err = TemplateCore.Execute(f, ww.documentInfo)
	if err != nil {
		return err
	}

	f, err = z.Create("_rels/.rels")
	err = TemplateRelationships.Execute(f, nil)
	if err != nil {
		return err
	}

	f, err = z.Create("xl/workbook.xml")
	err = TemplateWorkbook.Execute(f, ww.sheetNames)
	if err != nil {
		return err
	}

	f, err = z.Create("xl/_rels/workbook.xml.rels")
	err = TemplateWorkbookRelationships.Execute(f, ww.sheetNames)
	if err != nil {
		return err
	}

	f, err = z.Create("xl/styles.xml")
	err = TemplateStyles.Execute(f, nil)
	if err != nil {
		return err
	}

	f, err = z.Create("xl/sharedStrings.xml")
	err = TemplateStringLookups.Execute(f, ww.SharedStrings)
	if err != nil {
		return err
	}

	return err
}

// Handles the writing of an XLSX workbook
type WorkbookWriter struct {
	zipWriter     *zip.Writer
	sheetWriter   *SheetWriter
	headerWritten bool
	closed        bool
	sheetNames    []string
	SharedStrings []string
	documentInfo  *DocumentInfo
}

// Creates a new WorkbookWriter
func NewWorkbookWriter(w io.Writer) *WorkbookWriter {
	return &WorkbookWriter{zip.NewWriter(w), nil, false, false, []string{}, nil, nil}
}

// Closes the WorkbookWriter
func (ww *WorkbookWriter) Close() error {
	if ww.closed {
		panic("WorkbookWriter already closed")
	}

	if ww.sheetWriter != nil {
		err := ww.sheetWriter.Close()
		if err != nil {
			return err
		}
	}

	if !ww.headerWritten {
		err := ww.WriteHeader()
		if err != nil {
			return err
		}
	}

	ww.closed = true

	return ww.zipWriter.Close()
}

// NewSheetWriter creates a new SheetWriter in this workbook using the given sheet.
// It returns a SheetWriter to which rows can be written.
// All rows must be written to the SheetWriter before the next call to NewSheetWriter,
// as this will automatically close the previous SheetWriter.
func (ww *WorkbookWriter) NewSheetWriter(s *Sheet) (*SheetWriter, error) {
	if ww.closed {
		panic("Can not write to closed WorkbookWriter")
	}

	if ww.sheetWriter != nil {
		err := ww.sheetWriter.Close()
		if err != nil {
			return nil, err
		}
	}

	f, err := ww.zipWriter.Create("xl/worksheets/" + fmt.Sprintf("sheet%s", strconv.Itoa(len(ww.sheetNames)+1)) + ".xml")
	sw := &SheetWriter{f, err, 0, 0, false, []string{}, 0}

	ww.documentInfo = &s.DocumentInfo

	ww.sheetWriter = sw
	err = sw.WriteHeader(s)

	ww.sheetNames = append(ww.sheetNames, s.Title)

	return sw, err
}

// Handles the writing of a sheet
type SheetWriter struct {
	f               io.Writer
	err             error
	currentIndex    uint64
	maxNCols        uint64
	closed          bool
	mergeCells      []string
	mergeCellsCount int
}

// Write the given rows to this SheetWriter
func (sw *SheetWriter) WriteRows(rows []Row) error {
	if sw.closed {
		panic("Can not write to closed SheetWriter")
	}

	var err error

	for i, r := range rows {
		_, err = fmt.Fprintf(sw.f, `<row r="%d">`, uint64(i)+sw.currentIndex+1)
		if err != nil {
			return err
		}

		if sw.maxNCols < uint64(len(r.Cells)) {
			sw.maxNCols = uint64(len(r.Cells))
		}

		for j, c := range r.Cells {

			cellX, cellY := CellIndex(uint64(j), uint64(i)+sw.currentIndex)

			switch c.Type {
			case CellTypeDate, CellTypeDatetime:
				d, err := time.Parse(time.RFC3339, c.Value)
				if err == nil {
					c.Value = OADate(d)
				} else {
					return err
				}
			case CellTypeInlineString:
				c.Value = html.EscapeString(c.Value)
			}

			var cellString string

			switch c.Type {
			case CellTypeString:
				cellString = `<c r="%s%d" t="s" s="1"><v>%s</v></c>`
			case CellTypeInlineString:
				cellString = `<c r="%s%d" t="inlineStr"><is><t>%s</t></is></c>`
			case CellTypeNumber:
				cellString = `<c r="%s%d" t="n" s="1"><v>%s</v></c>`
			case CellTypeDatetime:
				cellString = `<c r="%s%d" s="2"><v>%s</v></c>`
			case CellTypeDate:
				cellString = `<c r="%s%d" s="3"><v>%s</v></c>`
			}

			if c.Colspan < 0 {
				panic(fmt.Sprintf("%v is not a valid colspan", c.Colspan))
			} else if c.Colspan > 1 {
				mergeCellX, _ := CellIndex(uint64(j)+c.Colspan-1, uint64(i)+sw.currentIndex)
				sw.mergeCells = append(sw.mergeCells, fmt.Sprintf(`<mergeCell ref="%[1]s%[2]d:%[3]s%[2]d"/>`, cellX, cellY, mergeCellX))
				if err != nil {
					return err
				}
				sw.mergeCellsCount += 1
			}

			_, err = fmt.Fprintf(sw.f, cellString, cellX, cellY, c.Value)
			if err != nil {
				return err
			}
		}

		_, err = fmt.Fprint(sw.f, `</row>`)
		if err != nil {
			return err
		}

	}

	sw.currentIndex += uint64(len(rows))

	return nil
}

// Closes the SheetWriter
func (sw *SheetWriter) Close() error {
	if sw.closed {
		panic("SheetWriter already closed")
	}

	cellEndX, cellEndY := CellIndex(sw.maxNCols-1, sw.currentIndex-1)
	_, err := fmt.Fprintf(sw.f, `<dimension ref="A1:%s%d"/></sheetData>`, cellEndX, cellEndY)
	if err != nil {
		return err
	}

	if sw.mergeCellsCount > 0 {
		_, err = fmt.Fprintf(sw.f, `<mergeCells count="%v">`, sw.mergeCellsCount)
		if err != nil {
			return err
		}

		for _, mergeCell := range sw.mergeCells {
			_, err = fmt.Fprint(sw.f, mergeCell)
			if err != nil {
				return err
			}
		}
		_, err = fmt.Fprint(sw.f, `</mergeCells>`)
		if err != nil {
			return err
		}
	}
	_, err = fmt.Fprintf(sw.f, `</worksheet>`)
	if err != nil {
		return err
	}

	sw.closed = true

	return nil
}

// Writes the header of a sheet
func (sw *SheetWriter) WriteHeader(s *Sheet) error {
	if sw.closed {
		panic("Can not write to closed SheetWriter")
	}

	sheet := struct {
		Cols []Column
	}{
		Cols: s.columns,
	}

	return TemplateSheetStart.Execute(sw.f, sheet)
}
<commit_msg>Add support for rowspans<commit_after>// Package implements creation of XLSX simple spreadsheet files

package xlsx

import (
	"archive/zip"
	"bufio"
	"fmt"
	"html"
	"io"
	"os"
	"strconv"
	"time"
)

type CellType uint

// Basic spreadsheet cell types
const (
	CellTypeNumber CellType = iota
	CellTypeString
	CellTypeDate
	CellTypeDatetime
	CellTypeInlineString
)

// XLSX Spreadsheet Cell
type Cell struct {
	Type    CellType
	Value   string
	Colspan uint64
	Rowspan uint64
}

// XLSX Spreadsheet Row
type Row struct {
	Cells []Cell
}

// XLSX Spreadsheet Column
type Column struct {
	Name  string
	Width uint64
}

// XLSX Workbook Document Properties
type DocumentInfo struct {
	CreatedBy  string
	ModifiedBy string
	CreatedAt  time.Time
	ModifiedAt time.Time
}

// XLSX Spreadsheet
type Sheet struct {
	Title           string
	columns         []Column
	rows            []Row
	sharedStringMap map[string]int
	sharedStrings   []string
	DocumentInfo    DocumentInfo
}

// Create a sheet with no dimensions
func NewSheet() Sheet {
	c := make([]Column, 0)
	r := make([]Row, 0)
	ssm := make(map[string]int)
	sst := make([]string, 0)

	s := Sheet{
		Title:           "Data",
		columns:         c,
		rows:            r,
		sharedStringMap: ssm,
		sharedStrings:   sst,
	}

	return s
}

// Create a sheet with dimensions derived from the given columns
func NewSheetWithColumns(c []Column) Sheet {
	r := make([]Row, 0)
	ssm := make(map[string]int)
	sst := make([]string, 0)

	s := Sheet{
		Title:           "Data",
		columns:         c,
		rows:            r,
		sharedStringMap: ssm,
		sharedStrings:   sst,
	}

	s.DocumentInfo.CreatedBy = "xlsx.go"
	s.DocumentInfo.CreatedAt = time.Now()

	s.DocumentInfo.ModifiedBy = s.DocumentInfo.CreatedBy
	s.DocumentInfo.ModifiedAt = s.DocumentInfo.CreatedAt

	return s
}

// Create a new row with a length caculated by the sheets known column count
func (s *Sheet) NewRow() Row {
	c := make([]Cell, len(s.columns))
	r := Row{
		Cells: c,
	}
	return r
}

// Append a row to the sheet
func (s *Sheet) AppendRow(r Row) error {
	if len(r.Cells) != len(s.columns) {
		return fmt.Errorf("the given row has %d cells and %d were expected", len(r.Cells), len(s.columns))
	}

	cells := make([]Cell, len(s.columns))

	for n, c := range r.Cells {
		cells[n].Type = c.Type
		cells[n].Value = c.Value

		if cells[n].Type == CellTypeString {
			// calculate string reference
			cells[n].Value = html.EscapeString(cells[n].Value)
			i, exists := s.sharedStringMap[cells[n].Value]
			if !exists {
				i = len(s.sharedStrings)
				s.sharedStringMap[cells[n].Value] = i
				s.sharedStrings = append(s.sharedStrings, cells[n].Value)
			}
			cells[n].Value = strconv.Itoa(i)
		}
	}

	row := s.NewRow()
	row.Cells = cells

	s.rows = append(s.rows, row)

	return nil
}

// Get the Shared Strings in the order they were added to the map
func (s *Sheet) SharedStrings() []string {
	return s.sharedStrings
}

// Given zero-based array indices output the Excel cell reference. For
// example (0,0) => "A1"; (2,2) => "C3"; (26,45) => "AA46"
func CellIndex(x, y uint64) (string, uint64) {
	return colName(x), (y + 1)
}

// From a zero-based column number return the Excel column name.
// For example: 0 => "A"; 2 => "C"; 26 => "AA"
func colName(n uint64) string {
	var s string
	n += 1

	for n > 0 {
		n -= 1
		s = string(65+(n%26)) + s
		n /= 26
	}

	return s
}

// Convert time to the OLE Automation format.
func OADate(d time.Time) string {
	epoch := time.Date(1899, 12, 30, 0, 0, 0, 0, time.UTC)
	nsPerDay := 24 * time.Hour

	v := -1 * float64(epoch.Sub(d)) / float64(nsPerDay)

	// TODO: deal with dates before epoch
	// e.g. http://stackoverflow.com/questions/15549823/oadate-to-milliseconds-timestamp-in-javascript/15550284#15550284

	if d.Hour() == 0 && d.Minute() == 0 && d.Second() == 0 {
		return fmt.Sprintf("%d", int64(v))
	} else {
		return fmt.Sprintf("%f", v)
	}
}

// Create filename and save the XLSX file
func (s *Sheet) SaveToFile(filename string) error {
	outputfile, err := os.Create(filename)
	if err != nil {
		return err
	}
	w := bufio.NewWriter(outputfile)
	err = s.SaveToWriter(w)
	defer w.Flush()
	return err
}

// Save the XLSX file to the given writer
func (s *Sheet) SaveToWriter(w io.Writer) error {

	ww := NewWorkbookWriter(w)

	sw, err := ww.NewSheetWriter(s)
	if err != nil {
		return err
	}

	err = sw.WriteRows(s.rows)
	if err != nil {
		return err
	}

	ww.SharedStrings = s.sharedStrings

	err = ww.Close()

	return err
}

// Write the header files of the workbook
func (ww *WorkbookWriter) WriteHeader() error {
	if ww.headerWritten {
		panic("Workbook header already written")
	}

	z := ww.zipWriter

	f, err := z.Create("[Content_Types].xml")
	err = TemplateContentTypes.Execute(f, ww.sheetNames)
	if err != nil {
		return err
	}

	f, err = z.Create("docProps/app.xml")
	err = TemplateApp.Execute(f, ww.sheetNames)
	if err != nil {
		return err
	}

	f, err = z.Create("docProps/core.xml")
	err = TemplateCore.Execute(f, ww.documentInfo)
	if err != nil {
		return err
	}

	f, err = z.Create("_rels/.rels")
	err = TemplateRelationships.Execute(f, nil)
	if err != nil {
		return err
	}

	f, err = z.Create("xl/workbook.xml")
	err = TemplateWorkbook.Execute(f, ww.sheetNames)
	if err != nil {
		return err
	}

	f, err = z.Create("xl/_rels/workbook.xml.rels")
	err = TemplateWorkbookRelationships.Execute(f, ww.sheetNames)
	if err != nil {
		return err
	}

	f, err = z.Create("xl/styles.xml")
	err = TemplateStyles.Execute(f, nil)
	if err != nil {
		return err
	}

	f, err = z.Create("xl/sharedStrings.xml")
	err = TemplateStringLookups.Execute(f, ww.SharedStrings)
	if err != nil {
		return err
	}

	return err
}

// Handles the writing of an XLSX workbook
type WorkbookWriter struct {
	zipWriter     *zip.Writer
	sheetWriter   *SheetWriter
	headerWritten bool
	closed        bool
	sheetNames    []string
	SharedStrings []string
	documentInfo  *DocumentInfo
}

// Creates a new WorkbookWriter
func NewWorkbookWriter(w io.Writer) *WorkbookWriter {
	return &WorkbookWriter{zip.NewWriter(w), nil, false, false, []string{}, nil, nil}
}

// Closes the WorkbookWriter
func (ww *WorkbookWriter) Close() error {
	if ww.closed {
		panic("WorkbookWriter already closed")
	}

	if ww.sheetWriter != nil {
		err := ww.sheetWriter.Close()
		if err != nil {
			return err
		}
	}

	if !ww.headerWritten {
		err := ww.WriteHeader()
		if err != nil {
			return err
		}
	}

	ww.closed = true

	return ww.zipWriter.Close()
}

// NewSheetWriter creates a new SheetWriter in this workbook using the given sheet.
// It returns a SheetWriter to which rows can be written.
// All rows must be written to the SheetWriter before the next call to NewSheetWriter,
// as this will automatically close the previous SheetWriter.
func (ww *WorkbookWriter) NewSheetWriter(s *Sheet) (*SheetWriter, error) {
	if ww.closed {
		panic("Can not write to closed WorkbookWriter")
	}

	if ww.sheetWriter != nil {
		err := ww.sheetWriter.Close()
		if err != nil {
			return nil, err
		}
	}

	f, err := ww.zipWriter.Create("xl/worksheets/" + fmt.Sprintf("sheet%s", strconv.Itoa(len(ww.sheetNames)+1)) + ".xml")
	sw := &SheetWriter{f, err, 0, 0, false, []string{}, 0}

	ww.documentInfo = &s.DocumentInfo

	ww.sheetWriter = sw
	err = sw.WriteHeader(s)

	ww.sheetNames = append(ww.sheetNames, s.Title)

	return sw, err
}

// Handles the writing of a sheet
type SheetWriter struct {
	f               io.Writer
	err             error
	currentIndex    uint64
	maxNCols        uint64
	closed          bool
	mergeCells      []string
	mergeCellsCount int
}

// Write the given rows to this SheetWriter
func (sw *SheetWriter) WriteRows(rows []Row) error {
	if sw.closed {
		panic("Can not write to closed SheetWriter")
	}

	var err error

	for i, r := range rows {
		_, err = fmt.Fprintf(sw.f, `<row r="%d">`, uint64(i)+sw.currentIndex+1)
		if err != nil {
			return err
		}

		if sw.maxNCols < uint64(len(r.Cells)) {
			sw.maxNCols = uint64(len(r.Cells))
		}

		for j, c := range r.Cells {

			cellX, cellY := CellIndex(uint64(j), uint64(i)+sw.currentIndex)

			switch c.Type {
			case CellTypeDate, CellTypeDatetime:
				d, err := time.Parse(time.RFC3339, c.Value)
				if err == nil {
					c.Value = OADate(d)
				} else {
					return err
				}
			case CellTypeInlineString:
				c.Value = html.EscapeString(c.Value)
			}

			var cellString string

			switch c.Type {
			case CellTypeString:
				cellString = `<c r="%s%d" t="s" s="1"><v>%s</v></c>`
			case CellTypeInlineString:
				cellString = `<c r="%s%d" t="inlineStr"><is><t>%s</t></is></c>`
			case CellTypeNumber:
				cellString = `<c r="%s%d" t="n" s="1"><v>%s</v></c>`
			case CellTypeDatetime:
				cellString = `<c r="%s%d" s="2"><v>%s</v></c>`
			case CellTypeDate:
				cellString = `<c r="%s%d" s="3"><v>%s</v></c>`
			}

			if c.Colspan < 0 || c.Rowspan < 0 {
				panic(fmt.Sprintf("%v is not a valid colspan", c.Colspan))
			} else if c.Colspan > 1 || c.Rowspan > 1 {

				if c.Colspan < 1 {
					c.Colspan = 1
				}
				if c.Rowspan < 1 {
					c.Rowspan = 1
				}

				mergeCellX, mergeCellY := CellIndex(uint64(j)+c.Colspan-1, uint64(i)+sw.currentIndex+c.Rowspan-1)
				sw.mergeCells = append(sw.mergeCells, fmt.Sprintf(`<mergeCell ref="%[1]s%[2]d:%[3]s%[4]d"/>`, cellX, cellY, mergeCellX, mergeCellY))
				if err != nil {
					return err
				}
				sw.mergeCellsCount += 1
			}

			_, err = fmt.Fprintf(sw.f, cellString, cellX, cellY, c.Value)
			if err != nil {
				return err
			}
		}

		_, err = fmt.Fprint(sw.f, `</row>`)
		if err != nil {
			return err
		}

	}

	sw.currentIndex += uint64(len(rows))

	return nil
}

// Closes the SheetWriter
func (sw *SheetWriter) Close() error {
	if sw.closed {
		panic("SheetWriter already closed")
	}

	cellEndX, cellEndY := CellIndex(sw.maxNCols-1, sw.currentIndex-1)
	_, err := fmt.Fprintf(sw.f, `<dimension ref="A1:%s%d"/></sheetData>`, cellEndX, cellEndY)
	if err != nil {
		return err
	}

	if sw.mergeCellsCount > 0 {
		_, err = fmt.Fprintf(sw.f, `<mergeCells count="%v">`, sw.mergeCellsCount)
		if err != nil {
			return err
		}

		for _, mergeCell := range sw.mergeCells {
			_, err = fmt.Fprint(sw.f, mergeCell)
			if err != nil {
				return err
			}
		}
		_, err = fmt.Fprint(sw.f, `</mergeCells>`)
		if err != nil {
			return err
		}
	}
	_, err = fmt.Fprintf(sw.f, `</worksheet>`)
	if err != nil {
		return err
	}

	sw.closed = true

	return nil
}

// Writes the header of a sheet
func (sw *SheetWriter) WriteHeader(s *Sheet) error {
	if sw.closed {
		panic("Can not write to closed SheetWriter")
	}

	sheet := struct {
		Cols []Column
	}{
		Cols: s.columns,
	}

	return TemplateSheetStart.Execute(sw.f, sheet)
}
<|endoftext|>