<commit_before>package main

import (
	"fmt"
	//	"github.com/bradfitz/iter"
	"github.com/codegangsta/negroni"
	"github.com/gorilla/mux"
	"github.com/gorilla/websocket"
	"github.com/hut8/tumblr-go"
	"github.com/kr/pretty"
	"html/template"
	"net/http"
	"os"
)

var upgrader websocket.Upgrader

func HomeHandler(w http.ResponseWriter, r *http.Request) {
	t, err := template.ParseFiles("templates/index.go.html")
	ensureNil(err)
	err = t.Execute(w, nil)
	ensureNil(err)
}

type SimilarPostRequest struct {
	PostUri string
}

type beginNotification struct {
	BaseHostname string `json:"base-hostname"`
	PostID       int64  `json:"pid"`
	MsgType      string `json:"msg-type"`
}

func sendBeginNotification(c *websocket.Conn, bh string, pid int64) error {
	msg := &beginNotification{
		BaseHostname: bh,
		PostID:       pid,
		MsgType:      "begin-notification",
	}
	return c.WriteJSON(msg)
}

func sendErrorNotification(c *websocket.Conn, err error) error {
	return c.WriteJSON(&struct {
		MsgType string `json:"msg-type"`
		Message string `json:"message"`
	}{
		"error",
		err.Error(),
	})
}

func sendBlogsLikingPostData(c *websocket.Conn, blogs []string) error {
	return c.WriteJSON(&struct {
		MsgType string   `json:"msg-type"`
		Blogs   []string `json:"blogs"`
	}{
		"blogs-liking-post",
		blogs,
	})
}

func sendBlogLikesData(c *websocket.Conn, blog string, likes []int64) error {
	return c.WriteJSON(&struct {
		MsgType string  `json:"msg-type"`
		Blog    string  `json:"blog"`
		Likes   []int64 `json:"likes"`
	}{
		"blog-likes",
		blog,
		likes,
	})
}

func SimilarHandler(w http.ResponseWriter, r *http.Request) {
	conn, err := upgrader.Upgrade(w, r, nil)
	ensureNil(err)
	defer conn.Close()

	// Figure out what post they want and extract the details we need
	spr := &SimilarPostRequest{}
	err = conn.ReadJSON(spr)
	ensureNil(err)
	bh, pid, err := extractPostId(spr.PostUri)
	if err != nil {
		msg := fmt.Errorf("invalid post uri: %s", spr.PostUri)
		sendErrorNotification(conn, msg)
		return
	}

	err = sendBeginNotification(conn, bh, pid)
	ensureNil(err)

	// Find every blog that likes the input post
	likingBlogs, err := blogsLikingPost(bh, pid)
	ensureNil(err)
	err = sendBlogsLikingPostData(conn, likingBlogs)
	ensureNil(err)

	// Find every liked post from every blog that likes the input post
	// postId -> []blogUrl
	blogLikeMap := make(map[int64][]string)
	// postId -> Post
	postMap := make(map[int64]tumblr.Post)
	for _, blogName := range likingBlogs {
		b := tumblrClient.NewBlog(blogName)
		fmt.Printf("Requesting likes for: %s\n", b.BaseHostname)
		likeCollection, err := b.Likes(tumblr.LimitOffset{})
		if err != nil {
			fmt.Println(err.Error())
			continue
		}

		// How many pages are we going to loop through
		totalPages := int(likeCollection.TotalCount) / 20
		if (likeCollection.TotalCount % 20) != 0 {
			totalPages += 1
		}

		// Loop over pages.
		// Note that we already retrieved the first page, so fetch at end of loop
		for currentPage := 1; currentPage < totalPages; currentPage++ {
			pagePostIDs := []int64{}
			for _, likedPost := range likeCollection.Likes.Posts {
				pagePostIDs = append(pagePostIDs, likedPost.PostId())
				postMap[likedPost.PostId()] = likedPost
				// Initialize if key if needbe
				_, ok := blogLikeMap[likedPost.PostId()]
				if !ok {
					blogLikeMap[likedPost.PostId()] = []string{}
				}
				blogLikeMap[likedPost.PostId()] = append(
					blogLikeMap[likedPost.PostId()], b.BaseHostname)
			}
			sendBlogLikesData(conn, b.BaseHostname, pagePostIDs)

			// Fetch next page
			likeCollection, err = b.Likes(tumblr.LimitOffset{
				Offset: currentPage*20,
			})
			if err != nil {
				fmt.Println(err.Error())
				break
			}
		}
		//sendBlogsLikingPostData(conn, blogLikeMap[likedPost.PostId()])
	}
	fmt.Printf("PostID->Blogs who like it%# v\n", pretty.Formatter(blogLikeMap))
}

func ensureNil(x interface{}) {
	if x != nil {
		panic(x)
	}
}

func main() {
	router := mux.NewRouter()
	router.HandleFunc("/", HomeHandler)
	router.HandleFunc("/post", SimilarHandler)

	n := negroni.New()
	n.UseHandler(router)
	n.Run(fmt.Sprintf(":%s", os.Getenv("PORT")))
}
<commit_msg>Clean up some of the message structs<commit_after>package main

import (
	"fmt"
	//	"github.com/bradfitz/iter"
	"github.com/codegangsta/negroni"
	"github.com/gorilla/mux"
	"github.com/gorilla/websocket"
	"github.com/hut8/tumblr-go"
	"github.com/kr/pretty"
	"html/template"
	"net/http"
	"os"
)

var upgrader websocket.Upgrader

func HomeHandler(w http.ResponseWriter, r *http.Request) {
	t, err := template.ParseFiles("templates/index.go.html")
	ensureNil(err)
	err = t.Execute(w, nil)
	ensureNil(err)
}

type SimilarPostRequest struct {
	PostUri string
}

func sendProcessNotification(c *websocket.Conn, bh string, pid int64) error {
	return c.WriteJSON(&struct {
		MsgType      string `json:"msg-type"`
		BaseHostname string `json:"base-hostname"`
		PostID       int64  `json:"pid"`
	}{
		"process-post",
		bh,
		pid,
	})
}

func sendBlogsLikingPostData(c *websocket.Conn, blogs []string) error {
	return c.WriteJSON(&struct {
		MsgType string   `json:"msg-type"`
		Blogs   []string `json:"blogs"`
	}{
		"blogs-liking-post",
		blogs,
	})
}

func sendBlogLikesData(c *websocket.Conn, blog string, likes []int64) error {
	return c.WriteJSON(&struct {
		MsgType string  `json:"msg-type"`
		Blog    string  `json:"blog"`
		Likes   []int64 `json:"likes"`
	}{
		"blog-likes",
		blog,
		likes,
	})
}

func SimilarHandler(w http.ResponseWriter, r *http.Request) {
	conn, err := upgrader.Upgrade(w, r, nil)
	ensureNil(err)
	defer conn.Close()

	// Figure out what post they want and extract the details we need
	spr := &SimilarPostRequest{}
	err = conn.ReadJSON(spr)
	ensureNil(err)
	bh, pid, err := extractPostId(spr.PostUri)
	if err != nil {
		msg := fmt.Errorf("invalid post uri: %s", spr.PostUri)
		sendErrorNotification(conn, msg)
		return
	}

	err = sendBeginNotification(conn, bh, pid)
	ensureNil(err)

	// Find every blog that likes the input post
	likingBlogs, err := blogsLikingPost(bh, pid)
	ensureNil(err)
	err = sendBlogsLikingPostData(conn, likingBlogs)
	ensureNil(err)

	// Find every liked post from every blog that likes the input post
	// postId -> []blogUrl
	blogLikeMap := make(map[int64][]string)
	// postId -> Post
	postMap := make(map[int64]tumblr.Post)
	for _, blogName := range likingBlogs {
		b := tumblrClient.NewBlog(blogName)
		fmt.Printf("Requesting likes for: %s\n", b.BaseHostname)
		likeCollection, err := b.Likes(tumblr.LimitOffset{})
		if err != nil {
			fmt.Println(err.Error())
			continue
		}

		// How many pages are we going to loop through
		totalPages := int(likeCollection.TotalCount) / 20
		if (likeCollection.TotalCount % 20) != 0 {
			totalPages += 1
		}

		// Loop over pages.
		// Note that we already retrieved the first page, so fetch at end of loop
		for currentPage := 1; currentPage < totalPages; currentPage++ {
			pagePostIDs := []int64{}
			for _, likedPost := range likeCollection.Likes.Posts {
				pagePostIDs = append(pagePostIDs, likedPost.PostId())
				postMap[likedPost.PostId()] = likedPost
				// Initialize if key if needbe
				_, ok := blogLikeMap[likedPost.PostId()]
				if !ok {
					blogLikeMap[likedPost.PostId()] = []string{}
				}
				blogLikeMap[likedPost.PostId()] = append(
					blogLikeMap[likedPost.PostId()], b.BaseHostname)
			}
			sendBlogLikesData(conn, b.BaseHostname, pagePostIDs)

			// Fetch next page
			likeCollection, err = b.Likes(tumblr.LimitOffset{
				Offset: currentPage*20,
			})
			if err != nil {
				fmt.Println(err.Error())
				break
			}
		}
		//sendBlogsLikingPostData(conn, blogLikeMap[likedPost.PostId()])
	}
	fmt.Printf("PostID->Blogs who like it%# v\n", pretty.Formatter(blogLikeMap))
}

func ensureNil(x interface{}) {
	if x != nil {
		panic(x)
	}
}

func main() {
	router := mux.NewRouter()
	router.HandleFunc("/", HomeHandler)
	router.HandleFunc("/post", SimilarHandler)

	n := negroni.New()
	n.UseHandler(router)
	n.Run(fmt.Sprintf(":%s", os.Getenv("PORT")))
}
<|endoftext|>


<commit_before>package main

import (
	"github.com/codegangsta/cli"
	"github.com/matthistuff/amazon/actions"
	"github.com/matthistuff/amazon/config"
	"os"
)

func init() {
	if err := config.LoadConfig(); err != nil {
		panic(err)
	}
}

func main() {
	app := cli.NewApp()
	app.EnableBashCompletion = true
	app.Name = "amazon"
	app.Usage = "the CLI interface to amazon"
	app.Version = "0.1.0"

	app.Flags = []cli.Flag{
		cli.StringFlag{
			Name:   "locale, l",
			Value:  "",
			Usage:  "Amazon locale",
			EnvVar: "AMAZON_CLI_LOCALE",
		},
		cli.BoolFlag{
			Name:  "no-color",
			Usage: "disable colored output",
		},
	}

	app.Commands = []cli.Command{
		{
			Name:   "search",
			Usage:  "search for products",
			Action: actions.Search,
			Flags: []cli.Flag{
				cli.IntFlag{
					Name:  "page, p",
					Value: 1,
					Usage: "search results page",
				},
				cli.StringFlag{
					Name:  "sort, s",
					Value: "",
					Usage: "sort order",
				},
				cli.StringFlag{
					Name:  "index, i",
					Value: "All",
					Usage: "search index",
				},
				cli.BoolFlag{
					Name:  "no-rating",
					Usage: "disable fetching product ratings",
				},
			},
		},
		{
			Name:   "info",
			Usage:  "get product info",
			Action: actions.Info,
		},
		{
			Name:   "open",
			Usage:  "open product in browser",
			Action: actions.Open,
		},
		{
			Name:  "cart",
			Usage: "manage a cart",
			Subcommands: []cli.Command{
				{
					Name:   "add",
					Usage:  "add item to cart",
					Action: actions.CartAdd,
				},
				{
					Name:   "update",
					Usage:  "update item in cart",
					Action: actions.CartUpdate,
				},
				{
					Name:   "remove",
					Usage:  "remove item from cart",
					Action: actions.CartRemove,
				},
				{
					Name:   "info",
					Usage:  "list cart items",
					Action: actions.CartInfo,
				},
			},
		},
		{
			Name:  "carts",
			Usage: "manage carts",
			Subcommands: []cli.Command{
				{
					Name:   "list",
					Usage:  "list all active varts",
					Action: actions.CartsList,
				},
				{
					Name:   "destroy",
					Usage:  "delete a cart",
					Action: actions.CartsDestroy,
				},
			},
		},
		{
			Name:   "checkout",
			Usage:  "proceed to checkout",
			Action: actions.Checkout,
		},
		{
			Name:   "locale",
			Usage:  "manage locale",
			Action: actions.Locale,
		},
		{
			Name:   "locales",
			Usage:  "list available locales",
			Action: actions.LocalesList,
		},
	}

	app.Run(os.Args)
}
<commit_msg>mention AWS configuration<commit_after>package main

import (
	"github.com/codegangsta/cli"
	"github.com/matthistuff/amazon/actions"
	"github.com/matthistuff/amazon/config"
	"os"
)

func init() {
	if err := config.LoadConfig(); err != nil {
		panic(err)
	}
}

func main() {
	app := cli.NewApp()
	app.EnableBashCompletion = true
	app.Name = "amazon"
	app.Usage = "the CLI interface to amazon"
	app.Version = "0.1.1"

	app.Flags = []cli.Flag{
		cli.StringFlag{
			Name:   "locale, l",
			Value:  "",
			Usage:  "Amazon locale",
			EnvVar: "AMAZON_CLI_LOCALE",
		},
		cli.BoolFlag{
			Name:  "no-color",
			Usage: "disable colored output",
		},
	}

	app.Commands = []cli.Command{
		{
			Name:   "search",
			Usage:  "search for products",
			Action: actions.Search,
			Flags: []cli.Flag{
				cli.IntFlag{
					Name:  "page, p",
					Value: 1,
					Usage: "search results page",
				},
				cli.StringFlag{
					Name:  "sort, s",
					Value: "",
					Usage: "sort order",
				},
				cli.StringFlag{
					Name:  "index, i",
					Value: "All",
					Usage: "search index",
				},
				cli.BoolFlag{
					Name:  "no-rating",
					Usage: "disable fetching product ratings",
				},
			},
		},
		{
			Name:   "info",
			Usage:  "get product info",
			Action: actions.Info,
		},
		{
			Name:   "open",
			Usage:  "open product in browser",
			Action: actions.Open,
		},
		{
			Name:  "cart",
			Usage: "manage a cart",
			Subcommands: []cli.Command{
				{
					Name:   "add",
					Usage:  "add item to cart",
					Action: actions.CartAdd,
				},
				{
					Name:   "update",
					Usage:  "update item in cart",
					Action: actions.CartUpdate,
				},
				{
					Name:   "remove",
					Usage:  "remove item from cart",
					Action: actions.CartRemove,
				},
				{
					Name:   "info",
					Usage:  "list cart items",
					Action: actions.CartInfo,
				},
			},
		},
		{
			Name:  "carts",
			Usage: "manage carts",
			Subcommands: []cli.Command{
				{
					Name:   "list",
					Usage:  "list all active varts",
					Action: actions.CartsList,
				},
				{
					Name:   "destroy",
					Usage:  "delete a cart",
					Action: actions.CartsDestroy,
				},
			},
		},
		{
			Name:   "checkout",
			Usage:  "proceed to checkout",
			Action: actions.Checkout,
		},
		{
			Name:   "locale",
			Usage:  "manage locale",
			Action: actions.Locale,
		},
		{
			Name:   "locales",
			Usage:  "list available locales",
			Action: actions.LocalesList,
		},
	}

	app.Run(os.Args)
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"fmt"
	"os"
	"strings"
)

