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

// Package fuseops contains implementations of the fuse.Op interface that may
// be returned by fuse.Connection.ReadOp. See documentation in that package for
// more.
package fuseops

import (
	"time"

	"github.com/jacobsa/bazilfuse"
	"golang.org/x/net/context"
)

// Convert the supplied bazilfuse request struct to an Op, returning nil if it
// is unknown.
//
// This function is an implementation detail of the fuse package, and must not
// be called by anyone else.
func Convert(r bazilfuse.Request) (o Op) {
	var co *commonOp

	switch typed := r.(type) {
	case *bazilfuse.InitRequest:
		to := &InitOp{}
		o = to
		co = &to.commonOp

	case *bazilfuse.LookupRequest:
		to := &LookUpInodeOp{
			Parent: InodeID(typed.Header.Node),
			Name:   typed.Name,
		}
		o = to
		co = &to.commonOp

	case *bazilfuse.GetattrRequest:
		to := &GetInodeAttributesOp{
			Inode: InodeID(typed.Header.Node),
		}
		o = to
		co = &to.commonOp

	case *bazilfuse.SetattrRequest:
		to := &SetInodeAttributesOp{
			Inode: InodeID(typed.Header.Node),
		}
		o = to
		co = &to.commonOp

	case *bazilfuse.MkdirRequest:
		to := &MkDirOp{
			Parent: InodeID(typed.Header.Node),
			Name:   typed.Name,
			Mode:   typed.Mode,
		}
		o = to
		co = &to.commonOp

	case *bazilfuse.CreateRequest:
		to := &CreateFileOp{
			Parent: InodeID(typed.Header.Node),
			Name:   typed.Name,
			Mode:   typed.Mode,
			Flags:  typed.Flags,
		}
		o = to
		co = &to.commonOp

	case *bazilfuse.RemoveRequest:
		if typed.Dir {
			to := &RmDirOp{
				Parent: InodeID(typed.Header.Node),
				Name:   typed.Name,
			}
			o = to
			co = &to.commonOp
		} else {
			to := &UnlinkOp{
				Parent: InodeID(typed.Header.Node),
				Name:   typed.Name,
			}
			o = to
			co = &to.commonOp
		}

	case *bazilfuse.OpenRequest:
		if typed.Dir {
			to := &OpenDirOp{
				Inode: InodeID(typed.Header.Node),
				Flags: typed.Flags,
			}
			o = to
			co = &to.commonOp
		} else {
			to := &OpenFileOp{
				Inode: InodeID(typed.Header.Node),
				Flags: typed.Flags,
			}
			o = to
			co = &to.commonOp
		}

	case *bazilfuse.ReadRequest:
		if typed.Dir {
			to := &ReadDirOp{
				Inode:  InodeID(typed.Header.Node),
				Handle: HandleID(typed.Handle),
				Offset: DirOffset(typed.Offset),
				Size:   typed.Size,
			}
			o = to
			co = &to.commonOp
		} else {
			to := &ReadFileOp{
				Inode:  InodeID(typed.Header.Node),
				Handle: HandleID(typed.Handle),
				Offset: typed.Offset,
				Size:   typed.Size,
			}
			o = to
			co = &to.commonOp
		}

	case *bazilfuse.ReleaseRequest:
		if typed.Dir {
			to := &ReleaseDirHandleOp{
				Handle: HandleID(typed.Handle),
			}
			o = to
			co = &to.commonOp
		} else {
			to := &ReadFileOp{
				Handle: HandleID(typed.Handle),
			}
			o = to
			co = &to.commonOp
		}

	case *bazilfuse.WriteRequest:
		to := &WriteFileOp{
			Inode:  InodeID(typed.Header.Node),
			Handle: HandleID(typed.Handle),
			Data:   typed.Data,
			Offset: typed.Offset,
		}
		o = to
		co = &to.commonOp

	case *bazilfuse.FsyncRequest:
		// We don't currently support this for directories.
		if typed.Dir {
			return
		}

		to := &SyncFileOp{
			Inode:  InodeID(typed.Header.Node),
			Handle: HandleID(typed.Handle),
		}
		o = to
		co = &to.commonOp

	case *bazilfuse.FlushRequest:
		to := &FlushFileOp{
			Inode:  InodeID(typed.Header.Node),
			Handle: HandleID(typed.Handle),
		}
		o = to
		co = &to.commonOp

	default:
		return
	}

	co.init(r)
	return
}

func convertAttributes(inode InodeID, attr InodeAttributes) bazilfuse.Attr {
	return bazilfuse.Attr{
		Inode:  uint64(inode),
		Size:   attr.Size,
		Mode:   attr.Mode,
		Nlink:  uint32(attr.Nlink),
		Atime:  attr.Atime,
		Mtime:  attr.Mtime,
		Ctime:  attr.Ctime,
		Crtime: attr.Crtime,
		Uid:    attr.Uid,
		Gid:    attr.Gid,
	}
}

// Convert an absolute cache expiration time to a relative time from now for
// consumption by fuse.
func convertExpirationTime(t time.Time) (d time.Duration) {
	// Fuse represents durations as unsigned 64-bit counts of seconds and 32-bit
	// counts of nanoseconds (cf. http://goo.gl/EJupJV). The bazil.org/fuse
	// package converts time.Duration values to this form in a straightforward
	// way (cf. http://goo.gl/FJhV8j).
	//
	// So negative durations are right out. There is no need to cap the positive
	// magnitude, because 2^64 seconds is well longer than the 2^63 ns range of
	// time.Duration.
	d = t.Sub(time.Now())
	if d < 0 {
		d = 0
	}

	return
}

func convertChildInodeEntry(
	in *ChildInodeEntry,
	out *bazilfuse.LookupResponse) {
	out.Node = bazilfuse.NodeID(in.Child)
	out.Generation = uint64(in.Generation)
	out.Attr = convertAttributes(in.Child, in.Attributes)
	out.AttrValid = convertExpirationTime(in.AttributesExpiration)
	out.EntryValid = convertExpirationTime(in.EntryExpiration)
}

// A helper for embedding common behavior.
type commonOp struct {
	ctx context.Context
	r   bazilfuse.Request
}

func (o *commonOp) init(r bazilfuse.Request) {
	o.ctx = context.Background()
	o.r = r
}

func (o *commonOp) Header() OpHeader {
	bh := o.r.Hdr()
	return OpHeader{
		Uid: bh.Uid,
		Gid: bh.Gid,
	}
}

func (o *commonOp) Context() context.Context {
	return o.ctx
}