//types

//Question ...
type Question struct {
	Question  string
	YesTarget Target
	NoTarget  Target
}

//Target ...
type Target struct {
	Type  string
	Index int
}

//Data
var animals = []string{"Fish", "Bird"}

var questions = []Question{
	Question{
		Question:  "Does it swim",
		YesTarget: Target{Type: "", Index: 0},
		NoTarget:  Target{Type: "", Index: 1},
	},
}

var reader = bufio.NewReader(os.Stdin) //we'll be needing this

//funcs
func main() {

	playIntroMessage()

	run := true
	for run {

		//let's begin
		fmt.Println("Are you thinking of an animal?")

		switch strings.ToLower(getInput())[:1] {
		case "n": //No
			//Quit the game
			run = false
		case "l": //List
			//output the animal list and then ask again
			listKnownAnimals()
		case "y": //Yes
		default:
			fmt.Println("I don't recognise that command")
		}
	}
}

func playIntroMessage() {
	fmt.Println("Play 'Guess the Animal'")
	fmt.Println("Think of an animal and the computer will try to guess it...")
}

func listKnownAnimals() {
	fmt.Println("I know the following animals")
	for _, v := range animals {
		fmt.Println(v)
	}
}

func getInput() (input string) {
	input, _ = reader.ReadString('\n')
	return
}
<commit_msg>implemented askQuestion and guessAnimal. The game now works but won't learn new animals / questions yet.<commit_after>package main

import (
	"bufio"
	"fmt"
	"os"
	"strings"
)

//types

//Question ...
type Question struct {
	Question  string
	YesTarget Target
	NoTarget  Target
}

//Target ...
type Target struct {
	Type  string
	Index int
}

//Data
var animals = []string{"Fish", "Bird"}

var questions = []Question{
	Question{
		Question:  "Does it swim",
		YesTarget: Target{Type: "a", Index: 0},
		NoTarget:  Target{Type: "a", Index: 1},
	},
}

var reader = bufio.NewReader(os.Stdin) //we'll be needing this

//funcs
func main() {

	playIntroMessage()

	run := true
	for run {

		//let's begin
		fmt.Println("Are you thinking of an animal?")

		switch strings.ToLower(getInput())[:1] {
		case "n": //No
			//Quit the game
			run = false
		case "l": //List
			//output the animal list and then ask again
			listKnownAnimals()
		case "y": //Yes
			askQuestion(0)
		default:
			fmt.Println("I don't recognise that command")
		}
	}
}

func playIntroMessage() {
	fmt.Println("Play 'Guess the Animal'")
	fmt.Println("Think of an animal and the computer will try to guess it...")
}

func listKnownAnimals() {
	fmt.Println("Animals I already know are:")
	for _, v := range animals {
		fmt.Println(v)
	}
}

func askQuestion(i int) {
	var t *Target

	q := questions[i]

	for t == nil {
		fmt.Println(q.Question + "?")

		switch strings.ToLower(getInput())[:1] {
		case "n": //No
			t = &q.NoTarget
		case "y": //Yes
			t = &q.YesTarget
		default:
			fmt.Println("Please answer yes or no.")
		}
	}

	//ask a question or guess an animal
	if t.Type == "a" {
		guessAnimal(t.Index)
	} else {
		askQuestion(t.Index)
	}
}

func guessAnimal(i int) bool {
	for true {
		fmt.Println("Is " + animals[i] + " your animal?")

		switch strings.ToLower(getInput())[:1] {
		case "n": //No
			return false
		case "y": //Yes
			return true
		default:
			fmt.Println("Please answer yes or no.")
		}
	}

	//this is impossible to reach, as the loop is infinite unless return is triggered by a case
	//but golint wants a return statement
	return false
}

func getInput() (input string) {
	input, _ = reader.ReadString('\n')
	return
}
<|endoftext|>


<commit_before>// AnsiGo 1.00 (c) by Frederic Cambus 2012
// http://www.github.com/fcambus/ansigo
//
// Created:      2012/02/14
// Last Updated: 2012/02/19
//
// AnsiGo is released under the MIT license.
// See LICENSE file for details.
package main

import (
	"fmt"
	"image"
	"image/draw"
	"image/png"
	"io/ioutil"
	"os"
	"strconv"
	"strings"
)

func main() {

	fmt.Println("-------------------------------------------------------------------------------\n                    AnsiGo 1.00 (c) by Frederic CAMBUS 2012\n-------------------------------------------------------------------------------\n")

	// Check input parameters and show usage
	if len(os.Args) != 2 {
		fmt.Println("USAGE:    ansigo inputfile\n")
		fmt.Println("EXAMPLES: ansigo ansi.ans\n")
		os.Exit(1)
	}

	input := os.Args[1]
	output := input + ".png"

	fmt.Println("Input File:", input)
	fmt.Println("Output File:", output)

	var ansi Ansi
	ansi.SetPalette()
	ansi.SetFont()

	// Load input file
	data, err := ioutil.ReadFile(input)
	if err != nil {
		fmt.Println("\nERROR: Can't open or read", input, "\n")
		os.Exit(1)
	}

	// Process ANSI
	for i := 0; i < len(data); i++ {
		ansi.character = data[i]

		// 80th column wrapping
		if ansi.positionX == 80 {
			ansi.positionY++
			ansi.positionX = 0
		}

		// CR (Carriage Return)
		if ansi.character == '\r' {
			continue
		}

		// LF (Line Feed)
		if ansi.character == '\n' {
			ansi.positionY++
			ansi.positionX = 0
			continue
		}

		// HT (Horizontal Tabulation)
		if ansi.character == '\t' {
			ansi.positionX += 8
			continue
		}

		// SUB (Substitute)
		if ansi.character == '\x1a' {
			break
		}

		// ANSI Sequence : ESC (Escape) + [
		if ansi.character == '\x1b' && data[i+1] == '[' {
			ansiSequence := []byte{}

			for j := 0; j < 12; j++ {
				ansiSequenceCharacter := data[i+2+j]

				// Cursor Position
				if ansiSequenceCharacter == 'H' || ansiSequenceCharacter == 'f' {
					ansiSequenceValues := strings.SplitN(string(ansiSequence), ";", -1)

					valueY, _ := strconv.Atoi(ansiSequenceValues[0])
					ansi.positionY = valueY - 1

					valueX, _ := strconv.Atoi(ansiSequenceValues[1])
					ansi.positionX = valueX - 1

					i += j + 2
					break
				}

				// Cursor Up
				if ansiSequenceCharacter == 'A' {
					valueY, _ := strconv.Atoi(string(ansiSequence))
					if valueY == 0 {
						valueY++
					}

					ansi.positionY = ansi.positionY - valueY

					i += j + 2
					break
				}

				// Cursor Down
				if ansiSequenceCharacter == 'B' {
					valueY, _ := strconv.Atoi(string(ansiSequence))
					if valueY == 0 {
						valueY++
					}

					ansi.positionY = ansi.positionY + valueY

					i += j + 2
					break
				}

				// Cursor Forward
				if ansiSequenceCharacter == 'C' {
					valueX, _ := strconv.Atoi(string(ansiSequence))
					if valueX == 0 {
						valueX++
					}

					ansi.positionX = ansi.positionX + valueX
					if ansi.positionX > 80 {
						ansi.positionX = 80
					}

					i += j + 2
					break
				}

				// Cursor Backward
				if ansiSequenceCharacter == 'D' {
					valueX, _ := strconv.Atoi(string(ansiSequence))
					if valueX == 0 {
						valueX++
					}

					ansi.positionX = ansi.positionX - valueX
					if ansi.positionX < 0 {
						ansi.positionX = 0
					}

					i += j + 2
					break
				}

				// Save Cursor Position
				if ansiSequenceCharacter == 's' {
					ansi.savedPositionY = ansi.positionY
					ansi.savedPositionX = ansi.positionX

					i += j + 2
					break
				}

				// Restore Cursor Position
				if ansiSequenceCharacter == 'u' {
					ansi.positionY = ansi.savedPositionY
					ansi.positionX = ansi.savedPositionX

					i += j + 2
					break
				}

				// Erase Display
				if ansiSequenceCharacter == 'J' {
					value, _ := strconv.Atoi(string(ansiSequence))

					if value == 2 {
						ansi.buffer = nil

						ansi.positionX = 0
						ansi.positionY = 0
						ansi.sizeX = 0
						ansi.sizeY = 0
					}

					i += j + 2
					break
				}

				// Set Graphic Rendition
				if ansiSequenceCharacter == 'm' {
					ansiSequenceValues := strings.SplitN(string(ansiSequence), ";", -1)

					for j := 0; j < len(ansiSequenceValues); j++ {
						valueColor, _ := strconv.Atoi(ansiSequenceValues[j])

						switch valueColor {
						case 0:
							ansi.colorBackground = 0
							ansi.colorForeground = 7
							ansi.bold = false

						case 1:
							ansi.colorForeground += 8
							ansi.bold = true

						case 5:
							ansi.colorBackground += 8

						case 30, 31, 32, 33, 34, 35, 36, 37:
							ansi.colorForeground = valueColor - 30
							if ansi.bold {
								ansi.colorForeground += 8
							}

						case 40, 41, 42, 43, 44, 45, 46, 47:
							ansi.colorBackground = valueColor - 40
						}
					}

					i += j + 2
					break
				}

				ansiSequence = append(ansiSequence, ansiSequenceCharacter)
			}
		} else {
			// Record Number Of Columns And Lines Used
			if ansi.positionX > ansi.sizeX {
				ansi.sizeX = ansi.positionX
			}
			if ansi.positionY > ansi.sizeY {
				ansi.sizeY = ansi.positionY
			}

			// Write Current Character Info In A Temporary Array
			ansi.buffer = append(ansi.buffer, Character{ansi.colorBackground, ansi.colorForeground, ansi.positionX, ansi.positionY, ansi.character})

			ansi.positionX++
		}
	}

	// Allocate Image Buffer Memory
	canvasSize := image.Rect(0, 0, 640, (ansi.sizeY+1)*16)
	canvas := image.NewRGBA(canvasSize)

	// Draw The Canvas Background
	draw.Draw(canvas, canvas.Bounds(), &image.Uniform{ansi.palette[0]}, image.ZP, draw.Src)

	// Render ANSI
	for i := 0; i < len(ansi.buffer); i++ {
		character := ansi.buffer[i]

		// Set Background
		draw.Draw(canvas, image.Rect(character.positionX*8, character.positionY*16, character.positionX*8+8, character.positionY*16+16), &image.Uniform{ansi.palette[character.colorBackground]}, image.ZP, draw.Src)

		// Draw Character
		for line := 0; line < 16; line++ {
			for column := 0; column < 8; column++ {
				if (ansi.font[line+(int(character.code)*16)] & (0x80 >> uint(column))) != 0 {
					canvas.Set(character.positionX*8+column, line+character.positionY*16, ansi.palette[character.colorForeground])
				}
			}
		}
	}

	// Create Output File
	outputFile, err := os.Create(output)
	if err != nil {
		fmt.Println("ERROR: Can't create ouput file.")
		os.Exit(1)
	}

	// Encode PNG image
	if err = png.Encode(outputFile, canvas); err != nil {
		fmt.Println("ERROR: Can't encode PNG file.")
		os.Exit(1)
	}

	outputFile.Close()

	fmt.Println("\nSuccessfully created file", output, "\n")
}
<commit_msg>Skipping 'Set mode' and 'Reset mode' sequences<commit_after>// AnsiGo 1.00 (c) by Frederic Cambus 2012
// http://www.github.com/fcambus/ansigo
//
// Created:      2012/02/14
// Last Updated: 2012/02/19
//
// AnsiGo is released under the MIT license.
// See LICENSE file for details.
package main

import (
	"fmt"
	"image"
	"image/draw"
	"image/png"
	"io/ioutil"
	"os"
	"strconv"
	"strings"
)

func main() {

	fmt.Println("-------------------------------------------------------------------------------\n                    AnsiGo 1.00 (c) by Frederic CAMBUS 2012\n-------------------------------------------------------------------------------\n")

	// Check input parameters and show usage
	if len(os.Args) != 2 {
		fmt.Println("USAGE:    ansigo inputfile\n")
		fmt.Println("EXAMPLES: ansigo ansi.ans\n")
		os.Exit(1)
	}

	input := os.Args[1]
	output := input + ".png"

	fmt.Println("Input File:", input)
	fmt.Println("Output File:", output)

	var ansi Ansi
	ansi.SetPalette()
	ansi.SetFont()

	// Load input file
	data, err := ioutil.ReadFile(input)
	if err != nil {
		fmt.Println("\nERROR: Can't open or read", input, "\n")
		os.Exit(1)
	}

	// Process ANSI
	for i := 0; i < len(data); i++ {
		ansi.character = data[i]

		// 80th column wrapping
		if ansi.positionX == 80 {
			ansi.positionY++
			ansi.positionX = 0
		}

		// CR (Carriage Return)
		if ansi.character == '\r' {
			continue
		}

		// LF (Line Feed)
		if ansi.character == '\n' {
			ansi.positionY++
			ansi.positionX = 0
			continue
		}

		// HT (Horizontal Tabulation)
		if ansi.character == '\t' {
			ansi.positionX += 8
			continue
		}

		// SUB (Substitute)
		if ansi.character == '\x1a' {
			break
		}

		// ANSI Sequence : ESC (Escape) + [
		if ansi.character == '\x1b' && data[i+1] == '[' {
			ansiSequence := []byte{}

			for j := 0; j < 12; j++ {
				ansiSequenceCharacter := data[i+2+j]

				// Cursor Position
				if ansiSequenceCharacter == 'H' || ansiSequenceCharacter == 'f' {
					ansiSequenceValues := strings.SplitN(string(ansiSequence), ";", -1)

					valueY, _ := strconv.Atoi(ansiSequenceValues[0])
					ansi.positionY = valueY - 1

					valueX, _ := strconv.Atoi(ansiSequenceValues[1])
					ansi.positionX = valueX - 1

					i += j + 2
					break
				}

				// Cursor Up
				if ansiSequenceCharacter == 'A' {
					valueY, _ := strconv.Atoi(string(ansiSequence))
					if valueY == 0 {
						valueY++
					}

					ansi.positionY = ansi.positionY - valueY

					i += j + 2
					break
				}

				// Cursor Down
				if ansiSequenceCharacter == 'B' {
					valueY, _ := strconv.Atoi(string(ansiSequence))
					if valueY == 0 {
						valueY++
					}

					ansi.positionY = ansi.positionY + valueY

					i += j + 2
					break
				}

				// Cursor Forward
				if ansiSequenceCharacter == 'C' {
					valueX, _ := strconv.Atoi(string(ansiSequence))
					if valueX == 0 {
						valueX++
					}

					ansi.positionX = ansi.positionX + valueX
					if ansi.positionX > 80 {
						ansi.positionX = 80
					}

					i += j + 2
					break
				}

				// Cursor Backward
				if ansiSequenceCharacter == 'D' {
					valueX, _ := strconv.Atoi(string(ansiSequence))
					if valueX == 0 {
						valueX++
					}

					ansi.positionX = ansi.positionX - valueX
					if ansi.positionX < 0 {
						ansi.positionX = 0
					}

					i += j + 2
					break
				}

				// Save Cursor Position
				if ansiSequenceCharacter == 's' {
					ansi.savedPositionY = ansi.positionY
					ansi.savedPositionX = ansi.positionX

					i += j + 2
					break
				}

				// Restore Cursor Position
				if ansiSequenceCharacter == 'u' {
					ansi.positionY = ansi.savedPositionY
					ansi.positionX = ansi.savedPositionX

					i += j + 2
					break
				}

				// Erase Display
				if ansiSequenceCharacter == 'J' {
					value, _ := strconv.Atoi(string(ansiSequence))

					if value == 2 {
						ansi.buffer = nil

						ansi.positionX = 0
						ansi.positionY = 0
						ansi.sizeX = 0
						ansi.sizeY = 0
					}

					i += j + 2
					break
				}

				// Set Graphic Rendition
				if ansiSequenceCharacter == 'm' {
					ansiSequenceValues := strings.SplitN(string(ansiSequence), ";", -1)

					for j := 0; j < len(ansiSequenceValues); j++ {
						valueColor, _ := strconv.Atoi(ansiSequenceValues[j])

						switch valueColor {
						case 0:
							ansi.colorBackground = 0
							ansi.colorForeground = 7
							ansi.bold = false

						case 1:
							ansi.colorForeground += 8
							ansi.bold = true

						case 5:
							ansi.colorBackground += 8

						case 30, 31, 32, 33, 34, 35, 36, 37:
							ansi.colorForeground = valueColor - 30
							if ansi.bold {
								ansi.colorForeground += 8
							}

						case 40, 41, 42, 43, 44, 45, 46, 47:
							ansi.colorBackground = valueColor - 40
						}
					}

					i += j + 2
					break
				}

				// Skipping Set Mode And Reset Mode Sequences
				if ansiSequenceCharacter == 'h' || ansiSequenceCharacter == 'l' {

					i += j + 2
					break
				}

				ansiSequence = append(ansiSequence, ansiSequenceCharacter)
			}
		} else {
			// Record Number Of Columns And Lines Used
			if ansi.positionX > ansi.sizeX {
				ansi.sizeX = ansi.positionX
			}
			if ansi.positionY > ansi.sizeY {
				ansi.sizeY = ansi.positionY
			}

			// Write Current Character Info In A Temporary Array
			ansi.buffer = append(ansi.buffer, Character{ansi.colorBackground, ansi.colorForeground, ansi.positionX, ansi.positionY, ansi.character})

			ansi.positionX++
		}
	}

	// Allocate Image Buffer Memory
	canvasSize := image.Rect(0, 0, 640, (ansi.sizeY+1)*16)
	canvas := image.NewRGBA(canvasSize)

	// Draw The Canvas Background
	draw.Draw(canvas, canvas.Bounds(), &image.Uniform{ansi.palette[0]}, image.ZP, draw.Src)

	// Render ANSI
	for i := 0; i < len(ansi.buffer); i++ {
		character := ansi.buffer[i]

		// Set Background
		draw.Draw(canvas, image.Rect(character.positionX*8, character.positionY*16, character.positionX*8+8, character.positionY*16+16), &image.Uniform{ansi.palette[character.colorBackground]}, image.ZP, draw.Src)

		// Draw Character
		for line := 0; line < 16; line++ {
			for column := 0; column < 8; column++ {
				if (ansi.font[line+(int(character.code)*16)] & (0x80 >> uint(column))) != 0 {
					canvas.Set(character.positionX*8+column, line+character.positionY*16, ansi.palette[character.colorForeground])
				}
			}
		}
	}

	// Create Output File
	outputFile, err := os.Create(output)
	if err != nil {
		fmt.Println("ERROR: Can't create ouput file.")
		os.Exit(1)
	}

	// Encode PNG image
	if err = png.Encode(outputFile, canvas); err != nil {
		fmt.Println("ERROR: Can't encode PNG file.")
		os.Exit(1)
	}

	outputFile.Close()

	fmt.Println("\nSuccessfully created file", output, "\n")
}
<|endoftext|>


<commit_before>package data

import (
	"fmt"
	"net/http"

	"github.com/cozy/cozy-stack/pkg/consts"
	"github.com/labstack/echo"
)

var readable = true
var none = false

var blackList = map[string]bool{
	consts.Sessions:         none,
	consts.Permissions:      none,
	consts.OAuthClients:     none,
	consts.OAuthAccessCodes: none,
	consts.Files:            readable,
	consts.Instances:        readable,
}

// CheckReadable will abort the context and returns false if the doctype
// is unreadable
func CheckReadable(doctype string) error {
	readable, inblacklist := blackList[doctype]
	if !inblacklist || readable {
		return nil
	}

	return &echo.HTTPError{
		Code:    http.StatusForbidden,
		Message: fmt.Sprintf("reserved doctype %s unreadable", doctype),
	}
}

// CheckWritable will abort the echo context if the doctype
// is unwritable
func CheckWritable(doctype string) error {
	_, inblacklist := blackList[doctype]
	if !inblacklist {
		return nil
	}

	return &echo.HTTPError{
		Code:    http.StatusForbidden,
		Message: fmt.Sprintf("reserved doctype %s unwritable", doctype),
	}
}
<commit_msg>Update the /data blacklist<commit_after>package data

import (
	"fmt"
	"net/http"

	"github.com/cozy/cozy-stack/pkg/consts"
	"github.com/labstack/echo"
)

var readable = true
var none = false

var blackList = map[string]bool{
	consts.Instances:        none,
	consts.Sessions:         none,
	consts.Permissions:      none,
	consts.Intents:          none,
	consts.OAuthClients:     none,
	consts.OAuthAccessCodes: none,
	consts.Archives:         none,
	consts.Recipients:       none,
	consts.Sharings:         none,
	consts.Apps:             readable,
	consts.Konnectors:       readable,
	consts.Files:            readable,
	consts.Jobs:             readable,
	consts.Queues:           readable,
	consts.Triggers:         readable,
}

// CheckReadable will abort the context and returns false if the doctype
// is unreadable
func CheckReadable(doctype string) error {
	readable, inblacklist := blackList[doctype]
	if !inblacklist || readable {
		return nil
	}

	return &echo.HTTPError{
		Code:    http.StatusForbidden,
		Message: fmt.Sprintf("reserved doctype %s unreadable", doctype),
	}
}

// CheckWritable will abort the echo context if the doctype
// is unwritable
func CheckWritable(doctype string) error {
	_, inblacklist := blackList[doctype]
	if !inblacklist {
		return nil
	}

	return &echo.HTTPError{
		Code:    http.StatusForbidden,
		Message: fmt.Sprintf("reserved doctype %s unwritable", doctype),
	}
}
<|endoftext|>


<commit_before>package cloudstack

type Zone struct {
	ResourceBase
	// the allocation state of the cluster
	AllocationState NullString `json:"allocationstate"`
	// the capacity of the Zone
	Capacity []Capacity `json:"capacity"`
	// Zone description
	Description NullString `json:"description"`
	// the dhcp Provider for the Zone
	DhcpProvider NullString `json:"dhcpprovider"`
	// the display text of the zone
	DisplayText NullString `json:"displaytext"`
	// the first DNS for the Zone
	Dns1 NullString `json:"dns1"`
	// the second DNS for the Zone
	Dns2 NullString `json:"dns2"`
	// Network domain name for the networks in the zone
	Domain NullString `json:"domain"`
	// the UUID of the containing domain, null for public zones
	DomainId ID `json:"domainid"`
	// the name of the containing domain, null for public zones
	DomainName NullString `json:"domainname"`
	// the guest CIDR address for the Zone
	GuestCidrAddress NullString `json:"guestcidraddress"`
	// Zone id
	Id ID `json:"id"`
	// the first internal DNS for the Zone
	InternalDns1 NullString `json:"internaldns1"`
	// the second internal DNS for the Zone
	InternalDns2 NullString `json:"internaldns2"`
	// the first IPv6 DNS for the Zone
	Ip6Dns1 NullString `json:"ip6dns1"`
	// the second IPv6 DNS for the Zone
	Ip6Dns2 NullString `json:"ip6dns2"`
	// true if local storage offering enabled, false otherwise
	LocalStorageEnabled NullBool `json:"localstorageenabled"`
	// Zone name
	Name NullString `json:"name"`
	// the network type of the zone; can be Basic or Advanced
	NetworkType NullString `json:"networktype"`
	// Meta data associated with the zone (key/value pairs)
	ResourceDetails NullString `json:"resourcedetails"`
	// true if security groups support is enabled, false otherwise
	SecurityGroupsEnabled NullBool `json:"securitygroupsenabled"`
	// the list of resource tags associated with zone.
	Tags []Tag `json:"tags"`
	// the vlan range of the zone
	Vlan NullString `json:"vlan"`
	// Zone Token
	Zonetoken NullString `json:"zonetoken"`
}
<commit_msg>update zone struct<commit_after>package cloudstack

type Zone struct {
	ResourceBase
	// the allocation state of the cluster
	AllocationState NullString `json:"allocationstate"`
	// the capacity of the Zone
	Capacity []Capacity `json:"capacity"`
	// Zone description
	Description NullString `json:"description"`
	// the dhcp Provider for the Zone
	DhcpProvider NullString `json:"dhcpprovider"`
	// the display text of the zone
	DisplayText NullString `json:"displaytext"`
	// the first DNS for the Zone
	Dns1 NullString `json:"dns1"`
	// the second DNS for the Zone
	Dns2 NullString `json:"dns2"`
	// Network domain name for the networks in the zone
	Domain NullString `json:"domain"`
	// the UUID of the containing domain, null for public zones
	DomainId ID `json:"domainid"`
	// the name of the containing domain, null for public zones
	DomainName NullString `json:"domainname"`
	// the guest CIDR address for the Zone
	GuestCidrAddress NullString `json:"guestcidraddress"`
	// Zone id
	Id ID `json:"id"`
	// the first internal DNS for the Zone
	InternalDns1 NullString `json:"internaldns1"`
	// the second internal DNS for the Zone
	InternalDns2 NullString `json:"internaldns2"`
	// the first IPv6 DNS for the Zone
	Ip6Dns1 NullString `json:"ip6dns1"`
	// the second IPv6 DNS for the Zone
	Ip6Dns2 NullString `json:"ip6dns2"`
	// true if local storage offering enabled, false otherwise
	LocalStorageEnabled NullBool `json:"localstorageenabled"`
	// Zone name
	Name NullString `json:"name"`
	// the network type of the zone; can be Basic or Advanced
	NetworkType NullString `json:"networktype"`
	// Meta data associated with the zone (key/value pairs)
	ResourceDetails map[string]string `json:"resourcedetails"`
	// true if security groups support is enabled, false otherwise
	SecurityGroupsEnabled NullBool `json:"securitygroupsenabled"`
	// the list of resource tags associated with zone.
	Tags []Tag `json:"tags"`
	// the vlan range of the zone
	Vlan NullString `json:"vlan"`
	// Zone Token
	Zonetoken NullString `json:"zonetoken"`
}
<|endoftext|>


<commit_before>package main

import (
	hpack "github.com/ami-GS/GoHPACK"
	http2 "github.com/ami-GS/simpleHTTP2"
	"os"
	"time"
)

func main() {
	args := os.Args[1:]
	var client http2.Connection
	if len(args) == 2 {
		client = http2.Connect(args[0] + ":" + args[1])
	} else {
		client = http2.Connect("127.0.0.1:8080")
	}
	go client.RunReceiver()
	client.Send(http2.NewSettings(http2.NO_SETTING, 0, http2.NO))
	time.Sleep(time.Second)
	headers := []hpack.Header{hpack.Header{":method", "GET"}, hpack.Header{":scheme", "http"},
		hpack.Header{":authority", "127.0.0.1"}, hpack.Header{":path", "/"}}
	client.Send(http2.NewHeaders(headers, &client.Table, 1, http2.END_HEADERS, 0, 0, false, 0))
	time.Sleep(time.Second)
	client.Send(http2.NewPriority(1, false, 1, 5))
	time.Sleep(time.Second)
	client.Send(http2.NewPing("aiue", http2.NO))
	time.Sleep(time.Second)
	client.Send(http2.NewGoAway(1, http2.NO_ERROR, "DEBUG string!!"))
}
<commit_msg>change the type of connection when it is created<commit_after>package main

import (
	hpack "github.com/ami-GS/GoHPACK"
	http2 "github.com/ami-GS/simpleHTTP2"
	"os"
	"time"
)