func (o *commonOp) respondErr(err error) {
	if err != nil {
		panic("Expect non-nil here.")
	}

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

// Package fuseops contains implementations of the fuse.Op interface that may
// be returned by fuse.Connection.ReadOp. See documentation in that package for
// more.
package fuseops

import (
	"time"

	"github.com/jacobsa/bazilfuse"
	"golang.org/x/net/context"
)

// Convert the supplied bazilfuse request struct to an Op, returning nil if it
// is unknown.
//
// This function is an implementation detail of the fuse package, and must not
// be called by anyone else.
func Convert(r bazilfuse.Request) (o Op) {
	var co *commonOp

	switch typed := r.(type) {
	case *bazilfuse.InitRequest:
		to := &InitOp{}
		o = to
		co = &to.commonOp

	case *bazilfuse.LookupRequest:
		to := &LookUpInodeOp{
			Parent: InodeID(typed.Header.Node),
			Name:   typed.Name,
		}
		o = to
		co = &to.commonOp

	case *bazilfuse.GetattrRequest:
		to := &GetInodeAttributesOp{
			Inode: InodeID(typed.Header.Node),
		}
		o = to
		co = &to.commonOp

	case *bazilfuse.SetattrRequest:
		to := &SetInodeAttributesOp{
			Inode: InodeID(typed.Header.Node),
		}
		o = to
		co = &to.commonOp

	case *bazilfuse.MkdirRequest:
		to := &MkDirOp{
			Parent: InodeID(typed.Header.Node),
			Name:   typed.Name,
			Mode:   typed.Mode,
		}
		o = to
		co = &to.commonOp

	case *bazilfuse.CreateRequest:
		to := &CreateFileOp{
			Parent: InodeID(typed.Header.Node),
			Name:   typed.Name,
			Mode:   typed.Mode,
			Flags:  typed.Flags,
		}
		o = to
		co = &to.commonOp

	case *bazilfuse.RemoveRequest:
		if typed.Dir {
			to := &RmDirOp{
				Parent: InodeID(typed.Header.Node),
				Name:   typed.Name,
			}
			o = to
			co = &to.commonOp
		} else {
			to := &UnlinkOp{
				Parent: InodeID(typed.Header.Node),
				Name:   typed.Name,
			}
			o = to
			co = &to.commonOp
		}

	case *bazilfuse.OpenRequest:
		if typed.Dir {
			to := &OpenDirOp{
				Inode: InodeID(typed.Header.Node),
				Flags: typed.Flags,
			}
			o = to
			co = &to.commonOp
		} else {
			to := &OpenFileOp{
				Inode: InodeID(typed.Header.Node),
				Flags: typed.Flags,
			}
			o = to
			co = &to.commonOp
		}

	case *bazilfuse.ReadRequest:
		if typed.Dir {
			to := &ReadDirOp{
				Inode:  InodeID(typed.Header.Node),
				Handle: HandleID(typed.Handle),
				Offset: DirOffset(typed.Offset),
				Size:   typed.Size,
			}
			o = to
			co = &to.commonOp
		} else {
			to := &ReadFileOp{
				Inode:  InodeID(typed.Header.Node),
				Handle: HandleID(typed.Handle),
				Offset: typed.Offset,
				Size:   typed.Size,
			}
			o = to
			co = &to.commonOp
		}

	case *bazilfuse.ReleaseRequest:
		if typed.Dir {
			to := &ReleaseDirHandleOp{
				Handle: HandleID(typed.Handle),
			}
			o = to
			co = &to.commonOp
		} else {
			to := &ReadFileOp{
				Handle: HandleID(typed.Handle),
			}
			o = to
			co = &to.commonOp
		}

	case *bazilfuse.WriteRequest:
		to := &WriteFileOp{
			Inode:  InodeID(typed.Header.Node),
			Handle: HandleID(typed.Handle),
			Data:   typed.Data,
			Offset: typed.Offset,
		}
		o = to
		co = &to.commonOp

	case *bazilfuse.FsyncRequest:
		// We don't currently support this for directories.
		if typed.Dir {
			return
		}

		to := &SyncFileOp{
			Inode:  InodeID(typed.Header.Node),
			Handle: HandleID(typed.Handle),
		}
		o = to
		co = &to.commonOp

	case *bazilfuse.FlushRequest:
		to := &FlushFileOp{
			Inode:  InodeID(typed.Header.Node),
			Handle: HandleID(typed.Handle),
		}
		o = to
		co = &to.commonOp

	default:
		return
	}

	co.init(r)
	return
}

func convertAttributes(inode InodeID, attr InodeAttributes) bazilfuse.Attr {
	return bazilfuse.Attr{
		Inode:  uint64(inode),
		Size:   attr.Size,
		Mode:   attr.Mode,
		Nlink:  uint32(attr.Nlink),
		Atime:  attr.Atime,
		Mtime:  attr.Mtime,
		Ctime:  attr.Ctime,
		Crtime: attr.Crtime,
		Uid:    attr.Uid,
		Gid:    attr.Gid,
	}
}

// Convert an absolute cache expiration time to a relative time from now for
// consumption by fuse.
func convertExpirationTime(t time.Time) (d time.Duration) {
	// Fuse represents durations as unsigned 64-bit counts of seconds and 32-bit
	// counts of nanoseconds (cf. http://goo.gl/EJupJV). The bazil.org/fuse
	// package converts time.Duration values to this form in a straightforward
	// way (cf. http://goo.gl/FJhV8j).
	//
	// So negative durations are right out. There is no need to cap the positive
	// magnitude, because 2^64 seconds is well longer than the 2^63 ns range of
	// time.Duration.
	d = t.Sub(time.Now())
	if d < 0 {
		d = 0
	}

	return
}

func convertChildInodeEntry(
	in *ChildInodeEntry,
	out *bazilfuse.LookupResponse) {
	out.Node = bazilfuse.NodeID(in.Child)
	out.Generation = uint64(in.Generation)
	out.Attr = convertAttributes(in.Child, in.Attributes)
	out.AttrValid = convertExpirationTime(in.AttributesExpiration)
	out.EntryValid = convertExpirationTime(in.EntryExpiration)
}

// A helper for embedding common behavior.
type commonOp struct {
	ctx context.Context
	r   bazilfuse.Request
}

func (o *commonOp) init(r bazilfuse.Request) {
	o.ctx = context.Background()
	o.r = r
}

func (o *commonOp) Header() OpHeader {
	bh := o.r.Hdr()
	return OpHeader{
		Uid: bh.Uid,
		Gid: bh.Gid,
	}
}

func (o *commonOp) Context() context.Context {
	return o.ctx
}

func (o *commonOp) respondErr(err error) {
	if err == nil {
		panic("Expect non-nil here.")
	}

	o.r.RespondError(err)
}
<|endoftext|>


<commit_before>// Convert Wikipedia XML dump to JSON or extract categories
package main

import (
	"encoding/json"
	"encoding/xml"
	"flag"
	"fmt"
	"io"
	"net/url"
	"os"
	"regexp"
	"strings"
)

const AppVersion = "1.0.7"

// Here is an example article from the Wikipedia XML dump
//
// <page>
// 	<title>Apollo 11</title>
//      <redirect title="Foo bar" />
// 	...
// 	<revision>
// 	...
// 	  <text xml:space="preserve">
// 	  {{Infobox Space mission
// 	  |mission_name=<!--See above-->
// 	  |insignia=Apollo_11_insignia.png
// 	...
// 	  </text>
// 	</revision>
// </page>
//
// Note how the tags on the fields of Page and Redirect below
// describe the XML schema structure.

type Redirect struct {
	Title string `xml:"title,attr" json:"title"`
}

type Page struct {
	Title          string   `xml:"title" json:"title"`
	CanonicalTitle string   `xml:"ctitle" json:"ctitle"`
	Redir          Redirect `xml:"redirect" json:"redirect"`
	Text           string   `xml:"revision>text" json:"text"`
}

type WikidataPage struct {
	Title          string      `xml:"title" json:"title"`
	CanonicalTitle string      `xml:"ctitle" json:"ctitle"`
	Redir          Redirect    `xml:"redirect" json:"redirect"`
	Content        interface{} `json:"content"`
}

func CanonicalizeTitle(title string) string {
	can := strings.ToLower(title)
	can = strings.Replace(can, " ", "_", -1)
	can = url.QueryEscape(can)
	return can
}

func main() {

	version := flag.Bool("v", false, "prints current version and exits")
	extractCategories := flag.String("c", "", "only extract categories TSV(page, category)")
	extractAuthorityData := flag.Bool("a", false, "only extract authority data (Normdaten)")
	decodeWikiData := flag.Bool("d", false, "decode the text key value")
	filter, _ := regexp.Compile("^file:.*|^talk:.*|^special:.*|^wikipedia:.*|^wiktionary:.*|^user:.*|^user_talk:.*")

	flag.Usage = func() {
		fmt.Fprintf(os.Stderr, "Usage of %s:\n", os.Args[0])
		fmt.Fprintf(os.Stderr, "\nExtract and convert things from wikipedia/wikidata XML dumps.\n\n")
		flag.PrintDefaults()
	}

	flag.Parse()

	if *extractCategories != "" && *extractAuthorityData {
		fmt.Println("It's either -a or -c")
		os.Exit(1)
	}

	if *version {
		fmt.Println(AppVersion)
		os.Exit(0)
	}

	if flag.NArg() < 1 {
		flag.Usage()
		os.Exit(1)
	}
	inputFile := flag.Args()[0]

	xmlFile, err := os.Open(inputFile)
	if err != nil {
		fmt.Println("Error opening file:", err)
		return
	}
	defer xmlFile.Close()

	decoder := xml.NewDecoder(xmlFile)
	var inElement string
	categoryPattern := regexp.MustCompile(`\[\[` + *extractCategories + `:([^\[]+)\]\]`)
	authorityDataPattern := regexp.MustCompile(`(?mi){{Normdaten[^}]*}}`)

	// for wikidata
	var container interface{}

	for {
		// Read tokens from the XML document in a stream.
		t, _ := decoder.Token()
		if t == nil {
			break
		}
		// Inspect the type of the token just read.
		switch se := t.(type) {
		case xml.StartElement:
			// If we just read a StartElement token
			inElement = se.Name.Local
			// ...and its name is "page"
			if inElement == "page" {
				var p Page
				// decode a whole chunk of following XML into the
				// variable p which is a Page (se above)
				decoder.DecodeElement(&p, &se)

				// Do some stuff with the page.
				p.CanonicalTitle = CanonicalizeTitle(p.Title)
				m := filter.MatchString(p.CanonicalTitle)
				if !m && p.Redir.Title == "" {
					if *extractCategories != "" {
						result := categoryPattern.FindAllStringSubmatch(p.Text, -1)
						for _, value := range result {
							// replace anything after a |
							category := strings.TrimSpace(value[1])
							firstIndex := strings.Index(category, "|")
							if firstIndex != -1 {
								category = category[0:firstIndex]
							}
							fmt.Printf("%s\t%s\n", p.Title, category)
						}
					} else if *extractAuthorityData {
						result := authorityDataPattern.FindString(p.Text)
						if result != "" {
							// https://cdn.mediacru.sh/JsdjtGoLZBcR.png
							result = strings.Replace(result, "\t", "", -1)
							fmt.Printf("%s\t%s\n", p.Title, result)
						}
					} else if *decodeWikiData {

						dec := json.NewDecoder(strings.NewReader(p.Text))
						dec.UseNumber()

						if err := dec.Decode(&container); err == io.EOF {
							break
						} else if err != nil {
							fmt.Fprintf(os.Stderr, "%s\n", err)
							continue
						}

						parsed := WikidataPage{Title: p.Title,
							CanonicalTitle: p.CanonicalTitle,
							Content:        container,
							Redir:          p.Redir}

						b, err := json.Marshal(parsed)
						if err != nil {
							os.Exit(2)
						}
						fmt.Println(string(b))
					} else {
						b, err := json.Marshal(p)
						if err != nil {
							os.Exit(2)
						}
						fmt.Println(string(b))
					}
				}
			}
		default:
		}
	}
}
<commit_msg>show version in usage<commit_after>// Convert Wikipedia XML dump to JSON or extract categories
package main

import (
	"encoding/json"
	"encoding/xml"
	"flag"
	"fmt"
	"io"
	"net/url"
	"os"
	"regexp"
	"strings"
)

const AppVersion = "1.0.7"

// Here is an example article from the Wikipedia XML dump
//
// <page>
// 	<title>Apollo 11</title>
//      <redirect title="Foo bar" />
// 	...
// 	<revision>
// 	...
// 	  <text xml:space="preserve">
// 	  {{Infobox Space mission
// 	  |mission_name=<!--See above-->
// 	  |insignia=Apollo_11_insignia.png
// 	...
// 	  </text>
// 	</revision>
// </page>
//
// Note how the tags on the fields of Page and Redirect below
// describe the XML schema structure.

type Redirect struct {
	Title string `xml:"title,attr" json:"title"`
}

type Page struct {
	Title          string   `xml:"title" json:"title"`
	CanonicalTitle string   `xml:"ctitle" json:"ctitle"`
	Redir          Redirect `xml:"redirect" json:"redirect"`
	Text           string   `xml:"revision>text" json:"text"`
}

type WikidataPage struct {
	Title          string      `xml:"title" json:"title"`
	CanonicalTitle string      `xml:"ctitle" json:"ctitle"`
	Redir          Redirect    `xml:"redirect" json:"redirect"`
	Content        interface{} `json:"content"`
}

func CanonicalizeTitle(title string) string {
	can := strings.ToLower(title)
	can = strings.Replace(can, " ", "_", -1)
	can = url.QueryEscape(can)
	return can
}

func main() {

	version := flag.Bool("v", false, "prints current version and exits")
	extractCategories := flag.String("c", "", "only extract categories TSV(page, category)")
	extractAuthorityData := flag.Bool("a", false, "only extract authority data (Normdaten)")
	decodeWikiData := flag.Bool("d", false, "decode the text key value")
	filter, _ := regexp.Compile("^file:.*|^talk:.*|^special:.*|^wikipedia:.*|^wiktionary:.*|^user:.*|^user_talk:.*")

	flag.Usage = func() {
		fmt.Fprintf(os.Stderr, "Usage of %s:\n", os.Args[0])
		fmt.Fprintf(os.Stderr, "\nExtract and convert things from wikipedia/wikidata XML dumps.\n")
		fmt.Fprintf(os.Stderr, "\nVersion: %s\n\n", AppVersion)
		flag.PrintDefaults()
	}

	flag.Parse()

	if *extractCategories != "" && *extractAuthorityData {
		fmt.Println("It's either -a or -c")
		os.Exit(1)
	}

	if *version {
		fmt.Println(AppVersion)
		os.Exit(0)
	}

	if flag.NArg() < 1 {
		flag.Usage()
		os.Exit(1)
	}
	inputFile := flag.Args()[0]

	xmlFile, err := os.Open(inputFile)
	if err != nil {
		fmt.Println("Error opening file:", err)
		return
	}
	defer xmlFile.Close()

	decoder := xml.NewDecoder(xmlFile)
	var inElement string
	categoryPattern := regexp.MustCompile(`\[\[` + *extractCategories + `:([^\[]+)\]\]`)
	authorityDataPattern := regexp.MustCompile(`(?mi){{Normdaten[^}]*}}`)

	// for wikidata
	var container interface{}

	for {
		// Read tokens from the XML document in a stream.
		t, _ := decoder.Token()
		if t == nil {
			break
		}
		// Inspect the type of the token just read.
		switch se := t.(type) {
		case xml.StartElement:
			// If we just read a StartElement token
			inElement = se.Name.Local
			// ...and its name is "page"
			if inElement == "page" {
				var p Page
				// decode a whole chunk of following XML into the
				// variable p which is a Page (se above)
				decoder.DecodeElement(&p, &se)

				// Do some stuff with the page.
				p.CanonicalTitle = CanonicalizeTitle(p.Title)
				m := filter.MatchString(p.CanonicalTitle)
				if !m && p.Redir.Title == "" {
					if *extractCategories != "" {
						result := categoryPattern.FindAllStringSubmatch(p.Text, -1)
						for _, value := range result {
							// replace anything after a |
							category := strings.TrimSpace(value[1])
							firstIndex := strings.Index(category, "|")
							if firstIndex != -1 {
								category = category[0:firstIndex]
							}
							fmt.Printf("%s\t%s\n", p.Title, category)
						}
					} else if *extractAuthorityData {
						result := authorityDataPattern.FindString(p.Text)
						if result != "" {
							// https://cdn.mediacru.sh/JsdjtGoLZBcR.png
							result = strings.Replace(result, "\t", "", -1)
							fmt.Printf("%s\t%s\n", p.Title, result)
						}
					} else if *decodeWikiData {

						dec := json.NewDecoder(strings.NewReader(p.Text))
						dec.UseNumber()

						if err := dec.Decode(&container); err == io.EOF {
							break
						} else if err != nil {
							fmt.Fprintf(os.Stderr, "%s\n", err)
							continue
						}

						parsed := WikidataPage{Title: p.Title,
							CanonicalTitle: p.CanonicalTitle,
							Content:        container,
							Redir:          p.Redir}

						b, err := json.Marshal(parsed)
						if err != nil {
							os.Exit(2)
						}
						fmt.Println(string(b))
					} else {
						b, err := json.Marshal(p)
						if err != nil {
							os.Exit(2)
						}
						fmt.Println(string(b))
					}
				}
			}
		default:
		}
	}
}
<|endoftext|>


<commit_before>// Copyright (c) 2014 TSUYUSATO Kitsune
// This software is released under the MIT License.
// http://opensource.org/licenses/mit-license.php

// +build windows

// Package hotkey_win is win32api wrapper for hotkey.
package hotkey_win

import (
	. "github.com/lxn/win"
	"syscall"
)

var (
	libuser32   uintptr
	libkernel32 uintptr

	registerHotKey    uintptr
	unregisterHotKey  uintptr
	postThreadMessage uintptr

	getCurrentThread uintptr
	getThreadId      uintptr
)

func init() {
	// Library
	libuser32 = MustLoadLibrary("user32.dll")
	libkernel32 = MustLoadLibrary("kernel32.dll")

	// Functions
	registerHotKey = MustGetProcAddress(libuser32, "RegisterHotKey")
	unregisterHotKey = MustGetProcAddress(libuser32, "UnregisterHotKey")
	postThreadMessage = MustGetProcAddress(libuser32, "PostThreadMessageW")

	getCurrentThread = MustGetProcAddress(libkernel32, "GetCurrentThread")
	getThreadId = MustGetProcAddress(libkernel32, "GetThreadId")
}

func RegisterHotKey(hwnd HWND, id int32, fsModifiers, vk uint32) bool {
	ret, _, _ := syscall.Syscall6(registerHotKey, 4,
		uintptr(hwnd),
		uintptr(id),
		uintptr(fsModifiers),
		uintptr(vk),
		0, 0)

	return ret != 0
}

func PostThreadMessage(idThread uint32, msg uint32, wParam, lParam int32) bool {
	ret, _, _ := syscall.Syscall6(postThreadMessage, 4,
		uintptr(idThread),
		uintptr(msg),
		uintptr(wParam),
		uintptr(lParam),
		0, 0)
	return ret != 0
}

func UnregisterHotKey(hwnd HWND, id int32) bool {
	ret, _, _ := syscall.Syscall(unregisterHotKey, 2,
		uintptr(hwnd),
		uintptr(id),
		0)

	return ret != 0
}

func GetCurrentThread() HANDLE {
	ret, _, _ := syscall.Syscall(getCurrentThread, 0, 0, 0, 0)
	return HANDLE(ret)
}

func GetThreadId(thread HANDLE) uint32 {
	ret, _, _ := syscall.Syscall(getThreadId, 1, uintptr(thread), 0, 0)
	return uint32(ret)
}
<commit_msg>Fix for newer lxn/win versions (after 2019 March 6)<commit_after>// Copyright (c) 2014 TSUYUSATO Kitsune
// This software is released under the MIT License.
// http://opensource.org/licenses/mit-license.php

// +build windows

// Package hotkey_win is win32api wrapper for hotkey.
package hotkey_win

import (
	"github.com/lxn/win"
	"golang.org/x/sys/windows"
)

var (
	registerHotKey    *windows.LazyProc
	unregisterHotKey  *windows.LazyProc
	postThreadMessage *windows.LazyProc

	getCurrentThread *windows.LazyProc
	getThreadId      *windows.LazyProc
)

func init() {
	// Library
	libuser32 := windows.NewLazySystemDLL("user32.dll")
	libkernel32 := windows.NewLazySystemDLL("kernel32.dll")

	// Functions
	registerHotKey = libuser32.NewProc("RegisterHotKey")
	unregisterHotKey = libuser32.NewProc("UnregisterHotKey")
	postThreadMessage = libuser32.NewProc("PostThreadMessageW")

	getCurrentThread = libkernel32.NewProc("GetCurrentThread")
	getThreadId = libkernel32.NewProc("GetThreadId")
}

func RegisterHotKey(hwnd win.HWND, id int32, fsModifiers, vk uint32) bool {
	ret, _, _ := registerHotKey.Call(
		uintptr(hwnd),
		uintptr(id),
		uintptr(fsModifiers),
		uintptr(vk))

	return ret != 0
}

func PostThreadMessage(idThread uint32, msg uint32, wParam, lParam int32) bool {
	ret, _, _ := postThreadMessage.Call(
		uintptr(idThread),
		uintptr(msg),
		uintptr(wParam),
		uintptr(lParam))
	return ret != 0
}

func UnregisterHotKey(hwnd win.HWND, id int32) bool {
	ret, _, _ := unregisterHotKey.Call(
		uintptr(hwnd),
		uintptr(id))

	return ret != 0
}

func GetCurrentThread() win.HANDLE {
	ret, _, _ := getCurrentThread.Call()
	return win.HANDLE(ret)
}

func GetThreadId(thread win.HANDLE) uint32 {
	ret, _, _ := getThreadId.Call(uintptr(thread))
	return uint32(ret)
}
<|endoftext|>


<commit_before>package main

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

	"github.com/fern4lvarez/piladb/pila"
	"github.com/fern4lvarez/piladb/pkg/uuid"
	"github.com/fern4lvarez/piladb/pkg/version"

	"github.com/gorilla/mux"
)