func main() {
	args := os.Args[1:]
	var client *http2.Connection
	if len(args) == 2 {
		client = http2.Connect(args[0] + ":" + args[1])
	} else {
		client = http2.Connect("127.0.0.1:8080")
	}
	go client.RunReceiver()
	client.Send(http2.NewSettings(http2.NO_SETTING, 0, http2.NO))
	time.Sleep(time.Second)
	headers := []hpack.Header{hpack.Header{":method", "GET"}, hpack.Header{":scheme", "http"},
		hpack.Header{":authority", "127.0.0.1"}, hpack.Header{":path", "/"}}
	client.Send(http2.NewHeaders(headers, &client.Table, 1, http2.END_HEADERS, 0, 0, false, 0))
	time.Sleep(time.Second)
	client.Send(http2.NewPriority(1, false, 1, 5))
	time.Sleep(time.Second)
	client.Send(http2.NewPing("aiue", http2.NO))
	time.Sleep(time.Second)
	client.Send(http2.NewGoAway(1, http2.NO_ERROR, "DEBUG string!!"))
}
<|endoftext|>


<commit_before>// Middleware contains the drivers for the various services Cassabon leverages.
package middleware

import "github.com/gocql/gocql"

// Returns a round-robin simple connection pool to the Cassandra cluster.
func CassandraSession(chost string, cport int, ckeyspace string) *gocql.Session {
	// Retrieve cluster configuration.
	cass := gocql.NewCluster(chost)

	// Set port and host discovery.
	cass.Port = cport
	cass.DiscoverHosts = true

	// Set the metrics keyspace (default: "cassabon")
	cass.Keyspace = ckeyspace

	// Create session
	csession, _ := cluster.CreateSession()

	// Defer closing
	defer csession.Close()

	// And return the session.
	return &csession()
}
<commit_msg>Fixed return on cassandra middleware.<commit_after>// Middleware contains the drivers for the various services Cassabon leverages.
package middleware

import "github.com/gocql/gocql"

// Returns a round-robin simple connection pool to the Cassandra cluster.
func CassandraSession(chosts []string, cport int, ckeyspace string) *gocql.Session {
	// Retrieve cluster configuration.
	cass := gocql.NewCluster(chost)

	// Set port and host discovery.
	cass.Port = cport
	cass.DiscoverHosts = true

	// Set the metrics keyspace (default: "cassabon")
	cass.Keyspace = ckeyspace

	// Create session
	csession, _ := cluster.CreateSession()

	// Defer closing
	defer csession.Close()

	// And return the session.
	return csession
}
<|endoftext|>


<commit_before>package main

import (
	"log"
	"os"
	"path"

	fsevents "github.com/tywkeene/go-fsevents"
)

func handleEvents(watcher *fsevents.Watcher) {
	watcher.StartAll()
	go watcher.Watch()
	log.Println("Waiting for events...")
	for {
		select {
		case event := <-watcher.Events:
			log.Printf("Event Name: %s Event Path: %s", event.Name, event.Path)

			// Root watch directory was deleted, panic
			log.Printf("Watcher %s event %s", watcher.RootPath, event.Path)
			if event.IsRootDeletion(watcher.RootPath) == true {
				panic("Root watch directory deleted!")
			}

			// Directory events
			if event.IsDirCreated() == true {
				log.Println("Directory created:", path.Clean(event.Path))
				if err := watcher.AddDescriptor(path.Clean(event.Path), 0); err != nil {
					panic(err)
				} else {
					// When a new dir is created, we need to add it to the descriptors list and start it
					descriptor := watcher.GetDescriptorByPath(path.Clean(event.Path))
					descriptor.Start(watcher.FileDescriptor)
					log.Printf("Watch descriptor created and started for %s", event.Path)
				}
			}
			if event.IsDirRemoved() == true {
				log.Println("Directory removed:", path.Clean(event.Path))
				if err := watcher.RemoveDescriptor(path.Clean(event.Path)); err != nil {
					panic(err)
				} else {
					log.Printf("Watch descriptor removed for %s", event.Path)
				}
			}
			if event.IsDirChanged() == true {
				log.Println("Directory changed: ", event.Name)
			}

			// File events
			if event.IsFileCreated() == true {
				log.Println("File created: ", event.Name)
			}
			if event.IsFileRemoved() == true {
				log.Println("File removed: ", event.Name)
			}
			if event.IsFileChanged() == true {
				log.Println("File changed: ", event.Name)
			}
			break
		case err := <-watcher.Errors:
			log.Println(err)
			break
		}
	}
}

func main() {
	if len(os.Args) == 1 {
		panic("Must specify directory to watch")
	}
	watchDir := os.Args[1]

	options := &fsevents.WatcherOptions{
		// Recursive flag will make a watcher recursive,
		// meaning it will go all the way down the directory
		// tree, and add descriptors for all directories it finds
		Recursive: true,
		// UseWatcherFlags will use the flag passed to NewWatcher()
		// for all subsequently created watch descriptors
		UseWatcherFlags: true,
	}

	// You might need to play with these flags to get the events you want
	// You can use these pre-defined flags that are declared in fsevents.go,
	// or the original inotify flags declared in the golang.org/x/sys/unix package
	inotifyFlags := fsevents.DirCreatedEvent | fsevents.DirRemovedEvent |
		fsevents.FileCreatedEvent | fsevents.FileRemovedEvent |
		fsevents.FileChangedEvent | fsevents.RootEvent

	w, err := fsevents.NewWatcher(watchDir, inotifyFlags, options)
	if err != nil {
		panic(err)
	}
	handleEvents(w)
}
<commit_msg>Updated example code<commit_after>package main

import (
	"log"
	"os"
	"path"

	fsevents "github.com/tywkeene/go-fsevents"
)

func handleEvents(watcher *fsevents.Watcher) {
	watcher.StartAll()
	go watcher.Watch()
	log.Println("Waiting for events...")
	for {
		select {
		case event := <-watcher.Events:
			log.Printf("Event Name: %s Event Path: %s Event Descriptor: %v", event.Name, event.Path, event.Descriptor)
			log.Println("Watcher Event Count:", watcher.GetEventCount())
			log.Println("Running descriptors:", watcher.GetRunningDescriptors())

			if event.IsDirCreated() == true {
				log.Println("Directory created:", path.Clean(event.Path))
				watcher.AddDescriptor(path.Clean(event.Path), 0)
				descriptor := watcher.GetDescriptorByPath(path.Clean(event.Path))
				descriptor.Start(watcher.FileDescriptor)
			}
			if event.IsDirRemoved() == true {
				log.Println("Directory removed:", path.Clean(event.Path))
				watcher.RemoveDescriptor(path.Clean(event.Path))
			}

			if event.IsFileCreated() == true {
				log.Println("File created: ", event.Name)
			}
			if event.IsFileRemoved() == true {
				log.Println("File removed: ", event.Name)
			}
			break

			break
		case err := <-watcher.Errors:
			log.Println(err)
			break
		}
	}
}

func main() {
	if len(os.Args) == 1 {
		panic("Must specify directory to watch")
	}
	watchDir := os.Args[1]

	options := &fsevents.WatcherOptions{
		// Recursive flag will make a watcher recursive,
		// meaning it will go all the way down the directory
		// tree, and add descriptors for all directories it finds
		Recursive: true,
		// UseWatcherFlags will use the flag passed to NewWatcher()
		// for all subsequently created watch descriptors
		UseWatcherFlags: true,
	}

	// You might need to play with these flags to get the events you want
	// You can use these pre-defined flags that are declared in fsevents.go,
	// or the original inotify flags declared in the golang.org/x/sys/unix package
	inotifyFlags := fsevents.DirCreatedEvent | fsevents.DirRemovedEvent |
		fsevents.FileCreatedEvent | fsevents.FileRemovedEvent |
		fsevents.FileChangedEvent | fsevents.RootEvent

	w, err := fsevents.NewWatcher(watchDir, inotifyFlags, options)
	if err != nil {
		panic(err)
	}
	handleEvents(w)
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"

	"github.com/bradfitz/iter"
	"github.com/jeremyschlatter/godebug"
)

var main_goScope = godebug.EnteringNewScope()

func main() {
	godebugScope := main_goScope.EnteringNewChildScope()
	godebug.Line()
	x := mul(1, 2)
	godebugScope.Declare("x", &x)
	godebug.SetTrace()
	godebug.Line()
	x = mul(x, x)
	godebug.Line()
	if x == 4 {
		godebug.Line()
		fmt.Println("It works! x == 4.")
	} else if n := func() int {
		godebug.ElseIfSimpleStmt("} else if n := 2; n == 3 {")
		return 2
	}(); func() bool {
		godebug.ElseIfExpr("} else if n := 2; n == 3 {")
		return n == 3
	}() {
		godebug.Line()
		fmt.Println("Math is broken. Run.")
	} else {
		godebug.SLine("} else {")
		godebug.Line()
		fmt.Println("What's going on? x ==", x)
	}
}

func add(n, m int) int {
	godebug.EnterFunc()
	defer godebug.ExitFunc()
	godebugScope := main_goScope.EnteringNewChildScope()
	defer godebugScope.End()
	godebugScope.Declare("n", &n, "m", &m)
	godebug.Line()
	if n == 0 {
		godebug.Line()
		return m
	}
	godebug.Line()
	if m == 0 {
		godebug.Line()
		return n
	}
	godebug.Line()
	return n + m
}

func mul(n, m int) int {
	godebug.EnterFunc()
	defer godebug.ExitFunc()
	godebugScope := main_goScope.EnteringNewChildScope()
	defer godebugScope.End()
	godebugScope.Declare("n", &n, "m", &m)
	godebug.Line()
	var x int
	godebugScope.Declare("x", &x)
	godebug.Line()
	for range iter.N(m) {
		godebug.Line()
		x = add(x, m)
		godebug.SLine("for range iter.N(m) {")
	}
	godebug.Line()
	return x
}
<commit_msg>example: do not declare scope until just before it is needed, remove minor optimization for main.main<commit_after>package main

import (
	"fmt"

	"github.com/bradfitz/iter"
	"github.com/jeremyschlatter/godebug"
)

var main_goScope = godebug.EnteringNewScope()

func main() {
	godebug.Line()
	x := mul(1, 2)
	godebugScope := main_goScope.EnteringNewChildScope()
	defer godebugScope.End()
	godebugScope.Declare("x", &x)
	godebug.SetTrace()
	godebug.Line()
	x = mul(x, x)
	godebug.Line()
	if x == 4 {
		godebug.Line()
		fmt.Println("It works! x == 4.")
	} else if n := func() int {
		godebug.ElseIfSimpleStmt("} else if n := 2; n == 3 {")
		return 2
	}(); func() bool {
		godebug.ElseIfExpr("} else if n := 2; n == 3 {")
		return n == 3
	}() {
		godebug.Line()
		fmt.Println("Math is broken. Run.")
	} else {
		godebug.SLine("} else {")
		godebug.Line()
		fmt.Println("What's going on? x ==", x)
	}
}

func add(n, m int) int {
	godebug.EnterFunc()
	defer godebug.ExitFunc()
	godebugScope := main_goScope.EnteringNewChildScope()
	defer godebugScope.End()
	godebugScope.Declare("n", &n, "m", &m)
	godebug.Line()
	if n == 0 {
		godebug.Line()
		return m
	}
	godebug.Line()
	if m == 0 {
		godebug.Line()
		return n
	}
	godebug.Line()
	return n + m
}

func mul(n, m int) int {
	godebug.EnterFunc()
	defer godebug.ExitFunc()
	godebugScope := main_goScope.EnteringNewChildScope()
	defer godebugScope.End()
	godebugScope.Declare("n", &n, "m", &m)
	godebug.Line()
	var x int
	godebugScope.Declare("x", &x)
	godebug.Line()
	for range iter.N(m) {
		godebug.Line()
		x = add(x, m)
		godebug.SLine("for range iter.N(m) {")
	}
	godebug.Line()
	return x
}
<|endoftext|>


<commit_before>package output

import (
	"time"

	"github.com/Shopify/sarama"
	"github.com/funkygao/dbus/engine"
	"github.com/funkygao/dbus/plugins/input/myslave"
	"github.com/funkygao/gafka/ctx"
	"github.com/funkygao/gafka/zk"
	conf "github.com/funkygao/jsconf"
	log "github.com/funkygao/log4go"
)

type KafkaOutput struct {
	zone, cluster, topic string

	zkzone  *zk.ZkZone
	myslave *myslave.MySlave
}

func (this *KafkaOutput) Init(config *conf.Conf) {
	this.zone = config.String("zone", "")
	this.cluster = config.String("cluster", "")
	this.topic = config.String("topic", "")
	if this.cluster == "" || this.zone == "" || this.topic == "" {
		panic("invalid configuration")
	}

	this.zkzone = zk.NewZkZone(zk.DefaultConfig(this.zone, ctx.ZoneZkAddrs(this.zone)))
	this.myslave = myslave.New().LoadConfig(config)
}

func (this *KafkaOutput) Run(r engine.OutputRunner, h engine.PluginHelper) error {
	// TODO async producer and SLA
	cf := sarama.NewConfig()
	cf.Producer.RequiredAcks = sarama.WaitForLocal
	p, err := sarama.NewSyncProducer(this.zkzone.NewCluster(this.cluster).BrokerList(), cf)
	if err != nil {
		return err
	}
	defer p.Close()

	var (
		partition int32
		offset    int64
	)
	for {
		select {
		case pack, ok := <-r.InChan():
			if !ok {
				return nil
			}

			row, ok := pack.Payload.(*myslave.RowsEvent)
			if !ok {
				log.Error("wrong payload: %+v", pack.Payload)
				continue
			}

			for {
				if partition, offset, err = p.SendMessage(&sarama.ProducerMessage{
					Topic: this.topic,
					Value: sarama.ByteEncoder(row.Bytes()),
				}); err == nil {
					break
				}

				log.Error("%s.%s.%s {%s} %v", this.zone, this.cluster, this.topic, row, err)
				time.Sleep(time.Second)
			}

			if err = this.myslave.MarkAsProcessed(row); err != nil {
				log.Warn("%s.%s.%s {%s} %v", this.zone, this.cluster, this.topic, row, err)
			}

			log.Debug("%d/%d %s", partition, offset, row)

			pack.Recycle()
		}
	}

	return nil
}

func init() {
	engine.RegisterPlugin("KafkaOutput", func() engine.Plugin {
		return new(KafkaOutput)
	})
}
<commit_msg>FIXME<commit_after>package output

import (
	"time"

	"github.com/Shopify/sarama"
	"github.com/funkygao/dbus/engine"
	"github.com/funkygao/dbus/plugins/input/myslave"
	"github.com/funkygao/gafka/ctx"
	"github.com/funkygao/gafka/zk"
	conf "github.com/funkygao/jsconf"
	log "github.com/funkygao/log4go"
)

type KafkaOutput struct {
	zone, cluster, topic string

	zkzone *zk.ZkZone
	// FIXME should be shared with MysqlbinlogInput
	// currently, KafkaOutput MUST setup master_host/master_port to correctly checkpoint position
	myslave *myslave.MySlave
}

func (this *KafkaOutput) Init(config *conf.Conf) {
	this.zone = config.String("zone", "")
	this.cluster = config.String("cluster", "")
	this.topic = config.String("topic", "")
	if this.cluster == "" || this.zone == "" || this.topic == "" {
		panic("invalid configuration")
	}

	this.zkzone = zk.NewZkZone(zk.DefaultConfig(this.zone, ctx.ZoneZkAddrs(this.zone)))
	this.myslave = myslave.New().LoadConfig(config)
}

func (this *KafkaOutput) Run(r engine.OutputRunner, h engine.PluginHelper) error {
	// TODO async producer and SLA
	cf := sarama.NewConfig()
	cf.Producer.RequiredAcks = sarama.WaitForLocal
	p, err := sarama.NewSyncProducer(this.zkzone.NewCluster(this.cluster).BrokerList(), cf)
	if err != nil {
		return err
	}
	defer p.Close()

	var (
		partition int32
		offset    int64
	)
	for {
		select {
		case pack, ok := <-r.InChan():
			if !ok {
				return nil
			}

			row, ok := pack.Payload.(*myslave.RowsEvent)
			if !ok {
				log.Error("wrong payload: %+v", pack.Payload)
				continue
			}

			for {
				if partition, offset, err = p.SendMessage(&sarama.ProducerMessage{
					Topic: this.topic,
					Value: sarama.ByteEncoder(row.Bytes()),
				}); err == nil {
					break
				}

				log.Error("%s.%s.%s {%s} %v", this.zone, this.cluster, this.topic, row, err)
				time.Sleep(time.Second)
			}

			if err = this.myslave.MarkAsProcessed(row); err != nil {
				log.Warn("%s.%s.%s {%s} %v", this.zone, this.cluster, this.topic, row, err)
			}

			log.Debug("%d/%d %s", partition, offset, row)

			pack.Recycle()
		}
	}

	return nil
}

func init() {
	engine.RegisterPlugin("KafkaOutput", func() engine.Plugin {
		return new(KafkaOutput)
	})
}
<|endoftext|>


<commit_before>package tcp

import (
	"errors"
	"math/rand"
	"net"
	"sort"
	"sync"
	"time"

	"github.com/vektra/cypress"
)

type TCPSend struct {
	hosts  []string
	window int
	c      net.Conn
	s      *cypress.Send

	lock        sync.Mutex
	outstanding int

	newMessages chan *cypress.Message
	closed      chan bool

	shutdown bool

	nacked cypress.Messages
}

const DefaultTCPBuffer = 128

func NewTCPSend(hosts []string, window, buffer int) (*TCPSend, error) {
	tcp := &TCPSend{
		hosts:       hosts,
		window:      window,
		newMessages: make(chan *cypress.Message, buffer),
		closed:      make(chan bool, 1),
	}

	err := tcp.Connect()
	if err != nil {
		return nil, err
	}

	go tcp.drain()

	return tcp, nil
}

var ErrNoAvailableHosts = errors.New("no available hosts")

func shuffle(a []string) {
	for i := range a {
		j := rand.Intn(i + 1)
		a[i], a[j] = a[j], a[i]
	}
}

func (t *TCPSend) Connect() error {
	shuffle(t.hosts)

	for _, host := range t.hosts {
		c, err := net.Dial("tcp", host)
		if err != nil {
			continue
		}

		s := cypress.NewSend(c, t.window)
		err = s.SendHandshake()
		if err != nil {
			c.Close()
			continue
		}

		t.c = c
		t.s = s

		s.OnClosed = t.onClosed

		return nil
	}

	return ErrNoAvailableHosts
}

func (t *TCPSend) Close() error {
	t.shutdown = true
	return t.c.Close()
}

func (t *TCPSend) Ack(m *cypress.Message) {
	t.lock.Lock()
	defer t.lock.Unlock()

	t.outstanding--
}

func (t *TCPSend) Nack(m *cypress.Message) {
	t.lock.Lock()
	defer t.lock.Unlock()

	t.outstanding--
	t.nacked = append(t.nacked, m)
}

func (t *TCPSend) onClosed() {
	t.closed <- true
}

func (t *TCPSend) reconnect() {
	t.lock.Lock()

	var err error

	t.c.Close()

	for {
		err = t.Connect()
		if err != nil {
			if t.shutdown {
				t.lock.Unlock()
				return
			}

			time.Sleep(1 * time.Second)
			continue
		}

		break
	}

	nacked := t.nacked
	t.nacked = nil

	t.lock.Unlock()

	for idx, msg := range nacked {
		t.outstanding++
		err = t.s.Send(msg, t)
		if err != nil {
			t.lock.Lock()
			t.nacked = append(nacked[idx+1:], t.nacked...)
			sort.Sort(t.nacked)

			// don't retry here because the OnClose handler will
			// prime the closed channel, so we return from here, pick
			// up the value from the channel, then this is called again.
			t.lock.Unlock()
			return
		}
	}
}

func (t *TCPSend) Receive(m *cypress.Message) error {
	t.newMessages <- m
	return nil
}

func (t *TCPSend) drain() {
	for {
		select {
		case <-t.closed:
			t.reconnect()
		case m := <-t.newMessages:
			t.lock.Lock()
			t.outstanding++
			t.lock.Unlock()
			t.s.Send(m, t)
		}
	}
}
<commit_msg>Try to connect to remote hosts on start continiously<commit_after>package tcp

import (
	"errors"
	"math/rand"
	"net"
	"sort"
	"sync"
	"time"

	"github.com/vektra/cypress"
)

type TCPSend struct {
	hosts  []string
	window int
	c      net.Conn
	s      *cypress.Send

	lock        sync.Mutex
	outstanding int

	newMessages chan *cypress.Message
	closed      chan bool

	shutdown bool

	nacked cypress.Messages
}

const DefaultTCPBuffer = 128

func NewTCPSend(hosts []string, window, buffer int) (*TCPSend, error) {
	tcp := &TCPSend{
		hosts:       hosts,
		window:      window,
		newMessages: make(chan *cypress.Message, buffer),
		closed:      make(chan bool, 1),
	}

	for {
		err := tcp.Connect()
		if err != nil {
			if err == ErrNoAvailableHosts {
				time.Sleep(1 * time.Second)
				continue
			}

			return nil, err
		}

		break
	}

	go tcp.drain()

	return tcp, nil
}

var ErrNoAvailableHosts = errors.New("no available hosts")

func shuffle(a []string) {
	for i := range a {
		j := rand.Intn(i + 1)
		a[i], a[j] = a[j], a[i]
	}
}

func (t *TCPSend) Connect() error {
	shuffle(t.hosts)

	for _, host := range t.hosts {
		c, err := net.Dial("tcp", host)
		if err != nil {
			continue
		}

		s := cypress.NewSend(c, t.window)
		err = s.SendHandshake()
		if err != nil {
			c.Close()
			continue
		}

		t.c = c
		t.s = s

		s.OnClosed = t.onClosed

		return nil
	}

	return ErrNoAvailableHosts
}

func (t *TCPSend) Close() error {
	t.shutdown = true
	return t.c.Close()
}

func (t *TCPSend) Ack(m *cypress.Message) {
	t.lock.Lock()
	defer t.lock.Unlock()

	t.outstanding--
}

func (t *TCPSend) Nack(m *cypress.Message) {
	t.lock.Lock()
	defer t.lock.Unlock()

	t.outstanding--
	t.nacked = append(t.nacked, m)
}

func (t *TCPSend) onClosed() {
	t.closed <- true
}

func (t *TCPSend) reconnect() {
	t.lock.Lock()

	var err error

	t.c.Close()

	for {
		err = t.Connect()
		if err != nil {
			if t.shutdown {
				t.lock.Unlock()
				return
			}

			time.Sleep(1 * time.Second)
			continue
		}

		break
	}

	nacked := t.nacked
	t.nacked = nil

	t.lock.Unlock()

	for idx, msg := range nacked {
		t.outstanding++
		err = t.s.Send(msg, t)
		if err != nil {
			t.lock.Lock()
			t.nacked = append(nacked[idx+1:], t.nacked...)
			sort.Sort(t.nacked)

			// don't retry here because the OnClose handler will
			// prime the closed channel, so we return from here, pick
			// up the value from the channel, then this is called again.
			t.lock.Unlock()
			return
		}
	}
}

func (t *TCPSend) Receive(m *cypress.Message) error {
	t.newMessages <- m
	return nil
}

func (t *TCPSend) drain() {
	for {
		select {
		case <-t.closed:
			t.reconnect()
		case m := <-t.newMessages:
			t.lock.Lock()
			t.outstanding++
			t.lock.Unlock()
			t.s.Send(m, t)
		}
	}
}
<|endoftext|>


<commit_before>package v3

import (
	"net/http"

	"code.cloudfoundry.org/cli/actor/actionerror"
	"code.cloudfoundry.org/cli/actor/sharedaction"
	"code.cloudfoundry.org/cli/actor/v2action"
	"code.cloudfoundry.org/cli/actor/v2v3action"
	"code.cloudfoundry.org/cli/actor/v3action"
	"code.cloudfoundry.org/cli/api/cloudcontroller/ccerror"
	"code.cloudfoundry.org/cli/api/cloudcontroller/ccversion"
	"code.cloudfoundry.org/cli/command"
	"code.cloudfoundry.org/cli/command/flag"
	"code.cloudfoundry.org/cli/command/translatableerror"
	sharedV2 "code.cloudfoundry.org/cli/command/v2/shared"
	sharedV3 "code.cloudfoundry.org/cli/command/v3/shared"
)

//go:generate counterfeiter . UnshareServiceActor

type UnshareServiceActor interface {
	UnshareServiceInstanceFromOrganizationNameAndSpaceNameByNameAndSpace(sharedToOrgName string, sharedToSpaceName string, serviceInstanceName string, currentlyTargetedSpaceGUID string) (v2v3action.Warnings, error)
	CloudControllerV3APIVersion() string
}

type UnshareServiceCommand struct {
	RequiredArgs      flag.ServiceInstance `positional-args:"yes"`
	SharedToOrgName   string               `short:"o" required:"false" description:"Org of the other space (Default: targeted org)"`
	SharedToSpaceName string               `short:"s" required:"true" description:"Space to unshare the service instance from"`
	Force             bool                 `short:"f" description:"Force unshare without confirmation"`
	usage             interface{}          `usage:"cf unshare-service SERVICE_INSTANCE -s OTHER_SPACE [-o OTHER_ORG] [-f]"`
	relatedCommands   interface{}          `related_commands:"delete-service, service, services, share-service, unbind-service"`

	UI          command.UI
	Config      command.Config
	SharedActor command.SharedActor
	Actor       UnshareServiceActor
}

func (cmd *UnshareServiceCommand) Setup(config command.Config, ui command.UI) error {
	cmd.UI = ui
	cmd.Config = config

	sharedActor := sharedaction.NewActor(config)
	cmd.SharedActor = sharedActor

	ccClientV3, uaaClientV3, err := sharedV3.NewClients(config, ui, true)
	if err != nil {
		if v3Err, ok := err.(ccerror.V3UnexpectedResponseError); ok && v3Err.ResponseCode == http.StatusNotFound {
			return translatableerror.MinimumAPIVersionNotMetError{MinimumVersion: ccversion.MinVersionShareServiceV3}
		}
		return err
	}

	ccClientV2, uaaClientV2, err := sharedV2.NewClients(config, ui, true)
	if err != nil {
		return err
	}

	cmd.Actor = v2v3action.NewActor(
		v2action.NewActor(ccClientV2, uaaClientV2, config),
		v3action.NewActor(ccClientV3, config, sharedActor, uaaClientV3),
	)

	return nil
}

func (cmd UnshareServiceCommand) Execute(args []string) error {
	err := command.MinimumAPIVersionCheck(cmd.Actor.CloudControllerV3APIVersion(), ccversion.MinVersionShareServiceV3)
	if err != nil {
		return err
	}

	err = cmd.SharedActor.CheckTarget(true, true)
	if err != nil {
		return err
	}

	user, err := cmd.Config.CurrentUser()
	if err != nil {
		return err
	}

	orgName := cmd.Config.TargetedOrganization().Name
	if cmd.SharedToOrgName != "" {
		orgName = cmd.SharedToOrgName
	}

	if !cmd.Force {
		cmd.UI.DisplayWarning("WARNING: Unsharing this service instance will remove any service bindings that exist in any spaces that this instance is shared into. This could cause applications to stop working.")
		cmd.UI.DisplayNewline()

		response, promptErr := cmd.UI.DisplayBoolPrompt(false, "Really unshare the service instance?", map[string]interface{}{
			"ServiceInstanceName": cmd.RequiredArgs.ServiceInstance,
		})
		if promptErr != nil {
			return promptErr
		}
		if !response {
			cmd.UI.DisplayText("Unshare cancelled")
			return nil
		}
	}

	cmd.UI.DisplayTextWithFlavor("Unsharing service instance {{.ServiceInstanceName}} from org {{.OrgName}} / space {{.SpaceName}} as {{.Username}}...", map[string]interface{}{
		"ServiceInstanceName": cmd.RequiredArgs.ServiceInstance,
		"OrgName":             orgName,
		"SpaceName":           cmd.SharedToSpaceName,
		"Username":            user.Name,
	})

	warnings, err := cmd.Actor.UnshareServiceInstanceFromOrganizationNameAndSpaceNameByNameAndSpace(orgName, cmd.SharedToSpaceName, cmd.RequiredArgs.ServiceInstance, cmd.Config.TargetedSpace().GUID)
	cmd.UI.DisplayWarnings(warnings)
	if err != nil {
		switch err.(type) {
		case actionerror.ServiceInstanceNotSharedToSpaceError:
			cmd.UI.DisplayText("Service instance {{.ServiceInstanceName}} is not shared with space {{.SpaceName}} in organization {{.OrgName}}.", map[string]interface{}{
				"ServiceInstanceName": cmd.RequiredArgs.ServiceInstance,
				"SpaceName":           cmd.SharedToSpaceName,
				"OrgName":             orgName,
			})
		default:
			return err
		}
	}

	cmd.UI.DisplayOK()
	return nil
}
<commit_msg>display experimental warnings on unshare-service command<commit_after>package v3