// Conn represents the current piladb connection, containing
// the Pila instance and its status.
type Conn struct {
	Pila   *pila.Pila
	Status *Status
}

// NewConn creates and returns a new piladb connection.
func NewConn() *Conn {
	conn := &Conn{}
	conn.Pila = pila.NewPila()
	conn.Status = NewStatus(version.CommitHash(), time.Now(), MemStats())
	return conn
}

// Connection Handlers

// statusHandler writes the piladb status into the response.
func (c *Conn) statusHandler(w http.ResponseWriter, r *http.Request) {
	c.Status.Update(time.Now(), MemStats())

	w.Header().Set("Content-Type", "application/json")
	log.Println(r.Method, r.URL, http.StatusOK)
	w.Write(c.Status.ToJSON())
}

// databasesHandler returns the information of the running databases.
func (c *Conn) databasesHandler(w http.ResponseWriter, r *http.Request) {
	if r.Method == "PUT" {
		c.createDatabaseHandler(w, r)
		return
	}

	w.Header().Set("Content-Type", "application/json")
	log.Println(r.Method, r.URL, http.StatusOK)
	w.Write(c.Pila.Status().ToJSON())
}

// createDatabaseHandler creates a Database and returns 201 and the ID and name
// of the Database.
func (c *Conn) createDatabaseHandler(w http.ResponseWriter, r *http.Request) {
	name := r.FormValue("name")
	if name == "" {
		log.Println(r.Method, r.URL, http.StatusBadRequest, "missing name")
		w.WriteHeader(http.StatusBadRequest)
		return
	}

	db := pila.NewDatabase(name)
	err := c.Pila.AddDatabase(db)
	if err != nil {
		log.Println(r.Method, r.URL, http.StatusConflict, err)
		w.WriteHeader(http.StatusConflict)
		return
	}

	w.Header().Set("Content-Type", "application/json")
	log.Println(r.Method, r.URL, http.StatusCreated)
	w.WriteHeader(http.StatusCreated)
	w.Write(db.Status().ToJSON())
}

// databaseHandler returns the information of a single database given its ID
// or name.
func (c *Conn) databaseHandler(databaseID string) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		vars := mux.Vars(r)

		// we override the mux vars to be able to test
		// an arbitrary database ID
		if databaseID != "" {
			vars = map[string]string{
				"id": databaseID,
			}
		}

		db, ok := ResourceDatabase(c, vars["id"])
		if !ok {
			c.goneHandler(w, r, fmt.Sprintf("database %s is Gone", vars["id"]))
			return
		}

		if r.Method == "DELETE" {
			_ = c.Pila.RemoveDatabase(db.ID)
			log.Println(r.Method, r.URL, http.StatusNoContent)
			w.WriteHeader(http.StatusNoContent)
			return
		}

		w.Header().Set("Content-Type", "application/json")
		log.Println(r.Method, r.URL, http.StatusOK)
		w.Write(db.Status().ToJSON())
	})
}

// stacksHandler handles the stacks of a database, being able to get the status
// of them, or create a new one.
func (c *Conn) stacksHandler(databaseID string) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		vars := mux.Vars(r)

		// we override the mux vars to be able to test
		// an arbitrary database ID
		if databaseID != "" {
			vars = map[string]string{
				"database_id": databaseID,
			}
		}

		db, ok := ResourceDatabase(c, vars["database_id"])
		if !ok {
			c.goneHandler(w, r, fmt.Sprintf("database %s is Gone", vars["database_id"]))
			return
		}

		if r.Method == "PUT" {
			c.createStackHandler(w, r, db.ID.String())
			return
		}

		res, err := db.StacksStatus().ToJSON()
		if err != nil {
			log.Println(r.Method, r.URL, http.StatusBadRequest,
				"error on response serialization:", err)
			w.WriteHeader(http.StatusBadRequest)
			return
		}

		w.Header().Set("Content-Type", "application/json")
		w.Write(res)
		log.Println(r.Method, r.URL, http.StatusOK)

	})
}

// createStackHandler handles the creation of a stack, given a database
// by its id. Returns the status of the new stack.
func (c *Conn) createStackHandler(w http.ResponseWriter, r *http.Request, databaseID string) {
	name := r.FormValue("name")
	if name == "" {
		log.Println(r.Method, r.URL, http.StatusBadRequest, "missing name")
		w.WriteHeader(http.StatusBadRequest)
		return
	}

	db, ok := c.Pila.Database(uuid.UUID(databaseID))
	if !ok {
		c.goneHandler(w, r, fmt.Sprintf("database %s is Gone", databaseID))
		return
	}

	stack := pila.NewStack(name)
	err := db.AddStack(stack)
	if err != nil {
		log.Println(r.Method, r.URL, http.StatusConflict, err)
		w.WriteHeader(http.StatusConflict)
		return
	}

	// Do not check error as the Status of a new stack does
	// not contain types that could cause such case.
	// See http://golang.org/src/encoding/json/encode.go?s=5438:5481#L125
	res, _ := stack.Status().ToJSON()

	w.Header().Set("Content-Type", "application/json")
	w.WriteHeader(http.StatusCreated)
	w.Write(res)
	log.Println(r.Method, r.URL, http.StatusCreated)
}

// stackHandler handles operations on a single stack of a database. It holds
// the PUSH, POP and PEEK methods, and the stack deletion.
func (c *Conn) stackHandler(params *map[string]string) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		vars := mux.Vars(r)
		// we override the mux vars to be able to test
		// an arbitrary database and stack ID
		if params != nil {
			vars = *params
		}

		db, ok := ResourceDatabase(c, vars["database_id"])
		if !ok {
			c.goneHandler(w, r, fmt.Sprintf("database %s is Gone", vars["database_id"]))
			return
		}

		stack, ok := ResourceStack(db, vars["stack_id"])
		if !ok {
			c.goneHandler(w, r, fmt.Sprintf("stack %s is Gone", vars["stack_id"]))
			return
		}

		if r.Method == "POST" {
			c.pushStackHandler(w, r, stack)
			return
		}

		if r.Method == "DELETE" {
			_ = r.ParseForm()
			if _, ok := r.Form["flush"]; ok {
				c.flushStackHandler(w, r, stack)
				return
			}
			if _, ok := r.Form["full"]; ok {
				c.deleteStackHandler(w, r, db, stack)
				return
			}
			c.popStackHandler(w, r, stack)
			return
		}
	})
}

// pushStackHandler adds an element into a Stack and returns 200 and the element.
func (c *Conn) pushStackHandler(w http.ResponseWriter, r *http.Request, stack *pila.Stack) {
	if r.Body == nil {
		log.Println(r.Method, r.URL, http.StatusBadRequest,
			"no element provided")
		w.WriteHeader(http.StatusBadRequest)
		return
	}

	var element pila.Element
	err := element.Decode(r.Body)
	if err != nil {
		log.Println(r.Method, r.URL, http.StatusBadRequest,
			"error on decoding element:", err)
		w.WriteHeader(http.StatusBadRequest)
		return
	}

	stack.Push(element.Value)

	log.Println(r.Method, r.URL, http.StatusOK, element.Value)
	w.Header().Set("Content-Type", "application/json")

	// Do not check error as we consider our element
	// suitable for a JSON encoding.
	b, _ := element.ToJSON()
	w.Write(b)
}

// popStackHandler extracts the peek element of a Stack, returns 200 and returns it.
func (c *Conn) popStackHandler(w http.ResponseWriter, r *http.Request, stack *pila.Stack) {
	value, ok := stack.Pop()
	if !ok {
		log.Println(r.Method, r.URL, http.StatusNoContent)
		w.WriteHeader(http.StatusNoContent)
		return
	}

	element := pila.Element{Value: value}

	log.Println(r.Method, r.URL, http.StatusOK, element.Value)
	w.Header().Set("Content-Type", "application/json")

	// Do not check error as we consider our element
	// suitable for a JSON encoding.
	b, _ := element.ToJSON()
	w.Write(b)
}

// flushStackHandler flushes the Stack, setting the size to 0 and emptying all
// the content.
func (c *Conn) flushStackHandler(w http.ResponseWriter, r *http.Request, stack *pila.Stack) {
	stack.Flush()

	log.Println(r.Method, r.URL, http.StatusOK)
	w.Header().Set("Content-Type", "application/json")

	// Do not check error as we consider that a flushed
	// stack has no JSON encoding issues.
	b, _ := stack.Status().ToJSON()
	w.Write(b)
}

// deleteStackHandler deletes the Stack from a database.
func (c *Conn) deleteStackHandler(w http.ResponseWriter, r *http.Request,
	database *pila.Database, stack *pila.Stack) {
	stack.Flush()

	// do not check output as we validated that
	// stack always exists
	_ = database.RemoveStack(stack.ID)

	log.Println(r.Method, r.URL, http.StatusNoContent)
	w.WriteHeader(http.StatusNoContent)
	return
}

// notFoundHandler logs and returns a 404 NotFound response.
func (c *Conn) notFoundHandler(w http.ResponseWriter, r *http.Request) {
	log.Println(r.Method, r.URL, http.StatusNotFound)
	http.NotFound(w, r)
}

// goneHandler logs and returns a 410 Gone response with information
// about the missing resource.
func (c *Conn) goneHandler(w http.ResponseWriter, r *http.Request, message string) {
	log.Println(r.Method, r.URL,
		http.StatusGone, message)
	w.WriteHeader(http.StatusGone)
}
<commit_msg>pilad: fmt for PR<commit_after>package main

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

	"github.com/fern4lvarez/piladb/pila"
	"github.com/fern4lvarez/piladb/pkg/uuid"
	"github.com/fern4lvarez/piladb/pkg/version"

	"github.com/gorilla/mux"
)

// Conn represents the current piladb connection, containing
// the Pila instance and its status.
type Conn struct {
	Pila   *pila.Pila
	Status *Status
}

// NewConn creates and returns a new piladb connection.
func NewConn() *Conn {
	conn := &Conn{}
	conn.Pila = pila.NewPila()
	conn.Status = NewStatus(version.CommitHash(), time.Now(), MemStats())
	return conn
}

// Connection Handlers

// statusHandler writes the piladb status into the response.
func (c *Conn) statusHandler(w http.ResponseWriter, r *http.Request) {
	c.Status.Update(time.Now(), MemStats())

	w.Header().Set("Content-Type", "application/json")
	log.Println(r.Method, r.URL, http.StatusOK)
	w.Write(c.Status.ToJSON())
}

// databasesHandler returns the information of the running databases.
func (c *Conn) databasesHandler(w http.ResponseWriter, r *http.Request) {
	if r.Method == "PUT" {
		c.createDatabaseHandler(w, r)
		return
	}

	w.Header().Set("Content-Type", "application/json")
	log.Println(r.Method, r.URL, http.StatusOK)
	w.Write(c.Pila.Status().ToJSON())
}