import (
	"net/http"

	"code.cloudfoundry.org/cli/actor/actionerror"
	"code.cloudfoundry.org/cli/actor/sharedaction"
	"code.cloudfoundry.org/cli/actor/v2action"
	"code.cloudfoundry.org/cli/actor/v2v3action"
	"code.cloudfoundry.org/cli/actor/v3action"
	"code.cloudfoundry.org/cli/api/cloudcontroller/ccerror"
	"code.cloudfoundry.org/cli/api/cloudcontroller/ccversion"
	"code.cloudfoundry.org/cli/command"
	"code.cloudfoundry.org/cli/command/flag"
	"code.cloudfoundry.org/cli/command/translatableerror"
	sharedV2 "code.cloudfoundry.org/cli/command/v2/shared"
	sharedV3 "code.cloudfoundry.org/cli/command/v3/shared"
)

//go:generate counterfeiter . UnshareServiceActor

type UnshareServiceActor interface {
	UnshareServiceInstanceFromOrganizationNameAndSpaceNameByNameAndSpace(sharedToOrgName string, sharedToSpaceName string, serviceInstanceName string, currentlyTargetedSpaceGUID string) (v2v3action.Warnings, error)
	CloudControllerV3APIVersion() string
}

type UnshareServiceCommand struct {
	RequiredArgs      flag.ServiceInstance `positional-args:"yes"`
	SharedToOrgName   string               `short:"o" required:"false" description:"Org of the other space (Default: targeted org)"`
	SharedToSpaceName string               `short:"s" required:"true" description:"Space to unshare the service instance from"`
	Force             bool                 `short:"f" description:"Force unshare without confirmation"`
	usage             interface{}          `usage:"cf unshare-service SERVICE_INSTANCE -s OTHER_SPACE [-o OTHER_ORG] [-f]"`
	relatedCommands   interface{}          `related_commands:"delete-service, service, services, share-service, unbind-service"`

	UI          command.UI
	Config      command.Config
	SharedActor command.SharedActor
	Actor       UnshareServiceActor
}

func (cmd *UnshareServiceCommand) Setup(config command.Config, ui command.UI) error {
	cmd.UI = ui
	cmd.Config = config

	sharedActor := sharedaction.NewActor(config)
	cmd.SharedActor = sharedActor

	ccClientV3, uaaClientV3, err := sharedV3.NewClients(config, ui, true)
	if err != nil {
		if v3Err, ok := err.(ccerror.V3UnexpectedResponseError); ok && v3Err.ResponseCode == http.StatusNotFound {
			return translatableerror.MinimumAPIVersionNotMetError{MinimumVersion: ccversion.MinVersionShareServiceV3}
		}
		return err
	}

	ccClientV2, uaaClientV2, err := sharedV2.NewClients(config, ui, true)
	if err != nil {
		return err
	}

	cmd.Actor = v2v3action.NewActor(
		v2action.NewActor(ccClientV2, uaaClientV2, config),
		v3action.NewActor(ccClientV3, config, sharedActor, uaaClientV3),
	)

	return nil
}

func (cmd UnshareServiceCommand) Execute(args []string) error {
	cmd.UI.DisplayText(command.ExperimentalWarning)
	cmd.UI.DisplayNewline()

	err := command.MinimumAPIVersionCheck(cmd.Actor.CloudControllerV3APIVersion(), ccversion.MinVersionShareServiceV3)
	if err != nil {
		return err
	}

	err = cmd.SharedActor.CheckTarget(true, true)
	if err != nil {
		return err
	}

	user, err := cmd.Config.CurrentUser()
	if err != nil {
		return err
	}

	orgName := cmd.Config.TargetedOrganization().Name
	if cmd.SharedToOrgName != "" {
		orgName = cmd.SharedToOrgName
	}

	if !cmd.Force {
		cmd.UI.DisplayWarning("WARNING: Unsharing this service instance will remove any service bindings that exist in any spaces that this instance is shared into. This could cause applications to stop working.")
		cmd.UI.DisplayNewline()

		response, promptErr := cmd.UI.DisplayBoolPrompt(false, "Really unshare the service instance?", map[string]interface{}{
			"ServiceInstanceName": cmd.RequiredArgs.ServiceInstance,
		})
		if promptErr != nil {
			return promptErr
		}
		if !response {
			cmd.UI.DisplayText("Unshare cancelled")
			return nil
		}
	}

	cmd.UI.DisplayTextWithFlavor("Unsharing service instance {{.ServiceInstanceName}} from org {{.OrgName}} / space {{.SpaceName}} as {{.Username}}...", map[string]interface{}{
		"ServiceInstanceName": cmd.RequiredArgs.ServiceInstance,
		"OrgName":             orgName,
		"SpaceName":           cmd.SharedToSpaceName,
		"Username":            user.Name,
	})

	warnings, err := cmd.Actor.UnshareServiceInstanceFromOrganizationNameAndSpaceNameByNameAndSpace(orgName, cmd.SharedToSpaceName, cmd.RequiredArgs.ServiceInstance, cmd.Config.TargetedSpace().GUID)
	cmd.UI.DisplayWarnings(warnings)
	if err != nil {
		switch err.(type) {
		case actionerror.ServiceInstanceNotSharedToSpaceError:
			cmd.UI.DisplayText("Service instance {{.ServiceInstanceName}} is not shared with space {{.SpaceName}} in organization {{.OrgName}}.", map[string]interface{}{
				"ServiceInstanceName": cmd.RequiredArgs.ServiceInstance,
				"SpaceName":           cmd.SharedToSpaceName,
				"OrgName":             orgName,
			})
		default:
			return err
		}
	}

	cmd.UI.DisplayOK()
	return nil
}
<|endoftext|>


<commit_before>package vfs

import (
	"encoding/base64"
	"fmt"
	"net/http"
	"os"
	"path"
	"strings"
	"time"

	"github.com/cozy/cozy-stack/pkg/consts"
	"github.com/cozy/cozy-stack/pkg/couchdb"
)

// FileDoc is a struct containing all the informations about a file.
// It implements the couchdb.Doc and jsonapi.Object interfaces.
type FileDoc struct {
	// Type of document. Useful to (de)serialize and filter the data
	// from couch.
	Type string `json:"type"`
	// Qualified file identifier
	DocID string `json:"_id,omitempty"`
	// File revision
	DocRev string `json:"_rev,omitempty"`
	// File name
	DocName string `json:"name"`
	// Parent directory identifier
	DirID       string `json:"dir_id,omitempty"`
	RestorePath string `json:"restore_path,omitempty"`

	CreatedAt time.Time `json:"created_at"`
	UpdatedAt time.Time `json:"updated_at"`

	ByteSize   int64    `json:"size,string"` // Serialized in JSON as a string, because JS has some issues with big numbers
	MD5Sum     []byte   `json:"md5sum"`
	Mime       string   `json:"mime"`
	Class      string   `json:"class"`
	Executable bool     `json:"executable"`
	Trashed    bool     `json:"trashed"`
	Tags       []string `json:"tags"`

	Metadata     Metadata               `json:"metadata,omitempty"`
	ReferencedBy []couchdb.DocReference `json:"referenced_by,omitempty"`

	CozyMetadata *FilesCozyMetadata `json:"cozyMetadata,omitempty"`

	// InternalID is an identifier that can be used by the VFS, but must no be
	// used by clients. For example, it can be used to know the location in
	// Swift of a file.
	InternalID string `json:"internal_vfs_id,omitempty"`

	// Cache of the fullpath of the file. Should not have to be invalidated
	// since we use FileDoc as immutable data-structures.
	fullpath string

	// NOTE: Do not forget to propagate changes made to this structure to the
	// structure DirOrFileDoc in model/vfs/vfs.go and client/files.go.
}

// ID returns the file qualified identifier
func (f *FileDoc) ID() string { return f.DocID }

// Rev returns the file revision
func (f *FileDoc) Rev() string { return f.DocRev }

// DocType returns the file document type
func (f *FileDoc) DocType() string { return consts.Files }

// Clone implements couchdb.Doc
func (f *FileDoc) Clone() couchdb.Doc {
	cloned := *f
	cloned.MD5Sum = make([]byte, len(f.MD5Sum))
	copy(cloned.MD5Sum, f.MD5Sum)
	cloned.Tags = make([]string, len(f.Tags))
	copy(cloned.Tags, f.Tags)
	cloned.ReferencedBy = make([]couchdb.DocReference, len(f.ReferencedBy))
	copy(cloned.ReferencedBy, f.ReferencedBy)
	cloned.Metadata = make(Metadata, len(f.Metadata))
	for k, v := range f.Metadata {
		cloned.Metadata[k] = v
	}
	if f.CozyMetadata != nil {
		cloned.CozyMetadata = f.CozyMetadata.Clone()
	}
	return &cloned
}

// SetID changes the file qualified identifier
func (f *FileDoc) SetID(id string) { f.DocID = id }

// SetRev changes the file revision
func (f *FileDoc) SetRev(rev string) { f.DocRev = rev }

// Path is used to generate the file path
func (f *FileDoc) Path(fp FilePather) (string, error) {
	if f.fullpath != "" {
		return f.fullpath, nil
	}
	var err error
	f.fullpath, err = fp.FilePath(f)
	return f.fullpath, err
}

// ResetFullpath clears the fullpath, so it can be recomputed with Path()
func (f *FileDoc) ResetFullpath() {
	f.fullpath = ""
}

// Parent returns the parent directory document
func (f *FileDoc) Parent(fs VFS) (*DirDoc, error) {
	parent, err := fs.DirByID(f.DirID)
	if os.IsNotExist(err) {
		err = ErrParentDoesNotExist
	}
	return parent, err
}

// Name returns base name of the file
func (f *FileDoc) Name() string { return f.DocName }

// Size returns the length in bytes for regular files; system-dependent for others
func (f *FileDoc) Size() int64 { return f.ByteSize }

// Mode returns the file mode bits
func (f *FileDoc) Mode() os.FileMode { return getFileMode(f.Executable) }

// ModTime returns the modification time
func (f *FileDoc) ModTime() time.Time { return f.UpdatedAt }

// IsDir returns the abbreviation for Mode().IsDir()
func (f *FileDoc) IsDir() bool { return false }

// Sys returns the underlying data source (can return nil)
func (f *FileDoc) Sys() interface{} { return nil }

// AddReferencedBy adds referenced_by to the file
func (f *FileDoc) AddReferencedBy(ri ...couchdb.DocReference) {
	f.ReferencedBy = append(f.ReferencedBy, ri...)
}

// SameReferences returns true if the two sets reference the same documents.
func SameReferences(a, b []couchdb.DocReference) bool {
	if len(a) != len(b) {
		return false
	}
	for _, ref := range a {
		if !containsReferencedBy(b, ref) {
			return false
		}
	}
	return true
}

func containsReferencedBy(haystack []couchdb.DocReference, needle couchdb.DocReference) bool {
	for _, ref := range haystack {
		if ref.ID == needle.ID && ref.Type == needle.Type {
			return true
		}
	}
	return false
}

// RemoveReferencedBy removes one or several referenced_by to the file
func (f *FileDoc) RemoveReferencedBy(ri ...couchdb.DocReference) {
	// https://github.com/golang/go/wiki/SliceTricks#filtering-without-allocating
	referenced := f.ReferencedBy[:0]
	for _, ref := range f.ReferencedBy {
		if !containsReferencedBy(ri, ref) {
			referenced = append(referenced, ref)
		}
	}
	f.ReferencedBy = referenced
}

// NewFileDoc is the FileDoc constructor. The given name is validated.
func NewFileDoc(name, dirID string, size int64, md5Sum []byte, mime, class string, cdate time.Time, executable, trashed bool, tags []string) (*FileDoc, error) {
	if err := checkFileName(name); err != nil {
		return nil, err
	}

	if dirID == "" {
		dirID = consts.RootDirID
	}

	tags = uniqueTags(tags)

	doc := &FileDoc{
		Type:    consts.FileType,
		DocName: name,
		DirID:   dirID,

		CreatedAt:  cdate,
		UpdatedAt:  cdate,
		ByteSize:   size,
		MD5Sum:     md5Sum,
		Mime:       mime,
		Class:      class,
		Executable: executable,
		Trashed:    trashed,
		Tags:       tags,
	}

	return doc, nil
}

// ServeFileContent replies to a http request using the content of a
// file given its FileDoc.
//
// It uses internally http.ServeContent and benefits from it by
// offering support to Range, If-Modified-Since and If-None-Match
// requests. It uses the revision of the file as the Etag value for
// non-ranged requests
//
// The content disposition is inlined.
func ServeFileContent(fs VFS, doc *FileDoc, version *Version, filename, disposition string, req *http.Request, w http.ResponseWriter) error {
	if filename == "" {
		filename = doc.DocName
	}
	header := w.Header()
	header.Set("Content-Type", doc.Mime)
	if disposition != "" {
		header.Set("Content-Disposition", ContentDisposition(disposition, filename))
	}

	if header.Get("Range") == "" {
		eTag := base64.StdEncoding.EncodeToString(doc.MD5Sum)
		header.Set("Etag", fmt.Sprintf(`"%s"`, eTag))
	}

	var content File
	var err error
	if version == nil {
		content, err = fs.OpenFile(doc)
	} else {
		content, err = fs.OpenFileVersion(doc, version)
	}
	if err != nil {
		return err
	}
	defer content.Close()

	http.ServeContent(w, req, filename, doc.UpdatedAt, content)
	return nil
}