// createDatabaseHandler creates a Database and returns 201 and the ID and name
// of the Database.
func (c *Conn) createDatabaseHandler(w http.ResponseWriter, r *http.Request) {
	name := r.FormValue("name")
	if name == "" {
		log.Println(r.Method, r.URL, http.StatusBadRequest, "missing name")
		w.WriteHeader(http.StatusBadRequest)
		return
	}

	db := pila.NewDatabase(name)
	err := c.Pila.AddDatabase(db)
	if err != nil {
		log.Println(r.Method, r.URL, http.StatusConflict, err)
		w.WriteHeader(http.StatusConflict)
		return
	}

	w.Header().Set("Content-Type", "application/json")
	log.Println(r.Method, r.URL, http.StatusCreated)
	w.WriteHeader(http.StatusCreated)
	w.Write(db.Status().ToJSON())
}

// databaseHandler returns the information of a single database given its ID
// or name.
func (c *Conn) databaseHandler(databaseID string) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		vars := mux.Vars(r)

		// we override the mux vars to be able to test
		// an arbitrary database ID
		if databaseID != "" {
			vars = map[string]string{
				"id": databaseID,
			}
		}

		db, ok := ResourceDatabase(c, vars["id"])
		if !ok {
			c.goneHandler(w, r, fmt.Sprintf("database %s is Gone", vars["id"]))
			return
		}

		if r.Method == "DELETE" {
			_ = c.Pila.RemoveDatabase(db.ID)
			log.Println(r.Method, r.URL, http.StatusNoContent)
			w.WriteHeader(http.StatusNoContent)
			return
		}

		w.Header().Set("Content-Type", "application/json")
		log.Println(r.Method, r.URL, http.StatusOK)
		w.Write(db.Status().ToJSON())
	})
}

// stacksHandler handles the stacks of a database, being able to get the status
// of them, or create a new one.
func (c *Conn) stacksHandler(databaseID string) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		vars := mux.Vars(r)

		// we override the mux vars to be able to test
		// an arbitrary database ID
		if databaseID != "" {
			vars = map[string]string{
				"database_id": databaseID,
			}
		}

		db, ok := ResourceDatabase(c, vars["database_id"])
		if !ok {
			c.goneHandler(w, r, fmt.Sprintf("database %s is Gone", vars["database_id"]))
			return
		}

		if r.Method == "PUT" {
			c.createStackHandler(w, r, db.ID.String())
			return
		}

		res, err := db.StacksStatus().ToJSON()
		if err != nil {
			log.Println(r.Method, r.URL, http.StatusBadRequest,
				"error on response serialization:", err)
			w.WriteHeader(http.StatusBadRequest)
			return
		}

		w.Header().Set("Content-Type", "application/json")
		w.Write(res)
		log.Println(r.Method, r.URL, http.StatusOK)

	})
}

// createStackHandler handles the creation of a stack, given a database
// by its id. Returns the status of the new stack.
func (c *Conn) createStackHandler(w http.ResponseWriter, r *http.Request, databaseID string) {
	name := r.FormValue("name")
	if name == "" {
		log.Println(r.Method, r.URL, http.StatusBadRequest, "missing name")
		w.WriteHeader(http.StatusBadRequest)
		return
	}

	db, ok := c.Pila.Database(uuid.UUID(databaseID))
	if !ok {
		c.goneHandler(w, r, fmt.Sprintf("database %s is Gone", databaseID))
		return
	}

	stack := pila.NewStack(name)
	err := db.AddStack(stack)
	if err != nil {
		log.Println(r.Method, r.URL, http.StatusConflict, err)
		w.WriteHeader(http.StatusConflict)
		return
	}

	// Do not check error as the Status of a new stack does
	// not contain types that could cause such case.
	// See http://golang.org/src/encoding/json/encode.go?s=5438:5481#L125
	res, _ := stack.Status().ToJSON()

	w.Header().Set("Content-Type", "application/json")
	w.WriteHeader(http.StatusCreated)
	w.Write(res)
	log.Println(r.Method, r.URL, http.StatusCreated)
}

// stackHandler handles operations on a single stack of a database. It holds
// the PUSH, POP and PEEK methods, and the stack deletion.
func (c *Conn) stackHandler(params *map[string]string) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		vars := mux.Vars(r)
		// we override the mux vars to be able to test
		// an arbitrary database and stack ID
		if params != nil {
			vars = *params
		}

		db, ok := ResourceDatabase(c, vars["database_id"])
		if !ok {
			c.goneHandler(w, r, fmt.Sprintf("database %s is Gone", vars["database_id"]))
			return
		}

		stack, ok := ResourceStack(db, vars["stack_id"])
		if !ok {
			c.goneHandler(w, r, fmt.Sprintf("stack %s is Gone", vars["stack_id"]))
			return
		}

		if r.Method == "POST" {
			c.pushStackHandler(w, r, stack)
			return
		}

		if r.Method == "DELETE" {
			_ = r.ParseForm()
			if _, ok := r.Form["flush"]; ok {
				c.flushStackHandler(w, r, stack)
				return
			}
			if _, ok := r.Form["full"]; ok {
				c.deleteStackHandler(w, r, db, stack)
				return
			}
			c.popStackHandler(w, r, stack)
			return
		}
	})
}

// pushStackHandler adds an element into a Stack and returns 200 and the element.
func (c *Conn) pushStackHandler(w http.ResponseWriter, r *http.Request, stack *pila.Stack) {
	if r.Body == nil {
		log.Println(r.Method, r.URL, http.StatusBadRequest,
			"no element provided")
		w.WriteHeader(http.StatusBadRequest)
		return
	}

	var element pila.Element
	err := element.Decode(r.Body)
	if err != nil {
		log.Println(r.Method, r.URL, http.StatusBadRequest,
			"error on decoding element:", err)
		w.WriteHeader(http.StatusBadRequest)
		return
	}

	stack.Push(element.Value)

	log.Println(r.Method, r.URL, http.StatusOK, element.Value)
	w.Header().Set("Content-Type", "application/json")

	// Do not check error as we consider our element
	// suitable for a JSON encoding.
	b, _ := element.ToJSON()
	w.Write(b)
}

// popStackHandler extracts the peek element of a Stack, returns 200 and returns it.
func (c *Conn) popStackHandler(w http.ResponseWriter, r *http.Request, stack *pila.Stack) {
	value, ok := stack.Pop()
	if !ok {
		log.Println(r.Method, r.URL, http.StatusNoContent)
		w.WriteHeader(http.StatusNoContent)
		return
	}

	element := pila.Element{Value: value}

	log.Println(r.Method, r.URL, http.StatusOK, element.Value)
	w.Header().Set("Content-Type", "application/json")

	// Do not check error as we consider our element
	// suitable for a JSON encoding.
	b, _ := element.ToJSON()
	w.Write(b)
}

// flushStackHandler flushes the Stack, setting the size to 0 and emptying all
// the content.
func (c *Conn) flushStackHandler(w http.ResponseWriter, r *http.Request, stack *pila.Stack) {
	stack.Flush()

	log.Println(r.Method, r.URL, http.StatusOK)
	w.Header().Set("Content-Type", "application/json")

	// Do not check error as we consider that a flushed
	// stack has no JSON encoding issues.
	b, _ := stack.Status().ToJSON()
	w.Write(b)
}

// deleteStackHandler deletes the Stack from a database.
func (c *Conn) deleteStackHandler(w http.ResponseWriter, r *http.Request, database *pila.Database, stack *pila.Stack) {
	stack.Flush()

	// do not check output as we validated that
	// stack always exists
	_ = database.RemoveStack(stack.ID)

	log.Println(r.Method, r.URL, http.StatusNoContent)
	w.WriteHeader(http.StatusNoContent)
	return
}

// notFoundHandler logs and returns a 404 NotFound response.
func (c *Conn) notFoundHandler(w http.ResponseWriter, r *http.Request) {
	log.Println(r.Method, r.URL, http.StatusNotFound)
	http.NotFound(w, r)
}

// goneHandler logs and returns a 410 Gone response with information
// about the missing resource.
func (c *Conn) goneHandler(w http.ResponseWriter, r *http.Request, message string) {
	log.Println(r.Method, r.URL,
		http.StatusGone, message)
	w.WriteHeader(http.StatusGone)
}
<|endoftext|>


<commit_before>/*
guest-set_time - set guest time

Example:
        { "execute": "guest-set-time", "arguments": {
            "time": int // optional, time to set
          }
        }
*/
package guest_set_time

import (
	"encoding/json"
	"os/exec"

	"github.com/vtolstov/qemu-ga/qga"

	"golang.org/x/sys/unix"
)

func init() {
	qga.RegisterCommand(&qga.Command{
		Name:    "guest-set-time",
		Func:    fnGuestSetTime,
		Enabled: true,
	})
}

func fnGuestSetTime(req *qga.Request) *qga.Response {
	res := &qga.Response{Id: req.Id}

	reqData := reqDataSetTime{}

	err := json.Unmarshal(req.RawArgs, &reqData)
	if err != nil {
		res.Error = &qga.Error{Code: -1, Desc: err.Error()}
		return res
	}

	args := []string{}
	if reqData.Time != 0 {
		tv := &unix.Timeval{Sec: reqData.Time / 1000000000, Usec: reqData.Time % 1000000000 / 1000}
		if err = unix.Settimeofday(tv); err != nil {
			res.Error = &qga.Error{Code: -1, Desc: err.Error()}
			return res
		}
		args = append(args, "-w")
	} else {
		args = append(args, "-s")
	}

	err = exec.Command("hwclock", args...).Run()
	if err != nil {
		res.Error = &qga.Error{Code: -1, Desc: err.Error()}
		return res
	}

	return res
}
<commit_msg>fix<commit_after>/*
guest-set-time - set guest time

Example:
        { "execute": "guest-set-time", "arguments": {
            "time": int // optional, time to set
          }
        }
*/
package guest_set_time

import (
	"encoding/json"
	"os/exec"

	"github.com/vtolstov/qemu-ga/qga"

	"golang.org/x/sys/unix"
)

func init() {
	qga.RegisterCommand(&qga.Command{
		Name:    "guest-set-time",
		Func:    fnGuestSetTime,
		Enabled: true,
	})
}

func fnGuestSetTime(req *qga.Request) *qga.Response {
	res := &qga.Response{Id: req.Id}

	reqData := reqDataSetTime{}

	err := json.Unmarshal(req.RawArgs, &reqData)
	if err != nil {
		res.Error = &qga.Error{Code: -1, Desc: err.Error()}
		return res
	}

	args := []string{}
	if reqData.Time != 0 {
		tv := &unix.Timeval{Sec: reqData.Time / 1000000000, Usec: reqData.Time % 1000000000 / 1000}
		if err = unix.Settimeofday(tv); err != nil {
			res.Error = &qga.Error{Code: -1, Desc: err.Error()}
			return res
		}
		args = append(args, "-w")
	} else {
		args = append(args, "-s")
	}

	err = exec.Command("hwclock", args...).Run()
	if err != nil {
		res.Error = &qga.Error{Code: -1, Desc: err.Error()}
		return res
	}

	return res
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"math/rand"
	"time"
)

// Consumer struct
type Consumer struct {
	inputChan chan int
	jobsChan  chan int
}

func getRandomTime() int {
	rand.Seed(time.Now().UnixNano())
	return rand.Intn(5)
}

func (c *Consumer) queue(input int) {
	c.jobsChan <- input
	fmt.Println("already send input value:", input)
}

func (c *Consumer) worker(num int) {
	for job := range c.jobsChan {
		n := getRandomTime()
		fmt.Printf("Sleeping %d seconds...\n", n)
		time.Sleep(time.Duration(n) * time.Second)
		fmt.Println("worker:", num, " job value:", job)
	}
}

const poolSize = 1

func main() {
	// create the consumer
	consumer := Consumer{
		inputChan: make(chan int, 1),
		jobsChan:  make(chan int, poolSize),
	}

	for i := 0; i < poolSize; i++ {
		go consumer.worker(i)
	}

	consumer.queue(1)
	consumer.queue(2)
	consumer.queue(3)
	consumer.queue(4)

	time.Sleep(5 * time.Second)
}
<commit_msg>chore: update sleep time<commit_after>package main

import (
	"fmt"
	"math/rand"
	"time"
)

// Consumer struct
type Consumer struct {
	inputChan chan int
	jobsChan  chan int
}

func getRandomTime() int {
	rand.Seed(time.Now().UnixNano())
	return rand.Intn(5)
}

func (c *Consumer) queue(input int) {
	c.jobsChan <- input
	fmt.Println("already send input value:", input)
}

func (c *Consumer) worker(num int) {
	for job := range c.jobsChan {
		n := getRandomTime()
		fmt.Printf("Sleeping %d seconds...\n", n)
		time.Sleep(time.Duration(n) * time.Second)
		fmt.Println("worker:", num, " job value:", job)
	}
}

const poolSize = 2

func main() {
	// create the consumer
	consumer := Consumer{
		inputChan: make(chan int, 1),
		jobsChan:  make(chan int, poolSize),
	}

	for i := 0; i < poolSize; i++ {
		go consumer.worker(i)
	}

	consumer.queue(1)
	consumer.queue(2)
	consumer.queue(3)
	consumer.queue(4)
	consumer.queue(5)

	time.Sleep(5 * time.Second)
}
<|endoftext|>


<commit_before>package edison

import (
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"strconv"

	"github.com/hybridgroup/gobot"
	"github.com/hybridgroup/gobot/sysfs"
)

var i2cLocation = "/dev/i2c-6"

// writeFile validates file existence and writes data into it
var writeFile = func(name, data string) error {
	if _, err := os.Stat(name); err == nil {
		err := ioutil.WriteFile(
			name,
			[]byte(data),
			0644,
		)
		if err != nil {
			return err
		}
	} else {
		return errors.New("File doesn't exist: " + name)
	}
	return nil
}
var readFile = func(path string) ([]byte, error) {
	return ioutil.ReadFile(path)
}

type mux struct {
	pin   int
	value int
}
type sysfsPin struct {
	pin          int
	resistor     int
	levelShifter int
	pwmPin       int
	mux          []mux
}

type EdisonAdaptor struct {
	gobot.Adaptor
	tristate    sysfs.DigitalPin
	digitalPins map[int]sysfs.DigitalPin
	pwmPins     map[int]*pwmPin
	i2cDevice   io.ReadWriteCloser
	connect     func(e *EdisonAdaptor)
}

var sysfsPinMap = map[string]sysfsPin{
	"0": sysfsPin{
		pin:          130,
		resistor:     216,
		levelShifter: 248,
		pwmPin:       -1,
		mux:          []mux{},
	},
	"1": sysfsPin{
		pin:          131,
		resistor:     217,
		levelShifter: 249,
		pwmPin:       -1,
		mux:          []mux{},
	},
	"2": sysfsPin{
		pin:          128,
		resistor:     218,
		levelShifter: 250,
		pwmPin:       -1,
		mux:          []mux{},
	},
	"3": sysfsPin{
		pin:          12,
		resistor:     219,
		levelShifter: 251,
		pwmPin:       0,
		mux:          []mux{},
	},

	"4": sysfsPin{
		pin:          129,
		resistor:     220,
		levelShifter: 252,
		pwmPin:       -1,
		mux:          []mux{},
	},
	"5": sysfsPin{
		pin:          13,
		resistor:     221,
		levelShifter: 253,
		pwmPin:       1,
		mux:          []mux{},
	},
	"6": sysfsPin{
		pin:          182,
		resistor:     222,
		levelShifter: 254,
		pwmPin:       2,
		mux:          []mux{},
	},
	"7": sysfsPin{
		pin:          48,
		resistor:     223,
		levelShifter: 255,
		pwmPin:       -1,
		mux:          []mux{},
	},
	"8": sysfsPin{
		pin:          49,
		resistor:     224,
		levelShifter: 256,
		pwmPin:       -1,
		mux:          []mux{},
	},
	"9": sysfsPin{
		pin:          183,
		resistor:     225,
		levelShifter: 257,
		pwmPin:       3,
		mux:          []mux{},
	},
	"10": sysfsPin{
		pin:          41,
		resistor:     226,
		levelShifter: 258,
		pwmPin:       4,
		mux: []mux{
			mux{263, sysfs.HIGH},
			mux{240, sysfs.LOW},
		},
	},
	"11": sysfsPin{
		pin:          43,
		resistor:     227,
		levelShifter: 259,
		pwmPin:       5,
		mux: []mux{
			mux{262, sysfs.HIGH},
			mux{241, sysfs.LOW},
		},
	},
	"12": sysfsPin{
		pin:          42,
		resistor:     228,
		levelShifter: 260,
		pwmPin:       -1,
		mux: []mux{
			mux{242, sysfs.LOW},
		},
	},
	"13": sysfsPin{
		pin:          40,
		resistor:     229,
		levelShifter: 261,
		pwmPin:       -1,
		mux: []mux{
			mux{243, sysfs.LOW},
		},
	},
}

// changePinMode writes pin mode to current_pinmux file
func changePinMode(pin, mode string) {
	err := writeFile(
		"/sys/kernel/debug/gpio_debug/gpio"+pin+"/current_pinmux",
		"mode"+mode,
	)
	if err != nil {
		panic(err)
	}
}

// NewEditionAdaptor creates a EdisonAdaptor with specified name and
// creates connect function
func NewEdisonAdaptor(name string) *EdisonAdaptor {
	return &EdisonAdaptor{
		Adaptor: *gobot.NewAdaptor(
			name,
			"EdisonAdaptor",
		),
		connect: func(e *EdisonAdaptor) {
			e.tristate = sysfs.NewDigitalPin(214)
			e.tristate.Export()
			e.tristate.Direction(sysfs.OUT)
			e.tristate.Write(sysfs.LOW)

			for _, i := range []int{263, 262} {
				io := sysfs.NewDigitalPin(i)
				io.Export()
				io.Direction(sysfs.OUT)
				io.Write(sysfs.HIGH)
				io.Unexport()
			}

			for _, i := range []int{240, 241, 242, 243} {
				io := sysfs.NewDigitalPin(i)
				io.Export()
				io.Direction(sysfs.OUT)
				io.Write(sysfs.LOW)
				io.Unexport()
			}

			for _, i := range []string{"111", "115", "114", "109"} {
				changePinMode(i, "1")
			}

			for _, i := range []string{"131", "129", "40"} {
				changePinMode(i, "0")
			}

			e.tristate.Write(sysfs.HIGH)
		},
	}
}

// Connect starts conection with board and creates
// digitalPins and pwmPins adaptor maps
func (e *EdisonAdaptor) Connect() bool {
	e.digitalPins = make(map[int]sysfs.DigitalPin)
	e.pwmPins = make(map[int]*pwmPin)
	e.connect(e)
	return true
}

// Finalize closes connection to board and pins
func (e *EdisonAdaptor) Finalize() bool {
	e.tristate.Unexport()
	for _, pin := range e.digitalPins {
		if pin != nil {
			pin.Unexport()
		}
	}
	for _, pin := range e.pwmPins {
		if pin != nil {
			pin.close()
		}
	}
	if e.i2cDevice != nil {
		e.i2cDevice.Close()
	}
	return true
}

// digitalPin returns matched digitalPin for specified values
func (e *EdisonAdaptor) digitalPin(pin string, dir string) sysfs.DigitalPin {
	i := sysfsPinMap[pin]
	if e.digitalPins[i.pin] == nil {
		e.digitalPins[i.pin] = sysfs.NewDigitalPin(i.pin)
		e.digitalPins[i.pin].Export()
		e.digitalPins[i.resistor] = sysfs.NewDigitalPin(i.resistor)
		e.digitalPins[i.resistor].Export()
		e.digitalPins[i.levelShifter] = sysfs.NewDigitalPin(i.levelShifter)
		e.digitalPins[i.levelShifter].Export()
		if len(i.mux) > 0 {
			for _, mux := range i.mux {
				e.digitalPins[mux.pin] = sysfs.NewDigitalPin(mux.pin)
				e.digitalPins[mux.pin].Export()
				e.digitalPins[mux.pin].Direction(sysfs.OUT)
				e.digitalPins[mux.pin].Write(mux.value)
			}
		}
	}

	if dir == "in" {
		e.digitalPins[i.pin].Direction(sysfs.IN)
		e.digitalPins[i.resistor].Direction(sysfs.OUT)
		e.digitalPins[i.resistor].Write(sysfs.LOW)
		e.digitalPins[i.levelShifter].Direction(sysfs.OUT)
		e.digitalPins[i.levelShifter].Write(sysfs.LOW)
	} else if dir == "out" {
		e.digitalPins[i.pin].Direction(sysfs.OUT)
		e.digitalPins[i.resistor].Direction(sysfs.IN)
		e.digitalPins[i.levelShifter].Direction(sysfs.OUT)
		e.digitalPins[i.levelShifter].Write(sysfs.HIGH)
	}
	return e.digitalPins[i.pin]
}

// DigitalRead reads digital value from pin
func (e *EdisonAdaptor) DigitalRead(pin string) (i int) {
	i, _ = e.digitalPin(pin, "in").Read()
	return
}

// DigitalWrite writes digital value to specified pin
func (e *EdisonAdaptor) DigitalWrite(pin string, val byte) {
	e.digitalPin(pin, "out").Write(int(val))
}

// PwmWrite writes scaled pwm value to specified pin
func (e *EdisonAdaptor) PwmWrite(pin string, val byte) {
	sysPin := sysfsPinMap[pin]
	if sysPin.pwmPin != -1 {
		if e.pwmPins[sysPin.pwmPin] == nil {
			e.DigitalWrite(pin, 1)
			changePinMode(strconv.Itoa(int(sysPin.pin)), "1")
			e.pwmPins[sysPin.pwmPin] = newPwmPin(sysPin.pwmPin)
		}
		period, err := strconv.Atoi(e.pwmPins[sysPin.pwmPin].period())
		if err != nil {
			panic(err)
		}
		duty := gobot.FromScale(float64(val), 0, 255.0)
		e.pwmPins[sysPin.pwmPin].writeDuty(strconv.Itoa(int(float64(period) * duty)))
	} else {
		fmt.Println("Not a PWM pin")
	}
}

// AnalogRead returns value from analog reading of specified pin
func (e *EdisonAdaptor) AnalogRead(pin string) int {
	buf, err := readFile(
		"/sys/bus/iio/devices/iio:device1/in_voltage" + pin + "_raw",
	)
	if err != nil {
		panic(err)
	}
	val, err := strconv.Atoi(string(buf[0 : len(buf)-1]))
	if err != nil {
		panic(err)
	}
	return val
}

// I2cStart initializes i2c device for addresss
func (e *EdisonAdaptor) I2cStart(address byte) {
	e.tristate.Write(sysfs.LOW)

	for _, i := range []int{14, 165, 212, 213} {
		io := sysfs.NewDigitalPin(i)
		io.Export()
		io.Direction(sysfs.IN)
		io.Unexport()
	}

	for _, i := range []int{236, 237, 204, 205} {
		io := sysfs.NewDigitalPin(i)
		io.Export()
		io.Direction(sysfs.OUT)
		io.Write(sysfs.LOW)
		io.Unexport()
	}

	for _, i := range []string{"28", "27"} {
		changePinMode(i, "1")
	}

	e.tristate.Write(sysfs.HIGH)

	e.i2cDevice, _ = sysfs.NewI2cDevice(i2cLocation, address)
}

// I2cWrite writes data to i2cDevice
func (e *EdisonAdaptor) I2cWrite(data []byte) {
	e.i2cDevice.Write(data)
}

// I2cRead reads data from i2cDevice
func (e *EdisonAdaptor) I2cRead(size uint) []byte {
	b := make([]byte, size)
	e.i2cDevice.Read(b)
	return b
}
<commit_msg>Satisfy DirectPin interface<commit_after>package edison

import (
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"strconv"

	"github.com/hybridgroup/gobot"
	"github.com/hybridgroup/gobot/sysfs"
)

var i2cLocation = "/dev/i2c-6"

// writeFile validates file existence and writes data into it
var writeFile = func(name, data string) error {
	if _, err := os.Stat(name); err == nil {
		err := ioutil.WriteFile(
			name,
			[]byte(data),
			0644,
		)
		if err != nil {
			return err
		}
	} else {
		return errors.New("File doesn't exist: " + name)
	}
	return nil
}
var readFile = func(path string) ([]byte, error) {
	return ioutil.ReadFile(path)
}

type mux struct {
	pin   int
	value int
}
type sysfsPin struct {
	pin          int
	resistor     int
	levelShifter int
	pwmPin       int
	mux          []mux
}

type EdisonAdaptor struct {
	gobot.Adaptor
	tristate    sysfs.DigitalPin
	digitalPins map[int]sysfs.DigitalPin
	pwmPins     map[int]*pwmPin
	i2cDevice   io.ReadWriteCloser
	connect     func(e *EdisonAdaptor)
}

var sysfsPinMap = map[string]sysfsPin{
	"0": sysfsPin{
		pin:          130,
		resistor:     216,
		levelShifter: 248,
		pwmPin:       -1,
		mux:          []mux{},
	},
	"1": sysfsPin{
		pin:          131,
		resistor:     217,
		levelShifter: 249,
		pwmPin:       -1,
		mux:          []mux{},
	},
	"2": sysfsPin{
		pin:          128,
		resistor:     218,
		levelShifter: 250,
		pwmPin:       -1,
		mux:          []mux{},
	},
	"3": sysfsPin{
		pin:          12,
		resistor:     219,
		levelShifter: 251,
		pwmPin:       0,
		mux:          []mux{},
	},

	"4": sysfsPin{
		pin:          129,
		resistor:     220,
		levelShifter: 252,
		pwmPin:       -1,
		mux:          []mux{},
	},
	"5": sysfsPin{
		pin:          13,
		resistor:     221,
		levelShifter: 253,
		pwmPin:       1,
		mux:          []mux{},
	},
	"6": sysfsPin{
		pin:          182,
		resistor:     222,
		levelShifter: 254,
		pwmPin:       2,
		mux:          []mux{},
	},
	"7": sysfsPin{
		pin:          48,
		resistor:     223,
		levelShifter: 255,
		pwmPin:       -1,
		mux:          []mux{},
	},
	"8": sysfsPin{
		pin:          49,
		resistor:     224,
		levelShifter: 256,
		pwmPin:       -1,
		mux:          []mux{},
	},
	"9": sysfsPin{
		pin:          183,
		resistor:     225,
		levelShifter: 257,
		pwmPin:       3,
		mux:          []mux{},
	},
	"10": sysfsPin{
		pin:          41,
		resistor:     226,
		levelShifter: 258,
		pwmPin:       4,
		mux: []mux{
			mux{263, sysfs.HIGH},
			mux{240, sysfs.LOW},
		},
	},
	"11": sysfsPin{
		pin:          43,
		resistor:     227,
		levelShifter: 259,
		pwmPin:       5,
		mux: []mux{
			mux{262, sysfs.HIGH},
			mux{241, sysfs.LOW},
		},
	},
	"12": sysfsPin{
		pin:          42,
		resistor:     228,
		levelShifter: 260,
		pwmPin:       -1,
		mux: []mux{
			mux{242, sysfs.LOW},
		},
	},
	"13": sysfsPin{
		pin:          40,
		resistor:     229,
		levelShifter: 261,
		pwmPin:       -1,
		mux: []mux{
			mux{243, sysfs.LOW},
		},
	},
}