// ModifyFileMetadata modify the metadata associated to a file. It can
// be used to rename or move the file in the VFS.
func ModifyFileMetadata(fs VFS, olddoc *FileDoc, patch *DocPatch) (*FileDoc, error) {
	var err error
	rename := patch.Name != nil
	cdate := olddoc.CreatedAt
	oname := olddoc.DocName
	trashed := olddoc.Trashed
	if patch.RestorePath != nil {
		trashed = *patch.RestorePath != ""
	}
	patch, err = normalizeDocPatch(&DocPatch{
		Name:        &oname,
		DirID:       &olddoc.DirID,
		RestorePath: &olddoc.RestorePath,
		Tags:        &olddoc.Tags,
		UpdatedAt:   &olddoc.UpdatedAt,
		Executable:  &olddoc.Executable,
	}, patch, cdate)
	if err != nil {
		return nil, err
	}

	// in case of a renaming of the file, if the extension of the file has
	// changed, we consider recalculating the mime and class attributes, using
	// the new extension.
	newname := *patch.Name
	oldname := olddoc.DocName
	var mime, class string
	if patch.Class != nil || (rename && path.Ext(newname) != path.Ext(oldname)) {
		mime, class = ExtractMimeAndClassFromFilename(newname)
	} else {
		mime, class = olddoc.Mime, olddoc.Class
	}

	if trashed && olddoc.DirID != *patch.DirID {
		return nil, ErrFileInTrash
	}

	newdoc, err := NewFileDoc(
		newname,
		*patch.DirID,
		olddoc.Size(),
		olddoc.MD5Sum,
		mime,
		class,
		cdate,
		*patch.Executable,
		trashed,
		*patch.Tags,
	)
	if err != nil {
		return nil, err
	}

	newdoc.RestorePath = *patch.RestorePath
	newdoc.UpdatedAt = *patch.UpdatedAt
	newdoc.Metadata = olddoc.Metadata
	newdoc.ReferencedBy = olddoc.ReferencedBy
	newdoc.CozyMetadata = olddoc.CozyMetadata
	newdoc.InternalID = olddoc.InternalID

	if patch.MD5Sum != nil {
		newdoc.MD5Sum = *patch.MD5Sum
	}

	if err = fs.UpdateFileDoc(olddoc, newdoc); err != nil {
		return nil, err
	}
	return newdoc, nil
}

// TrashFile is used to delete a file given its document
func TrashFile(fs VFS, olddoc *FileDoc) (*FileDoc, error) {
	oldpath, err := olddoc.Path(fs)
	if err != nil {
		return nil, err
	}

	if strings.HasPrefix(oldpath, TrashDirName) {
		return nil, ErrFileInTrash
	}

	trashDirID := consts.TrashDirID
	restorePath := path.Dir(oldpath)

	var newdoc *FileDoc
	err = tryOrUseSuffix(olddoc.DocName, conflictFormat, func(name string) error {
		newdoc = olddoc.Clone().(*FileDoc)
		newdoc.DirID = trashDirID
		newdoc.RestorePath = restorePath
		newdoc.DocName = name
		newdoc.Trashed = true
		newdoc.fullpath = path.Join(TrashDirName, name)
		newdoc.CozyMetadata = olddoc.CozyMetadata
		return fs.UpdateFileDoc(olddoc, newdoc)
	})

	return newdoc, err
}

// RestoreFile is used to restore a trashed file given its document
func RestoreFile(fs VFS, olddoc *FileDoc) (*FileDoc, error) {
	oldpath, err := olddoc.Path(fs)
	if err != nil {
		return nil, err
	}

	restoreDir, err := getRestoreDir(fs, oldpath, olddoc.RestorePath)
	if err != nil {
		return nil, err
	}

	name := stripSuffix(olddoc.DocName, conflictSuffix)

	var newdoc *FileDoc
	err = tryOrUseSuffix(name, "%s (%s)", func(name string) error {
		newdoc = olddoc.Clone().(*FileDoc)
		newdoc.DirID = restoreDir.DocID
		newdoc.RestorePath = ""
		newdoc.DocName = name
		newdoc.Trashed = false
		newdoc.fullpath = path.Join(restoreDir.Fullpath, name)
		newdoc.CozyMetadata = olddoc.CozyMetadata
		return fs.UpdateFileDoc(olddoc, newdoc)
	})

	return newdoc, err
}

func getFileMode(executable bool) os.FileMode {
	if executable {
		return 0755 // -rwxr-xr-x
	}
	return 0644 // -rw-r--r--
}