// changePinMode writes pin mode to current_pinmux file
func changePinMode(pin, mode string) {
	err := writeFile(
		"/sys/kernel/debug/gpio_debug/gpio"+pin+"/current_pinmux",
		"mode"+mode,
	)
	if err != nil {
		panic(err)
	}
}

// NewEditionAdaptor creates a EdisonAdaptor with specified name and
// creates connect function
func NewEdisonAdaptor(name string) *EdisonAdaptor {
	return &EdisonAdaptor{
		Adaptor: *gobot.NewAdaptor(
			name,
			"EdisonAdaptor",
		),
		connect: func(e *EdisonAdaptor) {
			e.tristate = sysfs.NewDigitalPin(214)
			e.tristate.Export()
			e.tristate.Direction(sysfs.OUT)
			e.tristate.Write(sysfs.LOW)

			for _, i := range []int{263, 262} {
				io := sysfs.NewDigitalPin(i)
				io.Export()
				io.Direction(sysfs.OUT)
				io.Write(sysfs.HIGH)
				io.Unexport()
			}

			for _, i := range []int{240, 241, 242, 243} {
				io := sysfs.NewDigitalPin(i)
				io.Export()
				io.Direction(sysfs.OUT)
				io.Write(sysfs.LOW)
				io.Unexport()
			}

			for _, i := range []string{"111", "115", "114", "109"} {
				changePinMode(i, "1")
			}

			for _, i := range []string{"131", "129", "40"} {
				changePinMode(i, "0")
			}

			e.tristate.Write(sysfs.HIGH)
		},
	}
}

// Connect starts conection with board and creates
// digitalPins and pwmPins adaptor maps
func (e *EdisonAdaptor) Connect() bool {
	e.digitalPins = make(map[int]sysfs.DigitalPin)
	e.pwmPins = make(map[int]*pwmPin)
	e.connect(e)
	return true
}

// Finalize closes connection to board and pins
func (e *EdisonAdaptor) Finalize() bool {
	e.tristate.Unexport()
	for _, pin := range e.digitalPins {
		if pin != nil {
			pin.Unexport()
		}
	}
	for _, pin := range e.pwmPins {
		if pin != nil {
			pin.close()
		}
	}
	if e.i2cDevice != nil {
		e.i2cDevice.Close()
	}
	return true
}

// digitalPin returns matched digitalPin for specified values
func (e *EdisonAdaptor) digitalPin(pin string, dir string) sysfs.DigitalPin {
	i := sysfsPinMap[pin]
	if e.digitalPins[i.pin] == nil {
		e.digitalPins[i.pin] = sysfs.NewDigitalPin(i.pin)
		e.digitalPins[i.pin].Export()
		e.digitalPins[i.resistor] = sysfs.NewDigitalPin(i.resistor)
		e.digitalPins[i.resistor].Export()
		e.digitalPins[i.levelShifter] = sysfs.NewDigitalPin(i.levelShifter)
		e.digitalPins[i.levelShifter].Export()
		if len(i.mux) > 0 {
			for _, mux := range i.mux {
				e.digitalPins[mux.pin] = sysfs.NewDigitalPin(mux.pin)
				e.digitalPins[mux.pin].Export()
				e.digitalPins[mux.pin].Direction(sysfs.OUT)
				e.digitalPins[mux.pin].Write(mux.value)
			}
		}
	}

	if dir == "in" {
		e.digitalPins[i.pin].Direction(sysfs.IN)
		e.digitalPins[i.resistor].Direction(sysfs.OUT)
		e.digitalPins[i.resistor].Write(sysfs.LOW)
		e.digitalPins[i.levelShifter].Direction(sysfs.OUT)
		e.digitalPins[i.levelShifter].Write(sysfs.LOW)
	} else if dir == "out" {
		e.digitalPins[i.pin].Direction(sysfs.OUT)
		e.digitalPins[i.resistor].Direction(sysfs.IN)
		e.digitalPins[i.levelShifter].Direction(sysfs.OUT)
		e.digitalPins[i.levelShifter].Write(sysfs.HIGH)
	}
	return e.digitalPins[i.pin]
}

// DigitalRead reads digital value from pin
func (e *EdisonAdaptor) DigitalRead(pin string) (i int) {
	i, _ = e.digitalPin(pin, "in").Read()
	return
}

// DigitalWrite writes digital value to specified pin
func (e *EdisonAdaptor) DigitalWrite(pin string, val byte) {
	e.digitalPin(pin, "out").Write(int(val))
}

// PwmWrite writes scaled pwm value to specified pin
func (e *EdisonAdaptor) PwmWrite(pin string, val byte) {
	sysPin := sysfsPinMap[pin]
	if sysPin.pwmPin != -1 {
		if e.pwmPins[sysPin.pwmPin] == nil {
			e.DigitalWrite(pin, 1)
			changePinMode(strconv.Itoa(int(sysPin.pin)), "1")
			e.pwmPins[sysPin.pwmPin] = newPwmPin(sysPin.pwmPin)
		}
		period, err := strconv.Atoi(e.pwmPins[sysPin.pwmPin].period())
		if err != nil {
			panic(err)
		}
		duty := gobot.FromScale(float64(val), 0, 255.0)
		e.pwmPins[sysPin.pwmPin].writeDuty(strconv.Itoa(int(float64(period) * duty)))
	} else {
		fmt.Println("Not a PWM pin")
	}
}

// AnalogWrite Not Implemented
func (e *EdisonAdaptor) AnalogWrite(string, byte) {}

// InitServo Not Implemented
func (e *EdisonAdaptor) InitServo() {}

// ServoWrite Not Implemented
func (e *EdisonAdaptor) ServoWrite(string, byte) {}

// AnalogRead returns value from analog reading of specified pin
func (e *EdisonAdaptor) AnalogRead(pin string) int {
	buf, err := readFile(
		"/sys/bus/iio/devices/iio:device1/in_voltage" + pin + "_raw",
	)
	if err != nil {
		panic(err)
	}
	val, err := strconv.Atoi(string(buf[0 : len(buf)-1]))
	if err != nil {
		panic(err)
	}
	return val
}

// I2cStart initializes i2c device for addresss
func (e *EdisonAdaptor) I2cStart(address byte) {
	e.tristate.Write(sysfs.LOW)

	for _, i := range []int{14, 165, 212, 213} {
		io := sysfs.NewDigitalPin(i)
		io.Export()
		io.Direction(sysfs.IN)
		io.Unexport()
	}

	for _, i := range []int{236, 237, 204, 205} {
		io := sysfs.NewDigitalPin(i)
		io.Export()
		io.Direction(sysfs.OUT)
		io.Write(sysfs.LOW)
		io.Unexport()
	}

	for _, i := range []string{"28", "27"} {
		changePinMode(i, "1")
	}

	e.tristate.Write(sysfs.HIGH)

	e.i2cDevice, _ = sysfs.NewI2cDevice(i2cLocation, address)
}

// I2cWrite writes data to i2cDevice
func (e *EdisonAdaptor) I2cWrite(data []byte) {
	e.i2cDevice.Write(data)
}

// I2cRead reads data from i2cDevice
func (e *EdisonAdaptor) I2cRead(size uint) []byte {
	b := make([]byte, size)
	e.i2cDevice.Read(b)
	return b
}
<|endoftext|>


<commit_before>package oauth

import (
	"time"

	"github.com/RangelReale/osin"
	"github.com/hellofresh/janus/cors"
	"github.com/hellofresh/janus/proxy"
	"gopkg.in/mgo.v2/bson"
)

// OAuth holds the configuration for oauth proxies
type OAuth struct {
	ID                     bson.ObjectId               `bson:"_id,omitempty" json:"id,omitempty" valid:"required"`
	Name                   string                      `bson:"name" json:"name" valid:"required"`
	CreatedAt              time.Time                   `bson:"created_at" json:"created_at" valid:"-"`
	UpdatedAt              time.Time                   `bson:"updated_at" json:"updated_at" valid:"-"`
	Endpoints              Endpoints                   `bson:"oauth_endpoints" json:"oauth_endpoints"`
	ClientEndpoints        ClientEndpoints             `bson:"oauth_client_endpoints" json:"oauth_client_endpoints"`
	AllowedAccessTypes     []osin.AccessRequestType    `bson:"allowed_access_types" json:"allowed_access_types"`
	AllowedAuthorizeTypes  []osin.AuthorizeRequestType `bson:"allowed_authorize_types" json:"allowed_authorize_types"`
	AuthorizeLoginRedirect string                      `bson:"auth_login_redirect" json:"auth_login_redirect"`
	Secrets                map[string]string           `bson:"secrets" json:"secrets"`
	CorsMeta               cors.Meta                   `bson:"cors_meta" json:"cors_meta" valid:"cors_meta"`
}

// Endpoints defines the oauth endpoints that wil be proxied
type Endpoints struct {
	Authorize proxy.Proxy `bson:"authorize" json:"authorize"`
	Token     proxy.Proxy `bson:"token" json:"token"`
	Info      proxy.Proxy `bson:"info" json:"info"`
}

// ClientEndpoints defines the oauth client endpoints that wil be proxied
type ClientEndpoints struct {
	Create proxy.Proxy `bson:"create" json:"create"`
	Remove proxy.Proxy `bson:"remove" json:"remove"`
}
<commit_msg>Removed osin dependency<commit_after>package oauth

import (
	"time"

	"github.com/hellofresh/janus/cors"
	"github.com/hellofresh/janus/proxy"
	"gopkg.in/mgo.v2/bson"
)

// AccessRequestType is the type for OAuth param `grant_type`
type AccessRequestType string

// AuthorizeRequestType is the type for OAuth param `response_type`
type AuthorizeRequestType string

// OAuth holds the configuration for oauth proxies
type OAuth struct {
	ID                     bson.ObjectId          `bson:"_id,omitempty" json:"id,omitempty" valid:"required"`
	Name                   string                 `bson:"name" json:"name" valid:"required"`
	CreatedAt              time.Time              `bson:"created_at" json:"created_at" valid:"-"`
	UpdatedAt              time.Time              `bson:"updated_at" json:"updated_at" valid:"-"`
	Endpoints              Endpoints              `bson:"oauth_endpoints" json:"oauth_endpoints"`
	ClientEndpoints        ClientEndpoints        `bson:"oauth_client_endpoints" json:"oauth_client_endpoints"`
	AllowedAccessTypes     []AccessRequestType    `bson:"allowed_access_types" json:"allowed_access_types"`
	AllowedAuthorizeTypes  []AuthorizeRequestType `bson:"allowed_authorize_types" json:"allowed_authorize_types"`
	AuthorizeLoginRedirect string                 `bson:"auth_login_redirect" json:"auth_login_redirect"`
	Secrets                map[string]string      `bson:"secrets" json:"secrets"`
	CorsMeta               cors.Meta              `bson:"cors_meta" json:"cors_meta" valid:"cors_meta"`
}

// Endpoints defines the oauth endpoints that wil be proxied
type Endpoints struct {
	Authorize proxy.Proxy `bson:"authorize" json:"authorize"`
	Token     proxy.Proxy `bson:"token" json:"token"`
	Info      proxy.Proxy `bson:"info" json:"info"`
}

// ClientEndpoints defines the oauth client endpoints that wil be proxied
type ClientEndpoints struct {
	Create proxy.Proxy `bson:"create" json:"create"`
	Remove proxy.Proxy `bson:"remove" json:"remove"`
}
<|endoftext|>


<commit_before>package none

import (
	"errors"
	"github.com/mitchellh/packer/packer"
	"io"
	"os"
)

type comm struct {
	config string
}

// Creates a null packer.Communicator implementation. This takes
// an already existing configuration.
func New(config string) (result *comm, err error) {
	// Establish an initial connection and connect
	result = &comm{
		config: config,
	}

	return
}

func (c *comm) Start(cmd *packer.RemoteCmd) (err error) {
	cmd.SetExited(0)
	return
}

func (c *comm) Upload(path string, input io.Reader, fi *os.FileInfo) error {
	return errors.New("Upload is not implemented when communicator = 'none'")
}

func (c *comm) UploadDir(dst string, src string, excl []string) error {
	return errors.New("UploadDir is not implemented when communicator = 'none'")
}

func (c *comm) Download(path string, output io.Writer) error {
	return errors.New("Download is not implemented when communicator = 'none'")
}
<commit_msg>Add new interface method to the 'none' communicator<commit_after>package none

import (
	"errors"
	"github.com/mitchellh/packer/packer"
	"io"
	"os"
)

type comm struct {
	config string
}

// Creates a null packer.Communicator implementation. This takes
// an already existing configuration.
func New(config string) (result *comm, err error) {
	// Establish an initial connection and connect
	result = &comm{
		config: config,
	}

	return
}

func (c *comm) Start(cmd *packer.RemoteCmd) (err error) {
	cmd.SetExited(0)
	return
}

func (c *comm) Upload(path string, input io.Reader, fi *os.FileInfo) error {
	return errors.New("Upload is not implemented when communicator = 'none'")
}

func (c *comm) UploadDir(dst string, src string, excl []string) error {
	return errors.New("UploadDir is not implemented when communicator = 'none'")
}

func (c *comm) Download(path string, output io.Writer) error {
	return errors.New("Download is not implemented when communicator = 'none'")
}

func (c *comm) DownloadDir(dst string, src string, excl []string) error {
	return errors.New("DownloadDir is not implemented when communicator = 'none'")
}
<|endoftext|>


<commit_before>/*
	Copyright (c) 2016, Percona LLC and/or its affiliates. All rights reserved.

	This program is free software: you can redistribute it and/or modify
	it under the terms of the GNU Affero General Public License as published by
	the Free Software Foundation, either version 3 of the License, or
	(at your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU Affero General Public License for more details.

	You should have received a copy of the GNU Affero General Public License
	along with this program.  If not, see <http://www.gnu.org/licenses/>
*/

package fakeapi

import (
	"context"
	"net"
	"net/http"
	"net/http/httptest"
	"net/url"
	"sync"
)

type FakeApi struct {
	testServer          *httptest.Server
	serveMux            *http.ServeMux
	ctx                 context.Context
	baseURL, host, port string
	sync.RWMutex
}

func New() *FakeApi {
	fakeApi := &FakeApi{}
	fakeApi.serveMux = http.NewServeMux()
	return fakeApi
}

// Start new FakeApi server and return it's URL, host and port
func (f *FakeApi) Start() (string, string, string) {
	f.Lock()
	defer f.Unlock()
	f.testServer = httptest.NewServer(f.serveMux)
	f.baseURL = f.testServer.URL
	u, _ := url.Parse(f.baseURL)
	f.host, f.port, _ = net.SplitHostPort(u.Host)
	return f.baseURL, f.host, f.port
}

func (f *FakeApi) Close() {
	f.ctx = nil
	if f.testServer != nil {
		f.testServer.Close()
		f.testServer = nil
	}
}

func (f *FakeApi) Append(pattern string, handler func(http.ResponseWriter, *http.Request)) {
	f.serveMux.HandleFunc(pattern, handler)
}
<commit_msg>One more comment.<commit_after>/*
	Copyright (c) 2016, Percona LLC and/or its affiliates. All rights reserved.

	This program is free software: you can redistribute it and/or modify
	it under the terms of the GNU Affero General Public License as published by
	the Free Software Foundation, either version 3 of the License, or
	(at your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU Affero General Public License for more details.

	You should have received a copy of the GNU Affero General Public License
	along with this program.  If not, see <http://www.gnu.org/licenses/>
*/

package fakeapi

import (
	"context"
	"net"
	"net/http"
	"net/http/httptest"
	"net/url"
	"sync"
)

type FakeApi struct {
	testServer          *httptest.Server
	serveMux            *http.ServeMux
	ctx                 context.Context
	baseURL, host, port string
	sync.RWMutex
}

func New() *FakeApi {
	fakeApi := &FakeApi{}
	fakeApi.serveMux = http.NewServeMux()
	return fakeApi
}

// Start new FakeApi server and return it's URL, host and port
func (f *FakeApi) Start() (string, string, string) {
	f.Lock()
	defer f.Unlock()
	f.testServer = httptest.NewServer(f.serveMux)
	f.baseURL = f.testServer.URL
	u, _ := url.Parse(f.baseURL)
	f.host, f.port, _ = net.SplitHostPort(u.Host)
	return f.baseURL, f.host, f.port
}

// Close shutdowns FakeApi server.
func (f *FakeApi) Close() {
	f.ctx = nil
	if f.testServer != nil {
		f.testServer.Close()
		f.testServer = nil
	}
}

func (f *FakeApi) Append(pattern string, handler func(http.ResponseWriter, *http.Request)) {
	f.serveMux.HandleFunc(pattern, handler)
}
<|endoftext|>


<commit_before>// Copyright 2018 Keybase Inc. All rights reserved.
// Use of this source code is governed by a BSD
// license that can be found in the LICENSE file.

package kbfsedits

import (
	"container/heap"
	"encoding/json"
	"sort"
	"sync"
)

const (
	// The max number of edits needed for each writer.
	maxEditsPerWriter    = 10
	maxWritersPerHistory = 10
)

type writerNotifications struct {
	writerName    string
	notifications notificationsByRevision
}

// writersByRevision sorts sets of per-writer notifications in reverse
// order by the revision of the latest notification for each writer.
type writersByRevision []*writerNotifications

func (wbr writersByRevision) Len() int {
	return len(wbr)
}

func (wbr writersByRevision) Less(i, j int) bool {
	// Some revisions come before no revisions.
	iHasZero := len(wbr[i].notifications) == 0
	jHasZero := len(wbr[j].notifications) == 0
	if jHasZero {
		return iHasZero
	} else if iHasZero {
		return false
	}

	// Reverse sort, so latest revisions come first.
	return wbr[i].notifications[0].Revision > wbr[j].notifications[0].Revision
}

func (wbr writersByRevision) Swap(i, j int) {
	wbr[i], wbr[j] = wbr[j], wbr[i]
}

func (wbr *writersByRevision) Push(x interface{}) {
	wn := x.(*writerNotifications)
	*wbr = append(*wbr, wn)
}

func (wbr *writersByRevision) Pop() interface{} {
	// The item to remove is the last item; heap has already swapped
	// it to the end.
	old := *wbr
	n := len(old)
	item := old[n-1]
	*wbr = old[0 : n-1]
	return item
}

// TlfHistory maintains a history of the last N file edits from each
// writer in the TLF.
//
// There will be two users of a TlfHistory instance:
//
//   * One user (likely something outside of the kbfsedits package,
//     e.g. libkbfs.folderBranchOps) will read notifications from the
//     corresponding TLF and add them to this history.  After adding a
//     batch or several batches of messages, it should call
//     `Recompute()`, and if some writers need more, earlier revisions,
//     it should fetch more notifications for the indicated writer and
//     repeat.
//
//   * The other user (within the kbfsedits package) will collate the
//     histories from multiple TlfHistory instances together using
//     `getHistory()` from each one.  It may also construct pretty
//     versions of individual edit histories for a particular TLF.
type TlfHistory struct {
	lock          sync.RWMutex
	byWriter      map[string]*writerNotifications
	computed      bool
	cachedHistory writersByRevision
}

// NewTlfHistory constructs a new TlfHistory instance.
func NewTlfHistory() *TlfHistory {
	return &TlfHistory{
		byWriter: make(map[string]*writerNotifications),
	}
}

// AddNotifications takes in a set of messages in this TLF by
// `writer`, and adds them to the history.  Once done adding messages,
// the caller should call `Recompute` to find out if more messages
// should be added for any particular writer.
func (th *TlfHistory) AddNotifications(
	writerName string, messages []string) (err error) {
	newEdits := make(notificationsByRevision, 0, len(messages))

	// Unmarshal and sort the new messages.
	for _, msg := range messages {
		var revList []NotificationMessage
		err := json.Unmarshal([]byte(msg), &revList)
		if err != nil {
			// The messages might be from a new version we don't
			// understand, so swallow the error.
			continue
		}

		for j := len(revList) - 1; j >= 0; j-- {
			revMsg := revList[j]
			if revMsg.Version != NotificationV2 {
				// Ignore messages that are too new for us to understand.
				continue
			}
			revMsg.numWithinRevision = j
			newEdits = append(newEdits, revMsg)
		}
	}

	th.lock.Lock()
	defer th.lock.Unlock()
	wn, existed := th.byWriter[writerName]
	if !existed {
		wn = &writerNotifications{writerName, nil}
	}
	oldLen := len(wn.notifications)
	newEdits = append(newEdits, wn.notifications...)
	sort.Sort(newEdits)
	wn.notifications = newEdits.uniquify()
	if len(wn.notifications) == oldLen {
		// No new messages.
		return nil
	}
	if !existed {
		wn.writerName = writerName
		th.byWriter[writerName] = wn
	}
	// Invalidate the cached results.
	th.computed = false
	return nil
}

type fileEvent struct {
	delete  bool
	newName string
}

type recomputer struct {
	byWriter      map[string]*writerNotifications
	modifiedFiles map[string]map[string]bool // writer -> file -> bool
	fileEvents    map[string]fileEvent       // currentName -> ultimate fate
	numProcessed  map[string]int             // writer name -> num
}

func newRecomputer() *recomputer {
	return &recomputer{
		byWriter:      make(map[string]*writerNotifications),
		modifiedFiles: make(map[string]map[string]bool),
		fileEvents:    make(map[string]fileEvent),
		numProcessed:  make(map[string]int),
	}
}

// processNotification adds the notification to the recomputer's
// history if it is a create/modify for a file that hasn't yet been
// deleted.  If the file is renamed in a future revision, the added
// notification has the new name of the file.  processNotification
// should be called with notifications in reverse order of their
// revision number.
//
// It returns true if it has added enough notifications for the given
// writer, and the caller should not send any more for that writer.
func (r *recomputer) processNotification(
	writer string, notification NotificationMessage) (doTrim bool) {
	filename := notification.Filename
	r.numProcessed[writer]++

	// If the file is renamed in a future revision, rename it in the
	// notification.
	//
	// TODO(KBFS-3073): maybe we should check all the parent
	// directories for renames as well, so we can give a full, updated
	// path for older edits.  That would also help avoid showing edits
	// for files that were later deleted, but in a renamed directory.
	eventFilename := filename
	event, hasEvent := r.fileEvents[filename]
	if hasEvent && event.newName != "" {
		notification.Filename = event.newName
		filename = event.newName
	}

	// Keep only the creates and modifies for non-deleted files,
	// but remember the renames and deletes.
	switch notification.Type {
	case NotificationCreate, NotificationModify:
		// Disregard any file that's already been deleted.
		if hasEvent && event.delete {
			return false
		}

		// We only care about files, so skip dir and sym creates.
		if notification.FileType != EntryTypeFile {
			return false
		}

		// We only need one modify message per writer per file.
		if r.modifiedFiles[writer][filename] {
			return false
		}

		wn, ok := r.byWriter[writer]
		if !ok {
			wn = &writerNotifications{writer, nil}
			r.byWriter[writer] = wn
		}
		wn.writerName = writer
		wn.notifications = append(wn.notifications, notification)

		modified, ok := r.modifiedFiles[writer]
		if !ok {
			modified = make(map[string]bool)
			r.modifiedFiles[writer] = modified
		}
		modified[filename] = true

		if len(wn.notifications) == maxEditsPerWriter {
			// We have enough edits for this user.
			return true
		}
	case NotificationRename:
		// If the file already has a final event, move that to the old
		// filename.  Otherwise, this is the final event.
		if hasEvent {
			r.fileEvents[notification.Params.OldFilename] = event
			delete(r.fileEvents, eventFilename)
		} else {
			r.fileEvents[notification.Params.OldFilename] =
				fileEvent{newName: eventFilename}
		}

		// The renamed file overwrote any existing file with the new
		// name.
		r.fileEvents[eventFilename] = fileEvent{delete: true}
	case NotificationDelete:
		r.fileEvents[eventFilename] = fileEvent{delete: true}
	}
	return false
}