var (
	_ couchdb.Doc = &FileDoc{}
	_ os.FileInfo = &FileDoc{}
)
<commit_msg>Force trashing file (#2693)<commit_after>package vfs

import (
	"encoding/base64"
	"fmt"
	"net/http"
	"os"
	"path"
	"strings"
	"time"

	"github.com/cozy/cozy-stack/pkg/consts"
	"github.com/cozy/cozy-stack/pkg/couchdb"
)

// FileDoc is a struct containing all the informations about a file.
// It implements the couchdb.Doc and jsonapi.Object interfaces.
type FileDoc struct {
	// Type of document. Useful to (de)serialize and filter the data
	// from couch.
	Type string `json:"type"`
	// Qualified file identifier
	DocID string `json:"_id,omitempty"`
	// File revision
	DocRev string `json:"_rev,omitempty"`
	// File name
	DocName string `json:"name"`
	// Parent directory identifier
	DirID       string `json:"dir_id,omitempty"`
	RestorePath string `json:"restore_path,omitempty"`

	CreatedAt time.Time `json:"created_at"`
	UpdatedAt time.Time `json:"updated_at"`

	ByteSize   int64    `json:"size,string"` // Serialized in JSON as a string, because JS has some issues with big numbers
	MD5Sum     []byte   `json:"md5sum"`
	Mime       string   `json:"mime"`
	Class      string   `json:"class"`
	Executable bool     `json:"executable"`
	Trashed    bool     `json:"trashed"`
	Tags       []string `json:"tags"`

	Metadata     Metadata               `json:"metadata,omitempty"`
	ReferencedBy []couchdb.DocReference `json:"referenced_by,omitempty"`

	CozyMetadata *FilesCozyMetadata `json:"cozyMetadata,omitempty"`

	// InternalID is an identifier that can be used by the VFS, but must no be
	// used by clients. For example, it can be used to know the location in
	// Swift of a file.
	InternalID string `json:"internal_vfs_id,omitempty"`

	// Cache of the fullpath of the file. Should not have to be invalidated
	// since we use FileDoc as immutable data-structures.
	fullpath string

	// NOTE: Do not forget to propagate changes made to this structure to the
	// structure DirOrFileDoc in model/vfs/vfs.go and client/files.go.
}

// ID returns the file qualified identifier
func (f *FileDoc) ID() string { return f.DocID }

// Rev returns the file revision
func (f *FileDoc) Rev() string { return f.DocRev }

// DocType returns the file document type
func (f *FileDoc) DocType() string { return consts.Files }

// Clone implements couchdb.Doc
func (f *FileDoc) Clone() couchdb.Doc {
	cloned := *f
	cloned.MD5Sum = make([]byte, len(f.MD5Sum))
	copy(cloned.MD5Sum, f.MD5Sum)
	cloned.Tags = make([]string, len(f.Tags))
	copy(cloned.Tags, f.Tags)
	cloned.ReferencedBy = make([]couchdb.DocReference, len(f.ReferencedBy))
	copy(cloned.ReferencedBy, f.ReferencedBy)
	cloned.Metadata = make(Metadata, len(f.Metadata))
	for k, v := range f.Metadata {
		cloned.Metadata[k] = v
	}
	if f.CozyMetadata != nil {
		cloned.CozyMetadata = f.CozyMetadata.Clone()
	}
	return &cloned
}

// SetID changes the file qualified identifier
func (f *FileDoc) SetID(id string) { f.DocID = id }

// SetRev changes the file revision
func (f *FileDoc) SetRev(rev string) { f.DocRev = rev }

// Path is used to generate the file path
func (f *FileDoc) Path(fp FilePather) (string, error) {
	if f.fullpath != "" {
		return f.fullpath, nil
	}
	var err error
	f.fullpath, err = fp.FilePath(f)
	return f.fullpath, err
}

// ResetFullpath clears the fullpath, so it can be recomputed with Path()
func (f *FileDoc) ResetFullpath() {
	f.fullpath = ""
}

// Parent returns the parent directory document
func (f *FileDoc) Parent(fs VFS) (*DirDoc, error) {
	parent, err := fs.DirByID(f.DirID)
	if os.IsNotExist(err) {
		err = ErrParentDoesNotExist
	}
	return parent, err
}

// Name returns base name of the file
func (f *FileDoc) Name() string { return f.DocName }

// Size returns the length in bytes for regular files; system-dependent for others
func (f *FileDoc) Size() int64 { return f.ByteSize }

// Mode returns the file mode bits
func (f *FileDoc) Mode() os.FileMode { return getFileMode(f.Executable) }

// ModTime returns the modification time
func (f *FileDoc) ModTime() time.Time { return f.UpdatedAt }

// IsDir returns the abbreviation for Mode().IsDir()
func (f *FileDoc) IsDir() bool { return false }

// Sys returns the underlying data source (can return nil)
func (f *FileDoc) Sys() interface{} { return nil }

// AddReferencedBy adds referenced_by to the file
func (f *FileDoc) AddReferencedBy(ri ...couchdb.DocReference) {
	f.ReferencedBy = append(f.ReferencedBy, ri...)
}

// SameReferences returns true if the two sets reference the same documents.
func SameReferences(a, b []couchdb.DocReference) bool {
	if len(a) != len(b) {
		return false
	}
	for _, ref := range a {
		if !containsReferencedBy(b, ref) {
			return false
		}
	}
	return true
}

func containsReferencedBy(haystack []couchdb.DocReference, needle couchdb.DocReference) bool {
	for _, ref := range haystack {
		if ref.ID == needle.ID && ref.Type == needle.Type {
			return true
		}
	}
	return false
}

// RemoveReferencedBy removes one or several referenced_by to the file
func (f *FileDoc) RemoveReferencedBy(ri ...couchdb.DocReference) {
	// https://github.com/golang/go/wiki/SliceTricks#filtering-without-allocating
	referenced := f.ReferencedBy[:0]
	for _, ref := range f.ReferencedBy {
		if !containsReferencedBy(ri, ref) {
			referenced = append(referenced, ref)
		}
	}
	f.ReferencedBy = referenced
}

// NewFileDoc is the FileDoc constructor. The given name is validated.
func NewFileDoc(name, dirID string, size int64, md5Sum []byte, mime, class string, cdate time.Time, executable, trashed bool, tags []string) (*FileDoc, error) {
	if err := checkFileName(name); err != nil {
		return nil, err
	}

	if dirID == "" {
		dirID = consts.RootDirID
	}

	tags = uniqueTags(tags)

	doc := &FileDoc{
		Type:    consts.FileType,
		DocName: name,
		DirID:   dirID,

		CreatedAt:  cdate,
		UpdatedAt:  cdate,
		ByteSize:   size,
		MD5Sum:     md5Sum,
		Mime:       mime,
		Class:      class,
		Executable: executable,
		Trashed:    trashed,
		Tags:       tags,
	}

	return doc, nil
}

// ServeFileContent replies to a http request using the content of a
// file given its FileDoc.
//
// It uses internally http.ServeContent and benefits from it by
// offering support to Range, If-Modified-Since and If-None-Match
// requests. It uses the revision of the file as the Etag value for
// non-ranged requests
//
// The content disposition is inlined.
func ServeFileContent(fs VFS, doc *FileDoc, version *Version, filename, disposition string, req *http.Request, w http.ResponseWriter) error {
	if filename == "" {
		filename = doc.DocName
	}
	header := w.Header()
	header.Set("Content-Type", doc.Mime)
	if disposition != "" {
		header.Set("Content-Disposition", ContentDisposition(disposition, filename))
	}

	if header.Get("Range") == "" {
		eTag := base64.StdEncoding.EncodeToString(doc.MD5Sum)
		header.Set("Etag", fmt.Sprintf(`"%s"`, eTag))
	}

	var content File
	var err error
	if version == nil {
		content, err = fs.OpenFile(doc)
	} else {
		content, err = fs.OpenFileVersion(doc, version)
	}
	if err != nil {
		return err
	}
	defer content.Close()

	http.ServeContent(w, req, filename, doc.UpdatedAt, content)
	return nil
}

// ModifyFileMetadata modify the metadata associated to a file. It can
// be used to rename or move the file in the VFS.
func ModifyFileMetadata(fs VFS, olddoc *FileDoc, patch *DocPatch) (*FileDoc, error) {
	var err error
	rename := patch.Name != nil
	cdate := olddoc.CreatedAt
	oname := olddoc.DocName
	trashed := olddoc.Trashed
	if patch.RestorePath != nil {
		trashed = *patch.RestorePath != ""
	}
	patch, err = normalizeDocPatch(&DocPatch{
		Name:        &oname,
		DirID:       &olddoc.DirID,
		RestorePath: &olddoc.RestorePath,
		Tags:        &olddoc.Tags,
		UpdatedAt:   &olddoc.UpdatedAt,
		Executable:  &olddoc.Executable,
	}, patch, cdate)
	if err != nil {
		return nil, err
	}

	// in case of a renaming of the file, if the extension of the file has
	// changed, we consider recalculating the mime and class attributes, using
	// the new extension.
	newname := *patch.Name
	oldname := olddoc.DocName
	var mime, class string
	if patch.Class != nil || (rename && path.Ext(newname) != path.Ext(oldname)) {
		mime, class = ExtractMimeAndClassFromFilename(newname)
	} else {
		mime, class = olddoc.Mime, olddoc.Class
	}

	if trashed && olddoc.DirID != *patch.DirID {
		return nil, ErrFileInTrash
	}

	newdoc, err := NewFileDoc(
		newname,
		*patch.DirID,
		olddoc.Size(),
		olddoc.MD5Sum,
		mime,
		class,
		cdate,
		*patch.Executable,
		trashed,
		*patch.Tags,
	)
	if err != nil {
		return nil, err
	}

	newdoc.RestorePath = *patch.RestorePath
	newdoc.UpdatedAt = *patch.UpdatedAt
	newdoc.Metadata = olddoc.Metadata
	newdoc.ReferencedBy = olddoc.ReferencedBy
	newdoc.CozyMetadata = olddoc.CozyMetadata
	newdoc.InternalID = olddoc.InternalID

	if patch.MD5Sum != nil {
		newdoc.MD5Sum = *patch.MD5Sum
	}

	if err = fs.UpdateFileDoc(olddoc, newdoc); err != nil {
		return nil, err
	}
	return newdoc, nil
}

// TrashFile is used to delete a file given its document
func TrashFile(fs VFS, olddoc *FileDoc) (*FileDoc, error) {
	oldpath, err := olddoc.Path(fs)
	if err != nil {
		return nil, err
	}

	// If there is only the trashed attribute or the parent in trash, but not
	// both, we can try again to move the file to the trash to fix the
	// inconsistency.
	if olddoc.Trashed && strings.HasPrefix(oldpath, TrashDirName) {
		return nil, ErrFileInTrash
	}

	trashDirID := consts.TrashDirID
	restorePath := path.Dir(oldpath)

	var newdoc *FileDoc
	err = tryOrUseSuffix(olddoc.DocName, conflictFormat, func(name string) error {
		newdoc = olddoc.Clone().(*FileDoc)
		newdoc.DirID = trashDirID
		newdoc.RestorePath = restorePath
		newdoc.DocName = name
		newdoc.Trashed = true
		newdoc.fullpath = path.Join(TrashDirName, name)
		newdoc.CozyMetadata = olddoc.CozyMetadata
		return fs.UpdateFileDoc(olddoc, newdoc)
	})

	return newdoc, err
}

// RestoreFile is used to restore a trashed file given its document
func RestoreFile(fs VFS, olddoc *FileDoc) (*FileDoc, error) {
	oldpath, err := olddoc.Path(fs)
	if err != nil {
		return nil, err
	}

	restoreDir, err := getRestoreDir(fs, oldpath, olddoc.RestorePath)
	if err != nil {
		return nil, err
	}

	name := stripSuffix(olddoc.DocName, conflictSuffix)

	var newdoc *FileDoc
	err = tryOrUseSuffix(name, "%s (%s)", func(name string) error {
		newdoc = olddoc.Clone().(*FileDoc)
		newdoc.DirID = restoreDir.DocID
		newdoc.RestorePath = ""
		newdoc.DocName = name
		newdoc.Trashed = false
		newdoc.fullpath = path.Join(restoreDir.Fullpath, name)
		newdoc.CozyMetadata = olddoc.CozyMetadata
		return fs.UpdateFileDoc(olddoc, newdoc)
	})

	return newdoc, err
}

func getFileMode(executable bool) os.FileMode {
	if executable {
		return 0755 // -rwxr-xr-x
	}
	return 0644 // -rw-r--r--
}

var (
	_ couchdb.Doc = &FileDoc{}
	_ os.FileInfo = &FileDoc{}
)
<|endoftext|>


<commit_before>package gorma

const modelTmpl = `// {{if .Description}}{{.Description}}{{else}}app.{{gotypename . 0}} storage type{{end}}
// Identifier: {{ $typeName :=  gotypename . 0}}{{$typeName := demodel $typeName}}
{{$td := gotypedef . 0 true false}}type {{$typeName}} {{modeldef $td .}}
{{ $belongsto := index .Metadata "github.com/bketelsen/gorma#belongsto" }}
{{ $m2m := index .Metadata "github.com/bketelsen/gorma#many2many" }}
func {{$typeName}}FromCreatePayload(ctx *app.Create{{demodel $typeName}}Context) {{$typeName}} {
	payload := ctx.Payload
	m := {{$typeName}}{}
	copier.Copy(&m, payload)
	{{ if ne $belongsto "" }} m.{{ $belongsto }}ID=int(ctx.{{ demodel $belongsto }}ID){{end}}
	return m
}

func {{$typeName}}FromUpdatePayload(ctx *app.Update{{demodel $typeName}}Context) {{$typeName}} {
	payload := ctx.Payload
	m := {{$typeName}}{}
	copier.Copy(&m, payload)
	return m
}
func (m {{$typeName}}) ToApp() *app.{{demodel $typeName}} {
	target := app.{{demodel $typeName}}{}
	copier.Copy(&target, &m)
	return &target
}
{{ $roler := index .Metadata "github.com/bketelsen/gorma#roler" }}
{{ if ne $roler "" }}
func (m {{$typeName}}) GetRole() string {
	return m.Role
}
{{end}}

type {{$typeName}}Storage interface {
	List(ctx ctx.Context) []{{$typeName}}
	Get(ctx ctx.Context, id int) ({{$typeName}}, error)
	Add(ctx ctx.Context, o {{$typeName}}) ({{$typeName}}, error)
	Update(ctx ctx.Context, o {{$typeName}}) (error)
	Delete(ctx ctx.Context, id int) (error)
	{{ storagedef . }}
}

type {{$typeName}}DB struct {
	DB gorm.DB
}
/*{{ if ne $belongsto "" }}{{$barray := split $belongsto ","}}{{ range $idx, $bt := $barray}}
// would prefer to just pass a context in here, but they're all different, so can't
func {{$typeName}}Filter(parentid int, originaldb *gorm.DB) func(db *gorm.DB) *gorm.DB {
	if parentid > 0 {
		return func(db *gorm.DB) *gorm.DB {
			return db.Where("{{ snake $bt }}_id = ?", parentid)
		}
	} else {
		return func(db *gorm.DB) *gorm.DB {
			return db
		}
	}
}{{end}}{{end}}
*/
func New{{$typeName}}DB(db gorm.DB) *{{$typeName}}DB {
	return &{{$typeName}}DB{DB: db}
}

func (m *{{$typeName}}DB) List(ctx ctx.Context) []{{$typeName}} {

	var objs []{{$typeName}}
    m.DB.Find(&objs)
	return objs
}

func (m *{{$typeName}}DB) Get(ctx ctx.Context, id int) ({{$typeName}}, error) {

	var obj {{$typeName}}

	err := m.DB.Find(&obj, id).Error
	if err != nil {
		ctx.Error(err.Error())
	}
	return obj, err
}

func (m *{{$typeName}}DB) Add(ctx ctx.Context, model {{$typeName}}) ({{$typeName}}, error) {
	err := m.DB.Create(&model).Error
	return model, err
}
func (m *{{$typeName}}DB) Update(ctx ctx.Context, model {{$typeName}}) error {
	obj, err := m.Get(ctx, model.ID)
	if err != nil {
		return  err
	}
	err = m.DB.Model(&obj).Updates(model).Error
	if err != nil {
		ctx.Error(err.Error())
	}
	return err
}
func (m *{{$typeName}}DB) Delete(ctx ctx.Context, id int)  error {
	var obj {{$typeName}}
	err := m.DB.Delete(&obj, id).Error
	if err != nil {
		ctx.Logger.Error(err.Error())
		return  err
	}
	return  nil
}

{{ if ne $m2m "" }}{{$barray := split $m2m ","}}{{ range $idx, $bt := $barray}}
{{ $pieces := split $bt ":" }} {{ $lowertype := index $pieces 1  }} {{ $lower := lower $lowertype }}  {{ $lowerplural := index $pieces 0  }} {{ $lowerplural := lower $lowerplural}}
func (m *{{$typeName}}DB) Delete{{index $pieces 1}}(ctx ctx.Context, {{$lower}}ID int)  error {
	var obj {{$typeName}}

	var assoc {{index $pieces 1}}
	var err error
	assoc.ID = {{$lower}}ID
	if err != nil {
		return err
	}
	err = m.DB.Model(&obj).Association("{{index $pieces 0}}").Delete(assoc).Error
	if err != nil {
		ctx.Logger.Error(err.Error())
		return  err
	}
	return  nil
}
func (m *{{$typeName}}DB) Add{{index $pieces 1}}(ctx ctx.Context, {{lower $typeName}}ID, {{$lower}}ID int) error {
	var {{lower $typeName}} {{$typeName}}
	{{lower $typeName}}.ID = {{lower $typeName}}ID
	var assoc {{index $pieces 1}}
	assoc.ID = {{$lower}}ID
	err := m.DB.Model(&{{lower $typeName}}).Association("{{index $pieces 0}}").Append(assoc).Error
	if err != nil {
		ctx.Logger.Error(err.Error())
		return  err
	}
	return  nil
}
func (m *{{$typeName}}DB) List{{index $pieces 0}}(ctx ctx.Context, {{lower $typeName}}ID int)  []{{index $pieces 1}} {
	list := make([]{{index $pieces 1}}, 0)
	var obj {{$typeName}}
	obj.ID = {{lower $typeName}}ID
	err := m.DB.Model(&obj).Association("{{index $pieces 0}}").Find(&list).Error
	if err != nil {
		ctx.Logger.Error(err.Error())
		return  list
	}
	return  nil
}
{{end}}{{end}}
{{if ne $belongsto ""}}{{$barray := split $belongsto ","}}{{ range $idx, $bt := $barray}}
func Filter{{$typeName}}By{{$bt}}(parent int, list []{{$typeName}}) []{{$typeName}} {
	filtered := make([]{{$typeName}},0)
	for _,o := range list {
		if o.{{$bt}}ID == int(parent) {
			filtered = append(filtered,o)
		}
	}
	return filtered
}
{{end}}{{end}}
`
<commit_msg>decouple contexts<commit_after>package gorma

const modelTmpl = `// {{if .Description}}{{.Description}}{{else}}app.{{gotypename . 0}} storage type{{end}}
// Identifier: {{ $typeName :=  gotypename . 0}}{{$typeName := demodel $typeName}}
{{$td := gotypedef . 0 true false}}type {{$typeName}} {{modeldef $td .}}
{{ $belongsto := index .Metadata "github.com/bketelsen/gorma#belongsto" }}
{{ $m2m := index .Metadata "github.com/bketelsen/gorma#many2many" }}
func {{$typeName}}FromCreatePayload(ctx *app.Create{{demodel $typeName}}Context) {{$typeName}} {
	payload := ctx.Payload
	m := {{$typeName}}{}
	copier.Copy(&m, payload)
	{{ if ne $belongsto "" }} m.{{ $belongsto }}ID=int(ctx.{{ demodel $belongsto }}ID){{end}}
	return m
}

func {{$typeName}}FromUpdatePayload(ctx *app.Update{{demodel $typeName}}Context) {{$typeName}} {
	payload := ctx.Payload
	m := {{$typeName}}{}
	copier.Copy(&m, payload)
	return m
}
func (m {{$typeName}}) ToApp() *app.{{demodel $typeName}} {
	target := app.{{demodel $typeName}}{}
	copier.Copy(&target, &m)
	return &target
}
{{ $roler := index .Metadata "github.com/bketelsen/gorma#roler" }}
{{ if ne $roler "" }}
func (m {{$typeName}}) GetRole() string {
	return m.Role
}
{{end}}

type {{$typeName}}Storage interface {
	List(ctx context.Context) []{{$typeName}}
	Get(ctx context.Context, id int) ({{$typeName}}, error)
	Add(ctx context.Context, o {{$typeName}}) ({{$typeName}}, error)
	Update(ctx context.Context, o {{$typeName}}) (error)
	Delete(ctx context.Context, id int) (error)
	{{ storagedef . }}
}

type {{$typeName}}DB struct {
	DB gorm.DB
}
/*{{ if ne $belongsto "" }}{{$barray := split $belongsto ","}}{{ range $idx, $bt := $barray}}
// would prefer to just pass a context in here, but they're all different, so can't
func {{$typeName}}Filter(parentid int, originaldb *gorm.DB) func(db *gorm.DB) *gorm.DB {
	if parentid > 0 {
		return func(db *gorm.DB) *gorm.DB {
			return db.Where("{{ snake $bt }}_id = ?", parentid)
		}
	} else {
		return func(db *gorm.DB) *gorm.DB {
			return db
		}
	}
}{{end}}{{end}}
*/
func New{{$typeName}}DB(db gorm.DB) *{{$typeName}}DB {
	return &{{$typeName}}DB{DB: db}
}

func (m *{{$typeName}}DB) List(ctx context.Context) []{{$typeName}} {

	var objs []{{$typeName}}
    m.DB.Find(&objs)
	return objs
}

func (m *{{$typeName}}DB) Get(ctx context.Context, id int) ({{$typeName}}, error) {

	var obj {{$typeName}}

	err := m.DB.Find(&obj, id).Error
	if err != nil {
		ctx.Error(err.Error())
	}
	return obj, err
}

func (m *{{$typeName}}DB) Add(ctx context.Context, model {{$typeName}}) ({{$typeName}}, error) {
	err := m.DB.Create(&model).Error
	return model, err
}
func (m *{{$typeName}}DB) Update(ctx context.Context, model {{$typeName}}) error {
	obj, err := m.Get(ctx, model.ID)
	if err != nil {
		return  err
	}
	err = m.DB.Model(&obj).Updates(model).Error
	if err != nil {
		ctx.Error(err.Error())
	}
	return err
}
func (m *{{$typeName}}DB) Delete(ctx context.Context, id int)  error {
	var obj {{$typeName}}
	err := m.DB.Delete(&obj, id).Error
	if err != nil {
		ctx.Logger.Error(err.Error())
		return  err
	}
	return  nil
}

{{ if ne $m2m "" }}{{$barray := split $m2m ","}}{{ range $idx, $bt := $barray}}
{{ $pieces := split $bt ":" }} {{ $lowertype := index $pieces 1  }} {{ $lower := lower $lowertype }}  {{ $lowerplural := index $pieces 0  }} {{ $lowerplural := lower $lowerplural}}
func (m *{{$typeName}}DB) Delete{{index $pieces 1}}(ctx context.Context, {{$lower}}ID int)  error {
	var obj {{$typeName}}

	var assoc {{index $pieces 1}}
	var err error
	assoc.ID = {{$lower}}ID
	if err != nil {
		return err
	}
	err = m.DB.Model(&obj).Association("{{index $pieces 0}}").Delete(assoc).Error
	if err != nil {
		ctx.Logger.Error(err.Error())
		return  err
	}
	return  nil
}
func (m *{{$typeName}}DB) Add{{index $pieces 1}}(ctx context.Context, {{lower $typeName}}ID, {{$lower}}ID int) error {
	var {{lower $typeName}} {{$typeName}}
	{{lower $typeName}}.ID = {{lower $typeName}}ID
	var assoc {{index $pieces 1}}
	assoc.ID = {{$lower}}ID
	err := m.DB.Model(&{{lower $typeName}}).Association("{{index $pieces 0}}").Append(assoc).Error
	if err != nil {
		ctx.Logger.Error(err.Error())
		return  err
	}
	return  nil
}
func (m *{{$typeName}}DB) List{{index $pieces 0}}(ctx context.Context, {{lower $typeName}}ID int)  []{{index $pieces 1}} {
	list := make([]{{index $pieces 1}}, 0)
	var obj {{$typeName}}
	obj.ID = {{lower $typeName}}ID
	err := m.DB.Model(&obj).Association("{{index $pieces 0}}").Find(&list).Error
	if err != nil {
		ctx.Logger.Error(err.Error())
		return  list
	}
	return  nil
}
{{end}}{{end}}
{{if ne $belongsto ""}}{{$barray := split $belongsto ","}}{{ range $idx, $bt := $barray}}
func Filter{{$typeName}}By{{$bt}}(parent int, list []{{$typeName}}) []{{$typeName}} {
	filtered := make([]{{$typeName}},0)
	for _,o := range list {
		if o.{{$bt}}ID == int(parent) {
			filtered = append(filtered,o)
		}
	}
	return filtered
}
{{end}}{{end}}
`
<|endoftext|>