func (th *TlfHistory) recomputeLocked() (
	history writersByRevision, writersWhoNeedMore map[string]bool) {
	writersWhoNeedMore = make(map[string]bool)

	// Copy the writer notifications into a heap.
	var writersHeap writersByRevision
	for _, wn := range th.byWriter {
		wnCopy := writerNotifications{
			writerName:    wn.writerName,
			notifications: make(notificationsByRevision, len(wn.notifications)),
		}
		copy(wnCopy.notifications, wn.notifications)
		writersHeap = append(writersHeap, &wnCopy)
	}
	heap.Init(&writersHeap)

	r := newRecomputer()

	// Iterate through the heap.  The writer with the next highest
	// revision will always be at index 0.  Process that writer's
	// first notification, then remove it and fix the heap so that the
	// next highest revision is at index 0.  That way events that
	// happen more recently (like deletes and renames) can be taken
	// into account when looking at older events.
	for writersHeap.Len() > 0 {
		nextWriter := writersHeap[0].writerName
		nextNotification := writersHeap[0].notifications[0]
		doTrim := r.processNotification(nextWriter, nextNotification)

		// Remove that notification, and fix the heap because this
		// writer has a different newest revision.
		if doTrim {
			// Trim all earlier revisions because they won't be needed
			// for the cached history.
			numProcessed := r.numProcessed[nextWriter]
			th.byWriter[nextWriter].notifications =
				th.byWriter[nextWriter].notifications[:numProcessed]
		} else {
			writersHeap[0].notifications = writersHeap[0].notifications[1:]
		}
		if len(writersHeap[0].notifications) == 0 || doTrim {
			heap.Pop(&writersHeap)
		} else {
			heap.Fix(&writersHeap, 0)
		}
	}

	history = make(writersByRevision, 0, len(r.byWriter))
	for writerName := range th.byWriter {
		wn := r.byWriter[writerName]
		if wn != nil && len(wn.notifications) > 0 {
			history = append(history, wn)
		}
		if wn == nil || len(wn.notifications) < maxEditsPerWriter {
			writersWhoNeedMore[writerName] = true
		}
	}
	sort.Sort(history)
	if len(history) > maxWritersPerHistory {
		// Garbage-collect any writers that don't appear in the history.
		for i := maxWritersPerHistory; i < len(history); i++ {
			delete(th.byWriter, history[i].writerName)
			delete(writersWhoNeedMore, history[i].writerName)
		}
		history = history[:maxWritersPerHistory]
	}
	th.computed = true
	th.cachedHistory = history
	return history, writersWhoNeedMore
}

func (th *TlfHistory) getHistoryIfCached() (
	cached bool, history writersByRevision) {
	th.lock.RLock()
	defer th.lock.RUnlock()
	if th.computed {
		return true, th.cachedHistory
	}
	return false, nil
}

func (th *TlfHistory) getHistory() writersByRevision {
	cached, history := th.getHistoryIfCached()
	if cached {
		return history
	}

	th.lock.Lock()
	defer th.lock.Unlock()
	if th.computed {
		// Maybe another goroutine got the lock and recomuted the
		// history since we checked above.
		return th.cachedHistory
	}
	history, _ = th.recomputeLocked()
	return history
}

// Recompute processes (and caches) the history so that it reflects
// all recently-added notifications, and returns the names of writers
// which don't yet have the maximum number of edits in the history.
func (th *TlfHistory) Recompute() (writersWhoNeedMore map[string]bool) {
	th.lock.Lock()
	defer th.lock.Unlock()
	_, writersWhoNeedMore = th.recomputeLocked()
	return writersWhoNeedMore
}
<commit_msg>kbfsedits: avoid unneeded writer name assignments<commit_after>// Copyright 2018 Keybase Inc. All rights reserved.
// Use of this source code is governed by a BSD
// license that can be found in the LICENSE file.

package kbfsedits

import (
	"container/heap"
	"encoding/json"
	"sort"
	"sync"
)

const (
	// The max number of edits needed for each writer.
	maxEditsPerWriter    = 10
	maxWritersPerHistory = 10
)

type writerNotifications struct {
	writerName    string
	notifications notificationsByRevision
}

// writersByRevision sorts sets of per-writer notifications in reverse
// order by the revision of the latest notification for each writer.
type writersByRevision []*writerNotifications

func (wbr writersByRevision) Len() int {
	return len(wbr)
}

func (wbr writersByRevision) Less(i, j int) bool {
	// Some revisions come before no revisions.
	iHasZero := len(wbr[i].notifications) == 0
	jHasZero := len(wbr[j].notifications) == 0
	if jHasZero {
		return iHasZero
	} else if iHasZero {
		return false
	}

	// Reverse sort, so latest revisions come first.
	return wbr[i].notifications[0].Revision > wbr[j].notifications[0].Revision
}

func (wbr writersByRevision) Swap(i, j int) {
	wbr[i], wbr[j] = wbr[j], wbr[i]
}

func (wbr *writersByRevision) Push(x interface{}) {
	wn := x.(*writerNotifications)
	*wbr = append(*wbr, wn)
}

func (wbr *writersByRevision) Pop() interface{} {
	// The item to remove is the last item; heap has already swapped
	// it to the end.
	old := *wbr
	n := len(old)
	item := old[n-1]
	*wbr = old[0 : n-1]
	return item
}

// TlfHistory maintains a history of the last N file edits from each
// writer in the TLF.
//
// There will be two users of a TlfHistory instance:
//
//   * One user (likely something outside of the kbfsedits package,
//     e.g. libkbfs.folderBranchOps) will read notifications from the
//     corresponding TLF and add them to this history.  After adding a
//     batch or several batches of messages, it should call
//     `Recompute()`, and if some writers need more, earlier revisions,
//     it should fetch more notifications for the indicated writer and
//     repeat.
//
//   * The other user (within the kbfsedits package) will collate the
//     histories from multiple TlfHistory instances together using
//     `getHistory()` from each one.  It may also construct pretty
//     versions of individual edit histories for a particular TLF.
type TlfHistory struct {
	lock          sync.RWMutex
	byWriter      map[string]*writerNotifications
	computed      bool
	cachedHistory writersByRevision
}

// NewTlfHistory constructs a new TlfHistory instance.
func NewTlfHistory() *TlfHistory {
	return &TlfHistory{
		byWriter: make(map[string]*writerNotifications),
	}
}

// AddNotifications takes in a set of messages in this TLF by
// `writer`, and adds them to the history.  Once done adding messages,
// the caller should call `Recompute` to find out if more messages
// should be added for any particular writer.
func (th *TlfHistory) AddNotifications(
	writerName string, messages []string) (err error) {
	newEdits := make(notificationsByRevision, 0, len(messages))

	// Unmarshal and sort the new messages.
	for _, msg := range messages {
		var revList []NotificationMessage
		err := json.Unmarshal([]byte(msg), &revList)
		if err != nil {
			// The messages might be from a new version we don't
			// understand, so swallow the error.
			continue
		}

		for j := len(revList) - 1; j >= 0; j-- {
			revMsg := revList[j]
			if revMsg.Version != NotificationV2 {
				// Ignore messages that are too new for us to understand.
				continue
			}
			revMsg.numWithinRevision = j
			newEdits = append(newEdits, revMsg)
		}
	}

	th.lock.Lock()
	defer th.lock.Unlock()
	wn, existed := th.byWriter[writerName]
	if !existed {
		wn = &writerNotifications{writerName, nil}
	}
	oldLen := len(wn.notifications)
	newEdits = append(newEdits, wn.notifications...)
	sort.Sort(newEdits)
	wn.notifications = newEdits.uniquify()
	if len(wn.notifications) == oldLen {
		// No new messages.
		return nil
	}
	if !existed {
		th.byWriter[writerName] = wn
	}
	// Invalidate the cached results.
	th.computed = false
	return nil
}

type fileEvent struct {
	delete  bool
	newName string
}

type recomputer struct {
	byWriter      map[string]*writerNotifications
	modifiedFiles map[string]map[string]bool // writer -> file -> bool
	fileEvents    map[string]fileEvent       // currentName -> ultimate fate
	numProcessed  map[string]int             // writer name -> num
}

func newRecomputer() *recomputer {
	return &recomputer{
		byWriter:      make(map[string]*writerNotifications),
		modifiedFiles: make(map[string]map[string]bool),
		fileEvents:    make(map[string]fileEvent),
		numProcessed:  make(map[string]int),
	}
}

// processNotification adds the notification to the recomputer's
// history if it is a create/modify for a file that hasn't yet been
// deleted.  If the file is renamed in a future revision, the added
// notification has the new name of the file.  processNotification
// should be called with notifications in reverse order of their
// revision number.
//
// It returns true if it has added enough notifications for the given
// writer, and the caller should not send any more for that writer.
func (r *recomputer) processNotification(
	writer string, notification NotificationMessage) (doTrim bool) {
	filename := notification.Filename
	r.numProcessed[writer]++

	// If the file is renamed in a future revision, rename it in the
	// notification.
	//
	// TODO(KBFS-3073): maybe we should check all the parent
	// directories for renames as well, so we can give a full, updated
	// path for older edits.  That would also help avoid showing edits
	// for files that were later deleted, but in a renamed directory.
	eventFilename := filename
	event, hasEvent := r.fileEvents[filename]
	if hasEvent && event.newName != "" {
		notification.Filename = event.newName
		filename = event.newName
	}

	// Keep only the creates and modifies for non-deleted files,
	// but remember the renames and deletes.
	switch notification.Type {
	case NotificationCreate, NotificationModify:
		// Disregard any file that's already been deleted.
		if hasEvent && event.delete {
			return false
		}

		// We only care about files, so skip dir and sym creates.
		if notification.FileType != EntryTypeFile {
			return false
		}

		// We only need one modify message per writer per file.
		if r.modifiedFiles[writer][filename] {
			return false
		}

		wn, ok := r.byWriter[writer]
		if !ok {
			wn = &writerNotifications{writer, nil}
			r.byWriter[writer] = wn
		}
		wn.notifications = append(wn.notifications, notification)

		modified, ok := r.modifiedFiles[writer]
		if !ok {
			modified = make(map[string]bool)
			r.modifiedFiles[writer] = modified
		}
		modified[filename] = true

		if len(wn.notifications) == maxEditsPerWriter {
			// We have enough edits for this user.
			return true
		}
	case NotificationRename:
		// If the file already has a final event, move that to the old
		// filename.  Otherwise, this is the final event.
		if hasEvent {
			r.fileEvents[notification.Params.OldFilename] = event
			delete(r.fileEvents, eventFilename)
		} else {
			r.fileEvents[notification.Params.OldFilename] =
				fileEvent{newName: eventFilename}
		}

		// The renamed file overwrote any existing file with the new
		// name.
		r.fileEvents[eventFilename] = fileEvent{delete: true}
	case NotificationDelete:
		r.fileEvents[eventFilename] = fileEvent{delete: true}
	}
	return false
}

func (th *TlfHistory) recomputeLocked() (
	history writersByRevision, writersWhoNeedMore map[string]bool) {
	writersWhoNeedMore = make(map[string]bool)

	// Copy the writer notifications into a heap.
	var writersHeap writersByRevision
	for _, wn := range th.byWriter {
		wnCopy := writerNotifications{
			writerName:    wn.writerName,
			notifications: make(notificationsByRevision, len(wn.notifications)),
		}
		copy(wnCopy.notifications, wn.notifications)
		writersHeap = append(writersHeap, &wnCopy)
	}
	heap.Init(&writersHeap)

	r := newRecomputer()

	// Iterate through the heap.  The writer with the next highest
	// revision will always be at index 0.  Process that writer's
	// first notification, then remove it and fix the heap so that the
	// next highest revision is at index 0.  That way events that
	// happen more recently (like deletes and renames) can be taken
	// into account when looking at older events.
	for writersHeap.Len() > 0 {
		nextWriter := writersHeap[0].writerName
		nextNotification := writersHeap[0].notifications[0]
		doTrim := r.processNotification(nextWriter, nextNotification)

		// Remove that notification, and fix the heap because this
		// writer has a different newest revision.
		if doTrim {
			// Trim all earlier revisions because they won't be needed
			// for the cached history.
			numProcessed := r.numProcessed[nextWriter]
			th.byWriter[nextWriter].notifications =
				th.byWriter[nextWriter].notifications[:numProcessed]
		} else {
			writersHeap[0].notifications = writersHeap[0].notifications[1:]
		}
		if len(writersHeap[0].notifications) == 0 || doTrim {
			heap.Pop(&writersHeap)
		} else {
			heap.Fix(&writersHeap, 0)
		}
	}

	history = make(writersByRevision, 0, len(r.byWriter))
	for writerName := range th.byWriter {
		wn := r.byWriter[writerName]
		if wn != nil && len(wn.notifications) > 0 {
			history = append(history, wn)
		}
		if wn == nil || len(wn.notifications) < maxEditsPerWriter {
			writersWhoNeedMore[writerName] = true
		}
	}
	sort.Sort(history)
	if len(history) > maxWritersPerHistory {
		// Garbage-collect any writers that don't appear in the history.
		for i := maxWritersPerHistory; i < len(history); i++ {
			delete(th.byWriter, history[i].writerName)
			delete(writersWhoNeedMore, history[i].writerName)
		}
		history = history[:maxWritersPerHistory]
	}
	th.computed = true
	th.cachedHistory = history
	return history, writersWhoNeedMore
}

func (th *TlfHistory) getHistoryIfCached() (
	cached bool, history writersByRevision) {
	th.lock.RLock()
	defer th.lock.RUnlock()
	if th.computed {
		return true, th.cachedHistory
	}
	return false, nil
}

func (th *TlfHistory) getHistory() writersByRevision {
	cached, history := th.getHistoryIfCached()
	if cached {
		return history
	}

	th.lock.Lock()
	defer th.lock.Unlock()
	if th.computed {
		// Maybe another goroutine got the lock and recomuted the
		// history since we checked above.
		return th.cachedHistory
	}
	history, _ = th.recomputeLocked()
	return history
}

// Recompute processes (and caches) the history so that it reflects
// all recently-added notifications, and returns the names of writers
// which don't yet have the maximum number of edits in the history.
func (th *TlfHistory) Recompute() (writersWhoNeedMore map[string]bool) {
	th.lock.Lock()
	defer th.lock.Unlock()
	_, writersWhoNeedMore = th.recomputeLocked()
	return writersWhoNeedMore
}
<|endoftext|>