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

// +build js

package js

import (
	"log"
	"runtime"
	"syscall/js"
	"time"

	"github.com/hajimehoshi/ebiten/internal/devicescale"
	"github.com/hajimehoshi/ebiten/internal/driver"
	"github.com/hajimehoshi/ebiten/internal/graphicsdriver/opengl"
	"github.com/hajimehoshi/ebiten/internal/hooks"
	"github.com/hajimehoshi/ebiten/internal/jsutil"
)

type UserInterface struct {
	runnableInBackground bool
	vsync                bool
	running              bool

	sizeChanged bool
	contextLost bool

	lastDeviceScaleFactor float64

	context driver.UIContext
	input   Input
}

var theUI = &UserInterface{
	sizeChanged: true,
	vsync:       true,
}

func init() {
	theUI.input.ui = theUI
}

func Get() *UserInterface {
	return theUI
}

var (
	window                = js.Global().Get("window")
	document              = js.Global().Get("document")
	canvas                js.Value
	requestAnimationFrame = window.Get("requestAnimationFrame")
	setTimeout            = window.Get("setTimeout")
)

func (u *UserInterface) ScreenSizeInFullscreen() (int, int) {
	return window.Get("innerWidth").Int(), window.Get("innerHeight").Int()
}

func (u *UserInterface) SetFullscreen(fullscreen bool) {
	// Do nothing
}

func (u *UserInterface) IsFullscreen() bool {
	return false
}

func (u *UserInterface) IsForeground() bool {
	// TODO: implement this
	return true
}

func (u *UserInterface) SetRunnableInBackground(runnableInBackground bool) {
	u.runnableInBackground = runnableInBackground
}

func (u *UserInterface) IsRunnableInBackground() bool {
	return u.runnableInBackground
}

func (u *UserInterface) SetVsyncEnabled(enabled bool) {
	u.vsync = enabled
}

func (u *UserInterface) IsVsyncEnabled() bool {
	return u.vsync
}

func (u *UserInterface) CursorMode() driver.CursorMode {
	if canvas.Get("style").Get("cursor").String() != "none" {
		return driver.CursorModeVisible
	}
	return driver.CursorModeHidden
}

func (u *UserInterface) SetCursorMode(mode driver.CursorMode) {
	var visible bool
	switch mode {
	case driver.CursorModeVisible:
		visible = true
	case driver.CursorModeHidden:
		visible = false
	default:
		return
	}

	if visible {
		canvas.Get("style").Set("cursor", "auto")
	} else {
		canvas.Get("style").Set("cursor", "none")
	}
}

func (u *UserInterface) DeviceScaleFactor() float64 {
	return devicescale.GetAt(0, 0)
}

func (u *UserInterface) updateSize() {
	a := u.DeviceScaleFactor()
	if u.lastDeviceScaleFactor != a {
		u.updateScreenSize()
	}
	u.lastDeviceScaleFactor = a

	if u.sizeChanged {
		u.sizeChanged = false
		body := document.Get("body")
		bw := body.Get("clientWidth").Float()
		bh := body.Get("clientHeight").Float()
		u.context.Layout(bw, bh)
	}
}

func (u *UserInterface) suspended() bool {
	if u.runnableInBackground {
		return false
	}

	if !document.Call("hasFocus").Bool() {
		return true
	}
	if document.Get("hidden").Bool() {
		return true
	}
	return false
}

func (u *UserInterface) update() error {
	if u.suspended() {
		hooks.SuspendAudio()
		return nil
	}
	hooks.ResumeAudio()

	u.input.UpdateGamepads()
	u.updateSize()
	if err := u.context.Update(func() {
		u.updateSize()
	}); err != nil {
		return err
	}
	return nil
}

func (u *UserInterface) loop(context driver.UIContext) <-chan error {
	u.context = context

	ch := make(chan error)
	var cf js.Func
	f := func(this js.Value, args []js.Value) interface{} {
		if u.contextLost {
			requestAnimationFrame.Invoke(cf)
			return nil
		}

		if err := u.update(); err != nil {
			ch <- err
			close(ch)
			return nil
		}
		if u.vsync {
			requestAnimationFrame.Invoke(cf)
		} else {
			setTimeout.Invoke(cf, 0)
		}
		return nil
	}
	// TODO: Should cf be released after the game ends?
	cf = js.FuncOf(f)
	// Call f asyncly to be async since ch is used in f.
	go func() {
		f(js.Value{}, nil)
	}()

	// Run another loop to watch suspended() as the above update function is never called when the tab is hidden.
	// To check the document's visiblity, visibilitychange event should usually be used. However, this event is
	// not reliable and sometimes it is not fired (#961). Then, watch the state regularly instead.
	go func() {
		t := time.NewTicker(100 * time.Millisecond)
		defer t.Stop()
		for range t.C {
			if u.suspended() {
				hooks.SuspendAudio()
			} else {
				hooks.ResumeAudio()
			}
		}
	}()

	return ch
}

func init() {
	if jsutil.Equal(document.Get("body"), js.Null()) {
		ch := make(chan struct{})
		window.Call("addEventListener", "load", js.FuncOf(func(this js.Value, args []js.Value) interface{} {
			close(ch)
			return nil
		}))
		<-ch
	}

	window.Call("addEventListener", "resize", js.FuncOf(func(this js.Value, args []js.Value) interface{} {
		theUI.updateScreenSize()
		return nil
	}))

	// Adjust the initial scale to 1.
	// https://developer.mozilla.org/en/docs/Mozilla/Mobile/Viewport_meta_tag
	meta := document.Call("createElement", "meta")
	meta.Set("name", "viewport")
	meta.Set("content", "width=device-width, initial-scale=1")
	document.Get("head").Call("appendChild", meta)

	canvas = document.Call("createElement", "canvas")
	canvas.Set("width", 16)
	canvas.Set("height", 16)

	document.Get("body").Call("appendChild", canvas)

	htmlStyle := document.Get("documentElement").Get("style")
	htmlStyle.Set("height", "100%")
	htmlStyle.Set("margin", "0")
	htmlStyle.Set("padding", "0")

	bodyStyle := document.Get("body").Get("style")
	bodyStyle.Set("backgroundColor", "#000")
	bodyStyle.Set("height", "100%")
	bodyStyle.Set("margin", "0")
	bodyStyle.Set("padding", "0")

	// TODO: This is OK as long as the game is in an independent iframe.
	// What if the canvas is embedded in a HTML directly?
	document.Get("body").Call("addEventListener", "click", js.FuncOf(func(this js.Value, args []js.Value) interface{} {
		canvas.Call("focus")
		return nil
	}))

	canvasStyle := canvas.Get("style")
	canvasStyle.Set("width", "100%")
	canvasStyle.Set("height", "100%")
	canvasStyle.Set("margin", "0")
	canvasStyle.Set("padding", "0")

	// Make the canvas focusable.
	canvas.Call("setAttribute", "tabindex", 1)
	canvas.Get("style").Set("outline", "none")

	// Keyboard
	canvas.Call("addEventListener", "keydown", js.FuncOf(func(this js.Value, args []js.Value) interface{} {
		// Focus the canvas explicitly to activate tha game (#961).
		canvas.Call("focus")

		e := args[0]
		// Don't 'preventDefault' on keydown events or keypress events wouldn't work (#715).
		theUI.input.Update(e)
		return nil
	}))
	canvas.Call("addEventListener", "keypress", js.FuncOf(func(this js.Value, args []js.Value) interface{} {
		e := args[0]
		e.Call("preventDefault")
		theUI.input.Update(e)
		return nil
	}))
	canvas.Call("addEventListener", "keyup", js.FuncOf(func(this js.Value, args []js.Value) interface{} {
		e := args[0]
		e.Call("preventDefault")
		theUI.input.Update(e)
		return nil
	}))

	// Mouse
	canvas.Call("addEventListener", "mousedown", js.FuncOf(func(this js.Value, args []js.Value) interface{} {
		// Focus the canvas explicitly to activate tha game (#961).
		canvas.Call("focus")

		e := args[0]
		e.Call("preventDefault")
		theUI.input.Update(e)
		return nil
	}))
	canvas.Call("addEventListener", "mouseup", js.FuncOf(func(this js.Value, args []js.Value) interface{} {
		e := args[0]
		e.Call("preventDefault")
		theUI.input.Update(e)
		return nil
	}))
	canvas.Call("addEventListener", "mousemove", js.FuncOf(func(this js.Value, args []js.Value) interface{} {
		e := args[0]
		e.Call("preventDefault")
		theUI.input.Update(e)
		return nil
	}))
	canvas.Call("addEventListener", "wheel", js.FuncOf(func(this js.Value, args []js.Value) interface{} {
		e := args[0]
		e.Call("preventDefault")
		theUI.input.Update(e)
		return nil
	}))

	// Touch
	canvas.Call("addEventListener", "touchstart", js.FuncOf(func(this js.Value, args []js.Value) interface{} {
		// Focus the canvas explicitly to activate tha game (#961).
		canvas.Call("focus")

		e := args[0]
		e.Call("preventDefault")
		theUI.input.Update(e)
		return nil
	}))
	canvas.Call("addEventListener", "touchend", js.FuncOf(func(this js.Value, args []js.Value) interface{} {
		e := args[0]
		e.Call("preventDefault")
		theUI.input.Update(e)
		return nil
	}))
	canvas.Call("addEventListener", "touchmove", js.FuncOf(func(this js.Value, args []js.Value) interface{} {
		e := args[0]
		e.Call("preventDefault")
		theUI.input.Update(e)
		return nil
	}))

	// Gamepad
	window.Call("addEventListener", "gamepadconnected", js.FuncOf(func(this js.Value, args []js.Value) interface{} {
		// Do nothing.
		return nil
	}))

	canvas.Call("addEventListener", "contextmenu", js.FuncOf(func(this js.Value, args []js.Value) interface{} {
		e := args[0]
		e.Call("preventDefault")
		return nil
	}))

	// Context
	canvas.Call("addEventListener", "webglcontextlost", js.FuncOf(func(this js.Value, args []js.Value) interface{} {
		e := args[0]
		e.Call("preventDefault")
		theUI.contextLost = true
		return nil
	}))
	canvas.Call("addEventListener", "webglcontextrestored", js.FuncOf(func(this js.Value, args []js.Value) interface{} {
		theUI.contextLost = false
		return nil
	}))
}

func (u *UserInterface) Run(context driver.UIContext) error {
	canvas.Call("focus")
	u.running = true
	ch := u.loop(context)
	if runtime.GOARCH == "wasm" {
		return <-ch
	}

	// On GopherJS, the main goroutine cannot be blocked due to the bug (gopherjs/gopherjs#826).
	// Return immediately.
	go func() {
		defer func() {
			u.running = false
		}()
		if err := <-ch; err != nil {
			log.Fatal(err)
		}
	}()
	return nil
}

func (u *UserInterface) RunWithoutMainLoop(width, height int, scale float64, title string, context driver.UIContext) <-chan error {
	panic("js: RunWithoutMainLoop is not implemented")
}

func (u *UserInterface) updateScreenSize() {
	body := document.Get("body")
	bw := int(body.Get("clientWidth").Float() * u.DeviceScaleFactor())
	bh := int(body.Get("clientHeight").Float() * u.DeviceScaleFactor())
	canvas.Set("width", bw)
	canvas.Set("height", bh)
	u.sizeChanged = true
}

func (u *UserInterface) SetScreenTransparent(transparent bool) {
	if u.running {
		panic("js: SetScreenTransparent can't be called after the main loop starts")
	}

	bodyStyle := document.Get("body").Get("style")
	if transparent {
		bodyStyle.Set("backgroundColor", "transparent")
	} else {
		bodyStyle.Set("backgroundColor", "#000")
	}
}

func (u *UserInterface) IsScreenTransparent() bool {
	bodyStyle := document.Get("body").Get("style")
	return bodyStyle.Get("backgroundColor").String() == "transparent"
}

func (u *UserInterface) MonitorPosition() (int, int) {
	return 0, 0
}

func (u *UserInterface) Input() driver.Input {
	return &u.input
}

func (u *UserInterface) Window() driver.Window {
	return nil
}

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

// +build js

package js

import (
	"log"
	"runtime"
	"syscall/js"
	"time"

	"github.com/hajimehoshi/ebiten/internal/devicescale"
	"github.com/hajimehoshi/ebiten/internal/driver"
	"github.com/hajimehoshi/ebiten/internal/graphicsdriver/opengl"
	"github.com/hajimehoshi/ebiten/internal/hooks"
	"github.com/hajimehoshi/ebiten/internal/jsutil"
)

type UserInterface struct {
	runnableInBackground bool
	vsync                bool
	running              bool

	sizeChanged bool
	contextLost bool

	lastDeviceScaleFactor float64

	context driver.UIContext
	input   Input
}

var theUI = &UserInterface{
	sizeChanged: true,
	vsync:       true,
}

func init() {
	theUI.input.ui = theUI
}

func Get() *UserInterface {
	return theUI
}

var (
	window                = js.Global().Get("window")
	document              = js.Global().Get("document")
	canvas                js.Value
	requestAnimationFrame = window.Get("requestAnimationFrame")
	setTimeout            = window.Get("setTimeout")
)

func (u *UserInterface) ScreenSizeInFullscreen() (int, int) {
	return window.Get("innerWidth").Int(), window.Get("innerHeight").Int()
}

func (u *UserInterface) SetFullscreen(fullscreen bool) {
	// Do nothing
}

func (u *UserInterface) IsFullscreen() bool {
	return false
}

func (u *UserInterface) IsForeground() bool {
	return u.isForeground()
}

func (u *UserInterface) SetRunnableInBackground(runnableInBackground bool) {
	u.runnableInBackground = runnableInBackground
}

func (u *UserInterface) IsRunnableInBackground() bool {
	return u.runnableInBackground
}

func (u *UserInterface) SetVsyncEnabled(enabled bool) {
	u.vsync = enabled
}

func (u *UserInterface) IsVsyncEnabled() bool {
	return u.vsync
}

func (u *UserInterface) CursorMode() driver.CursorMode {
	if canvas.Get("style").Get("cursor").String() != "none" {
		return driver.CursorModeVisible
	}
	return driver.CursorModeHidden
}

func (u *UserInterface) SetCursorMode(mode driver.CursorMode) {
	var visible bool
	switch mode {
	case driver.CursorModeVisible:
		visible = true
	case driver.CursorModeHidden:
		visible = false
	default:
		return
	}

	if visible {
		canvas.Get("style").Set("cursor", "auto")
	} else {
		canvas.Get("style").Set("cursor", "none")
	}
}

func (u *UserInterface) DeviceScaleFactor() float64 {
	return devicescale.GetAt(0, 0)
}

func (u *UserInterface) updateSize() {
	a := u.DeviceScaleFactor()
	if u.lastDeviceScaleFactor != a {
		u.updateScreenSize()
	}
	u.lastDeviceScaleFactor = a

	if u.sizeChanged {
		u.sizeChanged = false
		body := document.Get("body")
		bw := body.Get("clientWidth").Float()
		bh := body.Get("clientHeight").Float()
		u.context.Layout(bw, bh)
	}
}

func (u *UserInterface) suspended() bool {
	if u.runnableInBackground {
		return false
	}
	return !u.isForeground()
}

func (u *UserInterface) isForeground() bool {
	if !document.Call("hasFocus").Bool() {
		return false
	}
	if document.Get("hidden").Bool() {
		return false
	}
	return true
}

func (u *UserInterface) update() error {
	if u.suspended() {
		hooks.SuspendAudio()
		return nil
	}
	hooks.ResumeAudio()

	u.input.UpdateGamepads()
	u.updateSize()
	if err := u.context.Update(func() {
		u.updateSize()
	}); err != nil {
		return err
	}
	return nil
}

func (u *UserInterface) loop(context driver.UIContext) <-chan error {
	u.context = context

	ch := make(chan error)
	var cf js.Func
	f := func(this js.Value, args []js.Value) interface{} {
		if u.contextLost {
			requestAnimationFrame.Invoke(cf)
			return nil
		}

		if err := u.update(); err != nil {
			ch <- err
			close(ch)
			return nil
		}
		if u.vsync {
			requestAnimationFrame.Invoke(cf)
		} else {
			setTimeout.Invoke(cf, 0)
		}
		return nil
	}
	// TODO: Should cf be released after the game ends?
	cf = js.FuncOf(f)
	// Call f asyncly to be async since ch is used in f.
	go func() {
		f(js.Value{}, nil)
	}()

	// Run another loop to watch suspended() as the above update function is never called when the tab is hidden.
	// To check the document's visiblity, visibilitychange event should usually be used. However, this event is
	// not reliable and sometimes it is not fired (#961). Then, watch the state regularly instead.
	go func() {
		t := time.NewTicker(100 * time.Millisecond)
		defer t.Stop()
		for range t.C {
			if u.suspended() {
				hooks.SuspendAudio()
			} else {
				hooks.ResumeAudio()
			}
		}
	}()

	return ch
}

func init() {
	if jsutil.Equal(document.Get("body"), js.Null()) {
		ch := make(chan struct{})
		window.Call("addEventListener", "load", js.FuncOf(func(this js.Value, args []js.Value) interface{} {
			close(ch)
			return nil
		}))
		<-ch
	}

	window.Call("addEventListener", "resize", js.FuncOf(func(this js.Value, args []js.Value) interface{} {
		theUI.updateScreenSize()
		return nil
	}))

	// Adjust the initial scale to 1.
	// https://developer.mozilla.org/en/docs/Mozilla/Mobile/Viewport_meta_tag
	meta := document.Call("createElement", "meta")
	meta.Set("name", "viewport")
	meta.Set("content", "width=device-width, initial-scale=1")
	document.Get("head").Call("appendChild", meta)

	canvas = document.Call("createElement", "canvas")
	canvas.Set("width", 16)
	canvas.Set("height", 16)

	document.Get("body").Call("appendChild", canvas)

	htmlStyle := document.Get("documentElement").Get("style")
	htmlStyle.Set("height", "100%")
	htmlStyle.Set("margin", "0")
	htmlStyle.Set("padding", "0")

	bodyStyle := document.Get("body").Get("style")
	bodyStyle.Set("backgroundColor", "#000")
	bodyStyle.Set("height", "100%")
	bodyStyle.Set("margin", "0")
	bodyStyle.Set("padding", "0")

	// TODO: This is OK as long as the game is in an independent iframe.
	// What if the canvas is embedded in a HTML directly?
	document.Get("body").Call("addEventListener", "click", js.FuncOf(func(this js.Value, args []js.Value) interface{} {
		canvas.Call("focus")
		return nil
	}))

	canvasStyle := canvas.Get("style")
	canvasStyle.Set("width", "100%")
	canvasStyle.Set("height", "100%")
	canvasStyle.Set("margin", "0")
	canvasStyle.Set("padding", "0")

	// Make the canvas focusable.
	canvas.Call("setAttribute", "tabindex", 1)
	canvas.Get("style").Set("outline", "none")

	// Keyboard
	canvas.Call("addEventListener", "keydown", js.FuncOf(func(this js.Value, args []js.Value) interface{} {
		// Focus the canvas explicitly to activate tha game (#961).
		canvas.Call("focus")

		e := args[0]
		// Don't 'preventDefault' on keydown events or keypress events wouldn't work (#715).
		theUI.input.Update(e)
		return nil
	}))
	canvas.Call("addEventListener", "keypress", js.FuncOf(func(this js.Value, args []js.Value) interface{} {
		e := args[0]
		e.Call("preventDefault")
		theUI.input.Update(e)
		return nil
	}))
	canvas.Call("addEventListener", "keyup", js.FuncOf(func(this js.Value, args []js.Value) interface{} {
		e := args[0]
		e.Call("preventDefault")
		theUI.input.Update(e)
		return nil
	}))

	// Mouse
	canvas.Call("addEventListener", "mousedown", js.FuncOf(func(this js.Value, args []js.Value) interface{} {
		// Focus the canvas explicitly to activate tha game (#961).
		canvas.Call("focus")

		e := args[0]
		e.Call("preventDefault")
		theUI.input.Update(e)
		return nil
	}))
	canvas.Call("addEventListener", "mouseup", js.FuncOf(func(this js.Value, args []js.Value) interface{} {
		e := args[0]
		e.Call("preventDefault")
		theUI.input.Update(e)
		return nil
	}))
	canvas.Call("addEventListener", "mousemove", js.FuncOf(func(this js.Value, args []js.Value) interface{} {
		e := args[0]
		e.Call("preventDefault")
		theUI.input.Update(e)
		return nil
	}))
	canvas.Call("addEventListener", "wheel", js.FuncOf(func(this js.Value, args []js.Value) interface{} {
		e := args[0]
		e.Call("preventDefault")
		theUI.input.Update(e)
		return nil
	}))

	// Touch
	canvas.Call("addEventListener", "touchstart", js.FuncOf(func(this js.Value, args []js.Value) interface{} {
		// Focus the canvas explicitly to activate tha game (#961).
		canvas.Call("focus")

		e := args[0]
		e.Call("preventDefault")
		theUI.input.Update(e)
		return nil
	}))
	canvas.Call("addEventListener", "touchend", js.FuncOf(func(this js.Value, args []js.Value) interface{} {
		e := args[0]
		e.Call("preventDefault")
		theUI.input.Update(e)
		return nil
	}))
	canvas.Call("addEventListener", "touchmove", js.FuncOf(func(this js.Value, args []js.Value) interface{} {
		e := args[0]
		e.Call("preventDefault")
		theUI.input.Update(e)
		return nil
	}))

	// Gamepad
	window.Call("addEventListener", "gamepadconnected", js.FuncOf(func(this js.Value, args []js.Value) interface{} {
		// Do nothing.
		return nil
	}))

	canvas.Call("addEventListener", "contextmenu", js.FuncOf(func(this js.Value, args []js.Value) interface{} {
		e := args[0]
		e.Call("preventDefault")
		return nil
	}))

	// Context
	canvas.Call("addEventListener", "webglcontextlost", js.FuncOf(func(this js.Value, args []js.Value) interface{} {
		e := args[0]
		e.Call("preventDefault")
		theUI.contextLost = true
		return nil
	}))
	canvas.Call("addEventListener", "webglcontextrestored", js.FuncOf(func(this js.Value, args []js.Value) interface{} {
		theUI.contextLost = false
		return nil
	}))
}

func (u *UserInterface) Run(context driver.UIContext) error {
	canvas.Call("focus")
	u.running = true
	ch := u.loop(context)
	if runtime.GOARCH == "wasm" {
		return <-ch
	}

	// On GopherJS, the main goroutine cannot be blocked due to the bug (gopherjs/gopherjs#826).
	// Return immediately.
	go func() {
		defer func() {
			u.running = false
		}()
		if err := <-ch; err != nil {
			log.Fatal(err)
		}
	}()
	return nil
}

func (u *UserInterface) RunWithoutMainLoop(width, height int, scale float64, title string, context driver.UIContext) <-chan error {
	panic("js: RunWithoutMainLoop is not implemented")
}

func (u *UserInterface) updateScreenSize() {
	body := document.Get("body")
	bw := int(body.Get("clientWidth").Float() * u.DeviceScaleFactor())
	bh := int(body.Get("clientHeight").Float() * u.DeviceScaleFactor())
	canvas.Set("width", bw)
	canvas.Set("height", bh)
	u.sizeChanged = true
}

func (u *UserInterface) SetScreenTransparent(transparent bool) {
	if u.running {
		panic("js: SetScreenTransparent can't be called after the main loop starts")
	}

	bodyStyle := document.Get("body").Get("style")
	if transparent {
		bodyStyle.Set("backgroundColor", "transparent")
	} else {
		bodyStyle.Set("backgroundColor", "#000")
	}
}

func (u *UserInterface) IsScreenTransparent() bool {
	bodyStyle := document.Get("body").Get("style")
	return bodyStyle.Get("backgroundColor").String() == "transparent"
}

func (u *UserInterface) MonitorPosition() (int, int) {
	return 0, 0
}

func (u *UserInterface) Input() driver.Input {
	return &u.input
}

func (u *UserInterface) Window() driver.Window {
	return nil
}

func (*UserInterface) Graphics() driver.Graphics {
	return opengl.Get()
}
<|endoftext|>


<commit_before>/*
Copyright 2016 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package vfs

import (
	"fmt"
	"os"
	"sync"
	"time"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/credentials"
	"github.com/aws/aws-sdk-go/aws/endpoints"
	"github.com/aws/aws-sdk-go/aws/session"
	"github.com/aws/aws-sdk-go/service/ec2"
	"github.com/aws/aws-sdk-go/service/s3"
	"github.com/golang/glog"
)

type S3Context struct {
	mutex           sync.Mutex
	clients         map[string]*s3.S3
	bucketLocations map[string]string
}

func NewS3Context() *S3Context {
	return &S3Context{
		clients:         make(map[string]*s3.S3),
		bucketLocations: make(map[string]string),
	}
}

func (s *S3Context) getClient(region string) (*s3.S3, error) {
	s.mutex.Lock()
	defer s.mutex.Unlock()

	s3Client := s.clients[region]
	if s3Client == nil {
		var config *aws.Config
		var err error
		endpoint := os.Getenv("S3_ENDPOINT")
		if endpoint == "" {
			config = aws.NewConfig().WithRegion(region)
			config = config.WithCredentialsChainVerboseErrors(true)
		} else {
			// Use customized S3 storage
			glog.Infof("Found S3_ENDPOINT=%q, using as non-AWS S3 backend", endpoint)
			config, err = getCustomS3Config(endpoint, region)
			if err != nil {
				return nil, err
			}
		}

		sess, err := session.NewSession()
		if err != nil {
			return nil, err
		}
		s3Client = s3.New(sess, config)
		s.clients[region] = s3Client
	}

	return s3Client, nil
}

func getCustomS3Config(endpoint string, region string) (*aws.Config, error) {
	accessKeyID := os.Getenv("S3_ACCESS_KEY_ID")
	if accessKeyID == "" {
		return nil, fmt.Errorf("S3_ACCESS_KEY_ID cannot be empty when S3_ENDPOINT is not empty")
	}
	secretAccessKey := os.Getenv("S3_SECRET_ACCESS_KEY")
	if secretAccessKey == "" {
		return nil, fmt.Errorf("S3_SECRET_ACCESS_KEY cannot be empty when S3_ENDPOINT is not empty")
	}

	s3Config := &aws.Config{
		Credentials:      credentials.NewStaticCredentials(accessKeyID, secretAccessKey, ""),
		Endpoint:         aws.String(endpoint),
		Region:           aws.String(region),
		S3ForcePathStyle: aws.Bool(true),
	}

	return s3Config, nil
}

func (s *S3Context) getRegionForBucket(bucket string) (string, error) {
	region := func() string {
		s.mutex.Lock()
		defer s.mutex.Unlock()
		return s.bucketLocations[bucket]
	}()

	if region != "" {
		return region, nil
	}

	// Probe to find correct region for bucket
	endpoint := os.Getenv("S3_ENDPOINT")
	if endpoint != "" {
		// If customized S3 storage is set, return user-defined region
		region = os.Getenv("S3_REGION")
		if region == "" {
			region = "us-east-1"
		}
		return region, nil
	}

	awsRegion := os.Getenv("AWS_REGION")
	if awsRegion == "" {
		awsRegion = "us-east-1"
	}

	if err := validateRegion(awsRegion); err != nil {
		return "", err
	}

	request := &s3.GetBucketLocationInput{
		Bucket: &bucket,
	}
	var response *s3.GetBucketLocationOutput

	s3Client, err := s.getClient(awsRegion)
	if err != nil {
		return "", fmt.Errorf("error connecting to S3: %s", err)
	}
	// Attempt one GetBucketLocation call the "normal" way (i.e. as the bucket owner)
	response, err = s3Client.GetBucketLocation(request)

	// and fallback to brute-forcing if it fails
	if err != nil {
		glog.V(2).Infof("unable to get bucket location from region %q; scanning all regions: %v", awsRegion, err)
		response, err = bruteforceBucketLocation(&awsRegion, request)
	}

	if err != nil {
		return "", err
	}

	if response.LocationConstraint == nil {
		// US Classic does not return a region
		region = "us-east-1"
	} else {
		region = *response.LocationConstraint
		// Another special case: "EU" can mean eu-west-1
		if region == "EU" {
			region = "eu-west-1"
		}
	}
	glog.V(2).Infof("Found bucket %q in region %q", bucket, region)

	s.mutex.Lock()
	defer s.mutex.Unlock()
	s.bucketLocations[bucket] = region

	return region, nil
}

/*
Amazon's S3 API provides the GetBucketLocation call to determine the region in which a bucket is located.
This call can however only be used globally by the owner of the bucket, as mentioned on the documentation page.

For S3 buckets that are shared across multiple AWS accounts using bucket policies the call will only work if it is sent
to the correct region in the first place.

This method will attempt to "bruteforce" the bucket location by sending a request to every available region and picking
out the first result.

See also: https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetBucketLocationRequest
*/
func bruteforceBucketLocation(region *string, request *s3.GetBucketLocationInput) (*s3.GetBucketLocationOutput, error) {
	session, _ := session.NewSession(&aws.Config{Region: region})

	regions, err := ec2.New(session).DescribeRegions(nil)
	if err != nil {
		return nil, fmt.Errorf("Unable to list AWS regions: %v", err)
	}

	glog.V(2).Infof("Querying S3 for bucket location for %s", *request.Bucket)

	out := make(chan *s3.GetBucketLocationOutput, len(regions.Regions))
	for _, region := range regions.Regions {
		go func(regionName string) {
			glog.V(8).Infof("Doing GetBucketLocation in %q", regionName)
			s3Client := s3.New(session, &aws.Config{Region: aws.String(regionName)})
			result, bucketError := s3Client.GetBucketLocation(request)
			if bucketError == nil {
				glog.V(8).Infof("GetBucketLocation succeeded in %q", regionName)
				out <- result
			}
		}(*region.RegionName)
	}

	select {
	case bucketLocation := <-out:
		return bucketLocation, nil
	case <-time.After(5 * time.Second):
		return nil, fmt.Errorf("Could not retrieve location for AWS bucket %s", *request.Bucket)
	}
}

func validateRegion(region string) error {
	resolver := endpoints.DefaultResolver()
	partitions := resolver.(endpoints.EnumPartitions).Partitions()
	for _, p := range partitions {
		for _, r := range p.Regions() {
			if r.ID() == region {
				return nil
			}
		}
	}
	return fmt.Errorf("%s is not a valid region\nPlease check that your region is formatted correctly (i.e. us-east-1)", region)
}
<commit_msg>Wrap AWS NewSession() errors in vfs package<commit_after>/*
Copyright 2016 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package vfs

import (
	"fmt"
	"os"
	"sync"
	"time"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/credentials"
	"github.com/aws/aws-sdk-go/aws/endpoints"
	"github.com/aws/aws-sdk-go/aws/session"
	"github.com/aws/aws-sdk-go/service/ec2"
	"github.com/aws/aws-sdk-go/service/s3"
	"github.com/golang/glog"
)

type S3Context struct {
	mutex           sync.Mutex
	clients         map[string]*s3.S3
	bucketLocations map[string]string
}

func NewS3Context() *S3Context {
	return &S3Context{
		clients:         make(map[string]*s3.S3),
		bucketLocations: make(map[string]string),
	}
}

func (s *S3Context) getClient(region string) (*s3.S3, error) {
	s.mutex.Lock()
	defer s.mutex.Unlock()

	s3Client := s.clients[region]
	if s3Client == nil {
		var config *aws.Config
		var err error
		endpoint := os.Getenv("S3_ENDPOINT")
		if endpoint == "" {
			config = aws.NewConfig().WithRegion(region)
			config = config.WithCredentialsChainVerboseErrors(true)
		} else {
			// Use customized S3 storage
			glog.Infof("Found S3_ENDPOINT=%q, using as non-AWS S3 backend", endpoint)
			config, err = getCustomS3Config(endpoint, region)
			if err != nil {
				return nil, err
			}
		}

		sess, err := session.NewSession()
		if err != nil {
			return nil, fmt.Errorf("error starting new AWS session:%v", err)
		}
		s3Client = s3.New(sess, config)
		s.clients[region] = s3Client
	}

	return s3Client, nil
}

func getCustomS3Config(endpoint string, region string) (*aws.Config, error) {
	accessKeyID := os.Getenv("S3_ACCESS_KEY_ID")
	if accessKeyID == "" {
		return nil, fmt.Errorf("S3_ACCESS_KEY_ID cannot be empty when S3_ENDPOINT is not empty")
	}
	secretAccessKey := os.Getenv("S3_SECRET_ACCESS_KEY")
	if secretAccessKey == "" {
		return nil, fmt.Errorf("S3_SECRET_ACCESS_KEY cannot be empty when S3_ENDPOINT is not empty")
	}

	s3Config := &aws.Config{
		Credentials:      credentials.NewStaticCredentials(accessKeyID, secretAccessKey, ""),
		Endpoint:         aws.String(endpoint),
		Region:           aws.String(region),
		S3ForcePathStyle: aws.Bool(true),
	}

	return s3Config, nil
}

func (s *S3Context) getRegionForBucket(bucket string) (string, error) {
	region := func() string {
		s.mutex.Lock()
		defer s.mutex.Unlock()
		return s.bucketLocations[bucket]
	}()

	if region != "" {
		return region, nil
	}

	// Probe to find correct region for bucket
	endpoint := os.Getenv("S3_ENDPOINT")
	if endpoint != "" {
		// If customized S3 storage is set, return user-defined region
		region = os.Getenv("S3_REGION")
		if region == "" {
			region = "us-east-1"
		}
		return region, nil
	}

	awsRegion := os.Getenv("AWS_REGION")
	if awsRegion == "" {
		awsRegion = "us-east-1"
	}

	if err := validateRegion(awsRegion); err != nil {
		return "", err
	}

	request := &s3.GetBucketLocationInput{
		Bucket: &bucket,
	}
	var response *s3.GetBucketLocationOutput

	s3Client, err := s.getClient(awsRegion)
	if err != nil {
		return "", fmt.Errorf("error connecting to S3: %s", err)
	}
	// Attempt one GetBucketLocation call the "normal" way (i.e. as the bucket owner)
	response, err = s3Client.GetBucketLocation(request)

	// and fallback to brute-forcing if it fails
	if err != nil {
		glog.V(2).Infof("unable to get bucket location from region %q; scanning all regions: %v", awsRegion, err)
		response, err = bruteforceBucketLocation(&awsRegion, request)
	}

	if err != nil {
		return "", err
	}

	if response.LocationConstraint == nil {
		// US Classic does not return a region
		region = "us-east-1"
	} else {
		region = *response.LocationConstraint
		// Another special case: "EU" can mean eu-west-1
		if region == "EU" {
			region = "eu-west-1"
		}
	}
	glog.V(2).Infof("Found bucket %q in region %q", bucket, region)

	s.mutex.Lock()
	defer s.mutex.Unlock()
	s.bucketLocations[bucket] = region

	return region, nil
}

/*
Amazon's S3 API provides the GetBucketLocation call to determine the region in which a bucket is located.
This call can however only be used globally by the owner of the bucket, as mentioned on the documentation page.

For S3 buckets that are shared across multiple AWS accounts using bucket policies the call will only work if it is sent
to the correct region in the first place.

This method will attempt to "bruteforce" the bucket location by sending a request to every available region and picking
out the first result.

See also: https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetBucketLocationRequest
*/
func bruteforceBucketLocation(region *string, request *s3.GetBucketLocationInput) (*s3.GetBucketLocationOutput, error) {
	session, _ := session.NewSession(&aws.Config{Region: region})

	regions, err := ec2.New(session).DescribeRegions(nil)
	if err != nil {
		return nil, fmt.Errorf("Unable to list AWS regions: %v", err)
	}

	glog.V(2).Infof("Querying S3 for bucket location for %s", *request.Bucket)

	out := make(chan *s3.GetBucketLocationOutput, len(regions.Regions))
	for _, region := range regions.Regions {
		go func(regionName string) {
			glog.V(8).Infof("Doing GetBucketLocation in %q", regionName)
			s3Client := s3.New(session, &aws.Config{Region: aws.String(regionName)})
			result, bucketError := s3Client.GetBucketLocation(request)
			if bucketError == nil {
				glog.V(8).Infof("GetBucketLocation succeeded in %q", regionName)
				out <- result
			}
		}(*region.RegionName)
	}

	select {
	case bucketLocation := <-out:
		return bucketLocation, nil
	case <-time.After(5 * time.Second):
		return nil, fmt.Errorf("Could not retrieve location for AWS bucket %s", *request.Bucket)
	}
}

func validateRegion(region string) error {
	resolver := endpoints.DefaultResolver()
	partitions := resolver.(endpoints.EnumPartitions).Partitions()
	for _, p := range partitions {
		for _, r := range p.Regions() {
			if r.ID() == region {
				return nil
			}
		}
	}
	return fmt.Errorf("%s is not a valid region\nPlease check that your region is formatted correctly (i.e. us-east-1)", region)
}
<|endoftext|>


<commit_before>package azure

import (
	"encoding/xml"
	"errors"
	"fmt"

	"koding/kites/kloud/stack"
	"koding/kites/kloud/stack/provider"

	"github.com/Azure/azure-sdk-for-go/management"
	vm "github.com/Azure/azure-sdk-for-go/management/virtualmachine"
)

var p = &provider.Provider{
	Name:         "azure",
	ResourceName: "instance",
	Machine:      newMachine,
	Stack:        newStack,
	Schema: &provider.Schema{
		NewCredential: newCredential,
		NewBootstrap:  newBootstrap,
		NewMetadata:   newMetadata,
	},
}

func init() {
	provider.Register(p)
}

func newMachine(bm *provider.BaseMachine) (provider.Machine, error) {
	m := &Machine{BaseMachine: bm}
	cred := m.Cred()

	c, err := management.ClientFromPublishSettingsDataWithConfig(cred.PublishSettings, cred.SubscriptionID, management.DefaultConfig())
	if err != nil {
		return nil, err
	}

	vmclient := vm.NewClient(c)

	m.AzureClient = c
	m.AzureVMClient = &vmclient

	return m, nil
}

func newStack(bs *provider.BaseStack) (provider.Stack, error) {
	return &Stack{BaseStack: bs}, nil
}

func newCredential() interface{} {
	return &Cred{}
}

func newBootstrap() interface{} {
	return &Bootstrap{}
}

func newMetadata(m *stack.Machine) interface{} {
	if m == nil {
		return &Meta{}
	}

	meta := &Meta{
		InstanceID:      m.Attributes["id"],
		HostedServiceID: m.Attributes["hosted_service_name"],
		InstanceType:    m.Attributes["size"],
	}

	if cred, ok := m.Credential.Credential.(*Cred); ok {
		meta.Location = cred.Location
	}

	return meta
}

type PublishData struct {
	Subscriptions []Subscription `xml:"PublishProfile>Subscription"`
}

type Subscription struct {
	ID string `xml:"Id,attr"`
}

// Cred represents jCredentialDatas.meta for "azure" provider.
type Cred struct {
	// Credentials.
	PublishSettings []byte `json:"publish_settings" bson:"publish_settings" hcl:"publish_settings"` // required
	SubscriptionID  string `json:"subscription_id,omitempty" bson:"subscription_id,omitempty" hcl:"subscription_id"`
	Location        string `json:"location,omitempty" bson:"location,omitempty" hcl:"location"` // by default "East US 2"
}

var _ stack.Validator = (*Cred)(nil)

func (meta *Cred) PublishData() (*PublishData, error) {
	var pb PublishData

	if err := xml.Unmarshal(meta.PublishSettings, &pb); err != nil {
		return nil, err
	}

	if len(pb.Subscriptions) == 0 {
		return nil, errors.New("no subscriptions found in the publish settings file")
	}

	return &pb, nil
}

// Valid implements the kloud.Validator interface.
func (meta *Cred) Valid() error {
	if meta.Location == "" {
		meta.Location = "East US 2"
	}
	if len(meta.PublishSettings) == 0 {
		return errors.New("publish settings are emtpty or missing")
	}

	pb, err := meta.PublishData()
	if err != nil {
		return err
	}

	// If SubscriptionID was not explicitely provided and the publish
	// settings file contains only one subscription, we default to it.
	if meta.SubscriptionID == "" {
		if n := len(pb.Subscriptions); n != 1 {
			return fmt.Errorf("publish settings contain %d subscriptions, please specify which one to use", n)
		}

		return nil
	}

	for _, sub := range pb.Subscriptions {
		if sub.ID == meta.SubscriptionID {
			return nil
		}
	}

	return errors.New("specified subscription ID does not exist")
}

type Bootstrap struct {
	AddressSpace     string `json:"address_space,omitempty" bson:"address_space,omitempty" hcl:"address_space"`                      // by default "10.0.0.0/16"
	Storage          string `json:"storage,omitempty" bson:"storage,omitempty" hcl:"storage"`                                        // by default "Standard_LRS"
	StorageServiceID string `json:"storage_service_name,omitempty" bson:"storage_service_name,omitempty" hcl:"storage_service_name"` // unique Azure-wide

	// Bootstrap metadata.
	HostedServiceID  string `json:"hosted_service_name,omitempty" bson:"hosted_service_name,omitempty" hcl:"hosted_service_name"` // unique Azure-wide
	SecurityGroupID  string `json:"security_group,omitempty" bson:"security_group,omitempty" hcl:"security_group"`
	VirtualNetworkID string `json:"virtual_network,omitempty" bson:"virtual_network,omitempty" hcl:"virtual_network"`
	SubnetName       string `json:"subnet,omitempty" bson:"subnet,omitempty" hcl:"subnet"`
}

var _ stack.Validator = (*Bootstrap)(nil)

func (b *Bootstrap) Valid() error {
	if b.AddressSpace == "" {
		b.AddressSpace = "10.0.0.0/16"
	}
	if b.Storage == "" {
		b.Storage = "Standard_LRS"
	}
	if b.HostedServiceID == "" {
		return errors.New("hosted service ID is empty or missing")
	}
	if b.StorageServiceID == "" {
		return errors.New("storage service ID is empty or missing")
	}
	if b.SecurityGroupID == "" {
		return errors.New("security group ID is empty or missing")
	}
	if b.VirtualNetworkID == "" {
		return errors.New("virtual network ID is empty or missing")
	}
	if b.SubnetName == "" {
		return errors.New("subnet name is empty or missing")
	}
	return nil
}

type Meta struct {
	AlwaysOn        bool   `bson:"alwaysOn"`
	InstanceID      string `json:"instanceId" bson:"instanceId"`
	HostedServiceID string `json:"hostedServiceId" bson:"hostedServiceId"`
	InstanceType    string `json:"instance_type" bson:"instance_type"`
	Location        string `json:"location" bson:"location"`
	StorageSize     int    `json:"storage_size" bson:"storage_size"`
}

func (mt *Meta) Valid() error {
	if mt.InstanceID == "" {
		return errors.New("invalid empty instance ID")
	}

	if mt.HostedServiceID == "" {
		return errors.New("invalid hosted service ID")
	}

	return nil
}
<commit_msg>provider/azure: make provider a local variable<commit_after>package azure

import (
	"encoding/xml"
	"errors"
	"fmt"

	"koding/kites/kloud/stack"
	"koding/kites/kloud/stack/provider"

	"github.com/Azure/azure-sdk-for-go/management"
	vm "github.com/Azure/azure-sdk-for-go/management/virtualmachine"
)

func init() {
	provider.Register(&provider.Provider{
		Name:         "azure",
		ResourceName: "instance",
		Machine:      newMachine,
		Stack:        newStack,
		Schema: &provider.Schema{
			NewCredential: newCredential,
			NewBootstrap:  newBootstrap,
			NewMetadata:   newMetadata,
		},
	})
}

func newMachine(bm *provider.BaseMachine) (provider.Machine, error) {
	m := &Machine{BaseMachine: bm}
	cred := m.Cred()

	c, err := management.ClientFromPublishSettingsDataWithConfig(cred.PublishSettings, cred.SubscriptionID, management.DefaultConfig())
	if err != nil {
		return nil, err
	}

	vmclient := vm.NewClient(c)

	m.AzureClient = c
	m.AzureVMClient = &vmclient

	return m, nil
}

func newStack(bs *provider.BaseStack) (provider.Stack, error) {
	return &Stack{BaseStack: bs}, nil
}

func newCredential() interface{} {
	return &Cred{}
}

func newBootstrap() interface{} {
	return &Bootstrap{}
}

func newMetadata(m *stack.Machine) interface{} {
	if m == nil {
		return &Meta{}
	}

	meta := &Meta{
		InstanceID:      m.Attributes["id"],
		HostedServiceID: m.Attributes["hosted_service_name"],
		InstanceType:    m.Attributes["size"],
	}

	if cred, ok := m.Credential.Credential.(*Cred); ok {
		meta.Location = cred.Location
	}

	return meta
}

type PublishData struct {
	Subscriptions []Subscription `xml:"PublishProfile>Subscription"`
}

type Subscription struct {
	ID string `xml:"Id,attr"`
}

// Cred represents jCredentialDatas.meta for "azure" provider.
type Cred struct {
	// Credentials.
	PublishSettings []byte `json:"publish_settings" bson:"publish_settings" hcl:"publish_settings"` // required
	SubscriptionID  string `json:"subscription_id,omitempty" bson:"subscription_id,omitempty" hcl:"subscription_id"`
	Location        string `json:"location,omitempty" bson:"location,omitempty" hcl:"location"` // by default "East US 2"
}

var _ stack.Validator = (*Cred)(nil)

func (meta *Cred) PublishData() (*PublishData, error) {
	var pb PublishData

	if err := xml.Unmarshal(meta.PublishSettings, &pb); err != nil {
		return nil, err
	}

	if len(pb.Subscriptions) == 0 {
		return nil, errors.New("no subscriptions found in the publish settings file")
	}

	return &pb, nil
}

// Valid implements the kloud.Validator interface.
func (meta *Cred) Valid() error {
	if meta.Location == "" {
		meta.Location = "East US 2"
	}
	if len(meta.PublishSettings) == 0 {
		return errors.New("publish settings are emtpty or missing")
	}

	pb, err := meta.PublishData()
	if err != nil {
		return err
	}

	// If SubscriptionID was not explicitely provided and the publish
	// settings file contains only one subscription, we default to it.
	if meta.SubscriptionID == "" {
		if n := len(pb.Subscriptions); n != 1 {
			return fmt.Errorf("publish settings contain %d subscriptions, please specify which one to use", n)
		}

		return nil
	}

	for _, sub := range pb.Subscriptions {
		if sub.ID == meta.SubscriptionID {
			return nil
		}
	}

	return errors.New("specified subscription ID does not exist")
}

type Bootstrap struct {
	AddressSpace     string `json:"address_space,omitempty" bson:"address_space,omitempty" hcl:"address_space"`                      // by default "10.0.0.0/16"
	Storage          string `json:"storage,omitempty" bson:"storage,omitempty" hcl:"storage"`                                        // by default "Standard_LRS"
	StorageServiceID string `json:"storage_service_name,omitempty" bson:"storage_service_name,omitempty" hcl:"storage_service_name"` // unique Azure-wide

	// Bootstrap metadata.
	HostedServiceID  string `json:"hosted_service_name,omitempty" bson:"hosted_service_name,omitempty" hcl:"hosted_service_name"` // unique Azure-wide
	SecurityGroupID  string `json:"security_group,omitempty" bson:"security_group,omitempty" hcl:"security_group"`
	VirtualNetworkID string `json:"virtual_network,omitempty" bson:"virtual_network,omitempty" hcl:"virtual_network"`
	SubnetName       string `json:"subnet,omitempty" bson:"subnet,omitempty" hcl:"subnet"`
}

var _ stack.Validator = (*Bootstrap)(nil)

func (b *Bootstrap) Valid() error {
	if b.AddressSpace == "" {
		b.AddressSpace = "10.0.0.0/16"
	}
	if b.Storage == "" {
		b.Storage = "Standard_LRS"
	}
	if b.HostedServiceID == "" {
		return errors.New("hosted service ID is empty or missing")
	}
	if b.StorageServiceID == "" {
		return errors.New("storage service ID is empty or missing")
	}
	if b.SecurityGroupID == "" {
		return errors.New("security group ID is empty or missing")
	}
	if b.VirtualNetworkID == "" {
		return errors.New("virtual network ID is empty or missing")
	}
	if b.SubnetName == "" {
		return errors.New("subnet name is empty or missing")
	}
	return nil
}

type Meta struct {
	AlwaysOn        bool   `bson:"alwaysOn"`
	InstanceID      string `json:"instanceId" bson:"instanceId"`
	HostedServiceID string `json:"hostedServiceId" bson:"hostedServiceId"`
	InstanceType    string `json:"instance_type" bson:"instance_type"`
	Location        string `json:"location" bson:"location"`
	StorageSize     int    `json:"storage_size" bson:"storage_size"`
}

func (mt *Meta) Valid() error {
	if mt.InstanceID == "" {
		return errors.New("invalid empty instance ID")
	}

	if mt.HostedServiceID == "" {
		return errors.New("invalid hosted service ID")
	}

	return nil
}
<|endoftext|>


<commit_before>package fakes

import (
	boshsys "bosh/system"
	"strings"
)

type FakeCmdRunner struct {
	CommandResults map[string][]FakeCmdResult

	RunComplexCommands   []boshsys.Command
	RunCommands          [][]string
	RunCommandsWithInput [][]string

	CommandExistsValue bool
}

type FakeCmdResult struct {
	Stdout string
	Stderr string
	Error  error
}

func NewFakeCmdRunner() *FakeCmdRunner {
	return &FakeCmdRunner{}
}

func (runner *FakeCmdRunner) RunComplexCommand(cmd boshsys.Command) (stdout, stderr string, err error) {
	runner.RunComplexCommands = append(runner.RunComplexCommands, cmd)
	runCmd := append([]string{cmd.Name}, cmd.Args...)

	stdout, stderr, err = runner.getOutputsForCmd(runCmd)
	return
}

func (runner *FakeCmdRunner) RunCommand(cmdName string, args ...string) (stdout, stderr string, err error) {
	runCmd := append([]string{cmdName}, args...)
	runner.RunCommands = append(runner.RunCommands, runCmd)

	stdout, stderr, err = runner.getOutputsForCmd(runCmd)
	return
}

func (runner *FakeCmdRunner) RunCommandWithInput(input, cmdName string, args ...string) (stdout, stderr string, err error) {
	runCmd := append([]string{input, cmdName}, args...)
	runner.RunCommandsWithInput = append(runner.RunCommandsWithInput, runCmd)

	stdout, stderr, err = runner.getOutputsForCmd(runCmd)
	return
}

func (runner *FakeCmdRunner) CommandExists(cmdName string) (exists bool) {
	return runner.CommandExistsValue
}

func (runner *FakeCmdRunner) AddCmdResult(fullCmd string, result FakeCmdResult) {
	if runner.CommandResults == nil {
		runner.CommandResults = make(map[string][]FakeCmdResult)
	}
	results := runner.CommandResults[fullCmd]
	runner.CommandResults[fullCmd] = append(results, result)
}

func (runner *FakeCmdRunner) getOutputsForCmd(runCmd []string) (stdout, stderr string, err error) {
	fullCmd := strings.Join(runCmd, " ")

	results, found := runner.CommandResults[fullCmd]
	if found {
		result := results[0]
		newResults := []FakeCmdResult{}
		if len(results) > 1 {
			newResults = results[1:]
		}
		runner.CommandResults[fullCmd] = newResults

		stdout = result.Stdout
		stderr = result.Stderr
		err = result.Error
	}
	return
}
<commit_msg>added option to make command results stick for FakeCmdRunner<commit_after>package fakes

import (
	boshsys "bosh/system"
	"strings"
)

type FakeCmdRunner struct {
	CommandResults map[string][]FakeCmdResult

	RunComplexCommands   []boshsys.Command
	RunCommands          [][]string
	RunCommandsWithInput [][]string

	CommandExistsValue bool
}

type FakeCmdResult struct {
	Stdout string
	Stderr string
	Error  error
	Sticky bool //Set to true if this result should ALWAYS be returned for the given command
}

func NewFakeCmdRunner() *FakeCmdRunner {
	return &FakeCmdRunner{}
}

func (runner *FakeCmdRunner) RunComplexCommand(cmd boshsys.Command) (stdout, stderr string, err error) {
	runner.RunComplexCommands = append(runner.RunComplexCommands, cmd)
	runCmd := append([]string{cmd.Name}, cmd.Args...)

	stdout, stderr, err = runner.getOutputsForCmd(runCmd)
	return
}

func (runner *FakeCmdRunner) RunCommand(cmdName string, args ...string) (stdout, stderr string, err error) {
	runCmd := append([]string{cmdName}, args...)
	runner.RunCommands = append(runner.RunCommands, runCmd)

	stdout, stderr, err = runner.getOutputsForCmd(runCmd)
	return
}

func (runner *FakeCmdRunner) RunCommandWithInput(input, cmdName string, args ...string) (stdout, stderr string, err error) {
	runCmd := append([]string{input, cmdName}, args...)
	runner.RunCommandsWithInput = append(runner.RunCommandsWithInput, runCmd)

	stdout, stderr, err = runner.getOutputsForCmd(runCmd)
	return
}

func (runner *FakeCmdRunner) CommandExists(cmdName string) (exists bool) {
	return runner.CommandExistsValue
}

func (runner *FakeCmdRunner) AddCmdResult(fullCmd string, result FakeCmdResult) {
	if runner.CommandResults == nil {
		runner.CommandResults = make(map[string][]FakeCmdResult)
	}
	results := runner.CommandResults[fullCmd]
	runner.CommandResults[fullCmd] = append(results, result)
}

func (runner *FakeCmdRunner) getOutputsForCmd(runCmd []string) (stdout, stderr string, err error) {
	fullCmd := strings.Join(runCmd, " ")

	results, found := runner.CommandResults[fullCmd]
	if found {
		result := results[0]
		newResults := []FakeCmdResult{}
		if len(results) > 1 {
			newResults = results[1:]
		}

		if !result.Sticky {
			runner.CommandResults[fullCmd] = newResults
		}

		stdout = result.Stdout
		stderr = result.Stderr
		err = result.Error
	}
	return
}
<|endoftext|>


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

// Package intervalset provides an abtraction for dealing with sets of
// 1-dimensional spans, such as sets of time ranges. The Set type provides set
// arithmetic and enumeration methods based on an Interval interface.
//
// DISCLAIMER: This library is not yet stable, so expect breaking changes.
package intervalset

import (
	"fmt"
	"sort"
	"strings"
)

// Interval is the interface for a continuous or discrete span. The interval is
// assumed to be inclusive of the starting point and exclusive of the ending
// point.
//
// All methods in the interface are non-destructive: Calls to the methods should
// not modify the interval.
type Interval interface {
	// Intersect returns the intersection of an interval with another
	// interval. The function may panic if the other interval is incompatible.
	Intersect(Interval) Interval

	// Before returns true if the interval is completely before another interval.
	Before(Interval) bool

	// IsZero returns true for the zero value of an interval.
	IsZero() bool

	// Bisect returns two intervals, one on the lower side of x and one on the
	// upper side of x, corresponding to the subtraction of x from the original
	// interval. The returned intervals are always within the range of the
	// original interval.
	Bisect(x Interval) (Interval, Interval)

	// Adjoin returns the union of two intervals, if the intervals are exactly
	// adjacent, or the zero interval if they are not.
	Adjoin(Interval) Interval

	// Encompass returns an interval that covers the exact extents of two
	// intervals.
	Encompass(Interval) Interval
}

// Set is a set of interval objects used for
type Set struct {
	//non-overlapping intervals
	intervals []Interval
}

// NewSet returns a new set given a sorted slice of intervals. This function
// panics if the intervals are not sorted.
func NewSet(intervals []Interval) *Set {
	for i := 0; i < len(intervals)-1; i++ {
		if !intervals[i].Before(intervals[i+1]) {
			panic(fmt.Errorf("!intervals[%d].Before(intervals[%d]) for %s, %s", i, i+1, intervals[i], intervals[i+1]))
		}
	}
	return &Set{intervals}
}

// Empty returns a new, empty set of intervals.
func Empty() *Set {
	return &Set{}
}

// Copy returns a copy of a set that may be mutated without affecting the original.
func (s *Set) Copy() *Set {
	return &Set{append([]Interval(nil), s.intervals...)}
}

// String returns a human-friendly representation of the set.
func (s *Set) String() string {
	var strs []string
	for _, x := range s.intervals {
		strs = append(strs, fmt.Sprintf("%s", x))
	}
	return fmt.Sprintf("{%s}", strings.Join(strs, ", "))
}

// Extent returns the Interval defined by the minimum and maximum values of the
// set.
func (s *Set) Extent() Interval {
	if len(s.intervals) == 0 {
		return nil
	}
	return s.intervals[0].Encompass(s.intervals[len(s.intervals)-1])
}

// Add adds all the elements of another set to this set.
func (s *Set) Add(b *Set) {
	// Loop through the intervals of x
	for _, x := range b.intervals {
		s.insert(x)
	}
}

// Contains reports whether an interval is entirely contained by the set.
func (s *Set) Contains(ival Interval) bool {
	// Loop through the intervals of x
	next := s.iterator(ival, true)
	for setInterval := next(); setInterval != nil; setInterval = next() {
		left, right := ival.Bisect(setInterval)
		if !left.IsZero() {
			return false
		}
		ival = right
	}
	return ival.IsZero()
}

// adjoinOrAppend adds an interval to the end of intervals unless that value
// directly adjoins the last element of intervals, in which case the last
// element will be replaced by the adjoined interval.
func adjoinOrAppend(intervals []Interval, x Interval) []Interval {
	lastIndex := len(intervals) - 1
	if lastIndex == -1 {
		return append(intervals, x)
	}
	adjoined := intervals[lastIndex].Adjoin(x)
	if adjoined.IsZero() {
		return append(intervals, x)
	}
	intervals[lastIndex] = adjoined
	return intervals
}

func (s *Set) insert(insertion Interval) {
	if s.Contains(insertion) {
		return
	}
	// TODO(reddaly): Something like Java's ArrayList would allow both O(log(n))
	// insertion and O(log(n)) lookup. For now, we have O(log(n)) lookup and O(n)
	// insertion.
	var newIntervals []Interval
	push := func(x Interval) {
		newIntervals = adjoinOrAppend(newIntervals, x)
	}
	inserted := false
	for _, x := range s.intervals {
		if inserted {
			push(x)
			continue
		}
		if insertion.Before(x) {
			push(insertion)
			push(x)
			inserted = true
			continue
		}
		// [===left===)[==x===)[===right===)
		left, right := insertion.Bisect(x)
		if !left.IsZero() {
			push(left)
		}
		push(x)
		// Replace the interval being inserted with the remaining portion of the
		// interval to be inserted.
		if right.IsZero() {
			inserted = true
		} else {
			insertion = right
		}
	}
	if !inserted {
		push(insertion)
	}
	s.intervals = newIntervals
}

// Sub destructively modifies the set by subtracting b.
func (s *Set) Sub(b *Set) {
	var newIntervals []Interval
	push := func(x Interval) {
		newIntervals = adjoinOrAppend(newIntervals, x)
	}
	nextX := s.iterator(s.Extent(), true)
	nextY := b.iterator(s.Extent(), true)

	x := nextX()
	y := nextY()
	for x != nil {
		// If y == nil, all of the remaining intervals in A are to the right of B,
		// so just yield them.
		if y == nil {
			push(x)
			x = nextX()
			continue
		}
		// Split x into parts left and right of y.
		// The diagrams below show the bisection results for various situations.
		// if left.IsZero() && !right.IsZero()
		//             xxx
		// y1y1 y2y2 y3  y4y4
		//             xxx
		// or
		//   xxxxxxxxxxxx
		// y1y1 y2y2 y3  y4y4
		//
		// if !left.IsZero() && !right.IsZero()
		//       x1x1x1x1x1
		//         y1  y2
		//
		// if left.IsZero() && right.IsZero()
		//    x1x1x1x1  x2x2x2
		//  y1y1y1y1y1y1y1
		//
		// if !left.IsZero() && right.IsZero()
		//   x1x1  x2
		//     y1y1y1y1
		left, right := x.Bisect(y)

		// If the left side of x is non-zero, it can definitely be pushed to the
		// resulting interval set since no subsequent y value will intersect it.
		// The sequences look something like
		//         x1x1x1x1x1       OR   x1x1x1 x2
		//             y1 y2                       y1y1y1
		// left  = x1x1                  x1x1x1
		// right =       x1x1                            {zero}
		if !left.IsZero() {
			push(left)
		}

		if !right.IsZero() {
			// If the right side of x is non-zero:
			// 1) Right is the remaining portion of x that needs to be pushed.
			x = right
			// 2) It's not possible for current y to intersect it, so advance y. It's
			//    possible nextY() will intersect it, so don't push yet.
			y = nextY()
		} else {
			// There's nothing left of x to push, so advance x.
			x = nextX()
		}
	}

	// Setting s.intervals is the only side effect in this function.
	s.intervals = newIntervals
}

// Intersect destructively modifies the set by intersecting it with b.
func (s *Set) Intersect(b *Set) {
	var newIntervals []Interval
	push := func(x Interval) {
		newIntervals = adjoinOrAppend(newIntervals, x)
	}
	nextX := s.iterator(b.Extent(), true)
	nextY := b.iterator(s.Extent(), true)

	x := nextX()
	y := nextY()
	// Loop through corresponding intervals of S and B.
	// If y == nil, all of the remaining intervals in S are to the right of B.
	// If x == nil, all of the remaining intervals in B are to the right of S.
	for x != nil && y != nil {
		if x.Before(y) {
			x = nextX()
			continue
		}
		if y.Before(x) {
			y = nextY()
			continue
		}
		xyIntersect := x.Intersect(y)
		if !xyIntersect.IsZero() {
			push(xyIntersect)
			_, right := x.Bisect(y)
			x = right
		}
	}

	// Setting s.intervals is the only side effect in this function.
	s.intervals = newIntervals
}

// searchLow returns the first index in s.intervals that is not before x.
func (s *Set) searchLow(x Interval) int {
	return sort.Search(len(s.intervals), func(i int) bool {
		return !s.intervals[i].Before(x)
	})
}

// searchLow returns the index of the first interval in s.intervals that is
// entirely after x.
func (s *Set) searchHigh(x Interval) int {
	return sort.Search(len(s.intervals), func(i int) bool {
		return x.Before(s.intervals[i])
	})
}

// iterator returns a function that yields elements of the set in order.
func (s *Set) iterator(extents Interval, forward bool) func() Interval {
	low, high := s.searchLow(extents), s.searchHigh(extents)

	i, stride := low, 1
	if !forward {
		i, stride = high-1, -1
	}

	return func() Interval {
		if i < 0 || i >= len(s.intervals) {
			return nil
		}
		x := s.intervals[i]
		i += stride
		return x
	}
}

// IntervalReceiver is a function used for iterating over a set of intervals. It
// takes the start and end times and returns true if the iteration should
// continue.
type IntervalReceiver func(Interval) bool

// IntervalsBetween iterates over the intervals within extents set and calls f
// with each. If f returns false, iteration ceases.
//
// Any interval within the set that overlaps partially with extents is truncated
// before being passed to f.
func (s *Set) IntervalsBetween(extents Interval, f IntervalReceiver) {
	// Begin = first index in s.intervals that is not before extents.
	begin := sort.Search(len(s.intervals), func(i int) bool {
		return !s.intervals[i].Before(extents)
	})

	// TODO(reddaly): Optimize this by performing a binary search for the ending
	// point.
	for _, interval := range s.intervals[begin:] {
		// If the interval is after the extents, there will be no more overlap, so
		// break out of the loop.
		if extents.Before(interval) {
			break
		}
		portionOfInterval := extents.Intersect(interval)
		if portionOfInterval.IsZero() {
			continue
		}

		if !f(portionOfInterval) {
			return
		}
	}
}

// Intervals iterates over all the intervals within the set and calls f with
// each one. If f returns false, iteration ceases.
func (s *Set) Intervals(f IntervalReceiver) {
	for _, interval := range s.intervals {
		if !f(interval) {
			return
		}
	}
}

// AllIntervals returns an ordered slice of all the intervals in the set.
func (s *Set) AllIntervals() []Interval {
	return append(make([]Interval, 0, len(s.intervals)), s.intervals...)
}
<commit_msg>Deal with edge case in set intersection.<commit_after>// Copyright 2017 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// Package intervalset provides an abtraction for dealing with sets of
// 1-dimensional spans, such as sets of time ranges. The Set type provides set
// arithmetic and enumeration methods based on an Interval interface.
//
// DISCLAIMER: This library is not yet stable, so expect breaking changes.
package intervalset

import (
	"fmt"
	"sort"
	"strings"
)

// Interval is the interface for a continuous or discrete span. The interval is
// assumed to be inclusive of the starting point and exclusive of the ending
// point.
//
// All methods in the interface are non-destructive: Calls to the methods should
// not modify the interval.
type Interval interface {
	// Intersect returns the intersection of an interval with another
	// interval. The function may panic if the other interval is incompatible.
	Intersect(Interval) Interval

	// Before returns true if the interval is completely before another interval.
	Before(Interval) bool

	// IsZero returns true for the zero value of an interval.
	IsZero() bool

	// Bisect returns two intervals, one on the lower side of x and one on the
	// upper side of x, corresponding to the subtraction of x from the original
	// interval. The returned intervals are always within the range of the
	// original interval.
	Bisect(x Interval) (Interval, Interval)

	// Adjoin returns the union of two intervals, if the intervals are exactly
	// adjacent, or the zero interval if they are not.
	Adjoin(Interval) Interval

	// Encompass returns an interval that covers the exact extents of two
	// intervals.
	Encompass(Interval) Interval
}

// Set is a set of interval objects used for
type Set struct {
	//non-overlapping intervals
	intervals []Interval
}

// NewSet returns a new set given a sorted slice of intervals. This function
// panics if the intervals are not sorted.
func NewSet(intervals []Interval) *Set {
	for i := 0; i < len(intervals)-1; i++ {
		if !intervals[i].Before(intervals[i+1]) {
			panic(fmt.Errorf("!intervals[%d].Before(intervals[%d]) for %s, %s", i, i+1, intervals[i], intervals[i+1]))
		}
	}
	return &Set{intervals}
}

// Empty returns a new, empty set of intervals.
func Empty() *Set {
	return &Set{}
}

// Copy returns a copy of a set that may be mutated without affecting the original.
func (s *Set) Copy() *Set {
	return &Set{append([]Interval(nil), s.intervals...)}
}

// String returns a human-friendly representation of the set.
func (s *Set) String() string {
	var strs []string
	for _, x := range s.intervals {
		strs = append(strs, fmt.Sprintf("%s", x))
	}
	return fmt.Sprintf("{%s}", strings.Join(strs, ", "))
}

// Extent returns the Interval defined by the minimum and maximum values of the
// set.
func (s *Set) Extent() Interval {
	if len(s.intervals) == 0 {
		return nil
	}
	return s.intervals[0].Encompass(s.intervals[len(s.intervals)-1])
}

// Add adds all the elements of another set to this set.
func (s *Set) Add(b *Set) {
	// Loop through the intervals of x
	for _, x := range b.intervals {
		s.insert(x)
	}
}

// Contains reports whether an interval is entirely contained by the set.
func (s *Set) Contains(ival Interval) bool {
	// Loop through the intervals of x
	next := s.iterator(ival, true)
	for setInterval := next(); setInterval != nil; setInterval = next() {
		left, right := ival.Bisect(setInterval)
		if !left.IsZero() {
			return false
		}
		ival = right
	}
	return ival.IsZero()
}

// adjoinOrAppend adds an interval to the end of intervals unless that value
// directly adjoins the last element of intervals, in which case the last
// element will be replaced by the adjoined interval.
func adjoinOrAppend(intervals []Interval, x Interval) []Interval {
	lastIndex := len(intervals) - 1
	if lastIndex == -1 {
		return append(intervals, x)
	}
	adjoined := intervals[lastIndex].Adjoin(x)
	if adjoined.IsZero() {
		return append(intervals, x)
	}
	intervals[lastIndex] = adjoined
	return intervals
}

func (s *Set) insert(insertion Interval) {
	if s.Contains(insertion) {
		return
	}
	// TODO(reddaly): Something like Java's ArrayList would allow both O(log(n))
	// insertion and O(log(n)) lookup. For now, we have O(log(n)) lookup and O(n)
	// insertion.
	var newIntervals []Interval
	push := func(x Interval) {
		newIntervals = adjoinOrAppend(newIntervals, x)
	}
	inserted := false
	for _, x := range s.intervals {
		if inserted {
			push(x)
			continue
		}
		if insertion.Before(x) {
			push(insertion)
			push(x)
			inserted = true
			continue
		}
		// [===left===)[==x===)[===right===)
		left, right := insertion.Bisect(x)
		if !left.IsZero() {
			push(left)
		}
		push(x)
		// Replace the interval being inserted with the remaining portion of the
		// interval to be inserted.
		if right.IsZero() {
			inserted = true
		} else {
			insertion = right
		}
	}
	if !inserted {
		push(insertion)
	}
	s.intervals = newIntervals
}

// Sub destructively modifies the set by subtracting b.
func (s *Set) Sub(b *Set) {
	var newIntervals []Interval
	push := func(x Interval) {
		newIntervals = adjoinOrAppend(newIntervals, x)
	}
	nextX := s.iterator(s.Extent(), true)
	nextY := b.iterator(s.Extent(), true)

	x := nextX()
	y := nextY()
	for x != nil {
		// If y == nil, all of the remaining intervals in A are to the right of B,
		// so just yield them.
		if y == nil {
			push(x)
			x = nextX()
			continue
		}
		// Split x into parts left and right of y.
		// The diagrams below show the bisection results for various situations.
		// if left.IsZero() && !right.IsZero()
		//             xxx
		// y1y1 y2y2 y3  y4y4
		//             xxx
		// or
		//   xxxxxxxxxxxx
		// y1y1 y2y2 y3  y4y4
		//
		// if !left.IsZero() && !right.IsZero()
		//       x1x1x1x1x1
		//         y1  y2
		//
		// if left.IsZero() && right.IsZero()
		//    x1x1x1x1  x2x2x2
		//  y1y1y1y1y1y1y1
		//
		// if !left.IsZero() && right.IsZero()
		//   x1x1  x2
		//     y1y1y1y1
		left, right := x.Bisect(y)

		// If the left side of x is non-zero, it can definitely be pushed to the
		// resulting interval set since no subsequent y value will intersect it.
		// The sequences look something like
		//         x1x1x1x1x1       OR   x1x1x1 x2
		//             y1 y2                       y1y1y1
		// left  = x1x1                  x1x1x1
		// right =       x1x1                            {zero}
		if !left.IsZero() {
			push(left)
		}

		if !right.IsZero() {
			// If the right side of x is non-zero:
			// 1) Right is the remaining portion of x that needs to be pushed.
			x = right
			// 2) It's not possible for current y to intersect it, so advance y. It's
			//    possible nextY() will intersect it, so don't push yet.
			y = nextY()
		} else {
			// There's nothing left of x to push, so advance x.
			x = nextX()
		}
	}

	// Setting s.intervals is the only side effect in this function.
	s.intervals = newIntervals
}

// Intersect destructively modifies the set by intersecting it with b.
func (s *Set) Intersect(b *Set) {
	var newIntervals []Interval
	push := func(x Interval) {
		newIntervals = adjoinOrAppend(newIntervals, x)
	}
	nextX := s.iterator(b.Extent(), true)
	nextY := b.iterator(s.Extent(), true)

	x := nextX()
	y := nextY()
	// Loop through corresponding intervals of S and B.
	// If y == nil, all of the remaining intervals in S are to the right of B.
	// If x == nil, all of the remaining intervals in B are to the right of S.
	for x != nil && y != nil {
		if x.Before(y) {
			x = nextX()
			continue
		}
		if y.Before(x) {
			y = nextY()
			continue
		}
		xyIntersect := x.Intersect(y)
		if !xyIntersect.IsZero() {
			push(xyIntersect)
			_, right := x.Bisect(y)
			if !right.IsZero() {
				x = right
			} else {
				x = nextX()
			}
		}
	}

	// Setting s.intervals is the only side effect in this function.
	s.intervals = newIntervals
}

// searchLow returns the first index in s.intervals that is not before x.
func (s *Set) searchLow(x Interval) int {
	return sort.Search(len(s.intervals), func(i int) bool {
		return !s.intervals[i].Before(x)
	})
}

// searchLow returns the index of the first interval in s.intervals that is
// entirely after x.
func (s *Set) searchHigh(x Interval) int {
	return sort.Search(len(s.intervals), func(i int) bool {
		return x.Before(s.intervals[i])
	})
}

// iterator returns a function that yields elements of the set in order.
func (s *Set) iterator(extents Interval, forward bool) func() Interval {
	low, high := s.searchLow(extents), s.searchHigh(extents)

	i, stride := low, 1
	if !forward {
		i, stride = high-1, -1
	}

	return func() Interval {
		if i < 0 || i >= len(s.intervals) {
			return nil
		}
		x := s.intervals[i]
		i += stride
		return x
	}
}

// IntervalReceiver is a function used for iterating over a set of intervals. It
// takes the start and end times and returns true if the iteration should
// continue.
type IntervalReceiver func(Interval) bool

// IntervalsBetween iterates over the intervals within extents set and calls f
// with each. If f returns false, iteration ceases.
//
// Any interval within the set that overlaps partially with extents is truncated
// before being passed to f.
func (s *Set) IntervalsBetween(extents Interval, f IntervalReceiver) {
	// Begin = first index in s.intervals that is not before extents.
	begin := sort.Search(len(s.intervals), func(i int) bool {
		return !s.intervals[i].Before(extents)
	})

	// TODO(reddaly): Optimize this by performing a binary search for the ending
	// point.
	for _, interval := range s.intervals[begin:] {
		// If the interval is after the extents, there will be no more overlap, so
		// break out of the loop.
		if extents.Before(interval) {
			break
		}
		portionOfInterval := extents.Intersect(interval)
		if portionOfInterval.IsZero() {
			continue
		}

		if !f(portionOfInterval) {
			return
		}
	}
}

// Intervals iterates over all the intervals within the set and calls f with
// each one. If f returns false, iteration ceases.
func (s *Set) Intervals(f IntervalReceiver) {
	for _, interval := range s.intervals {
		if !f(interval) {
			return
		}
	}
}

// AllIntervals returns an ordered slice of all the intervals in the set.
func (s *Set) AllIntervals() []Interval {
	return append(make([]Interval, 0, len(s.intervals)), s.intervals...)
}
<|endoftext|>


<commit_before>// Copyright (c) 2016 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

package zap

import (
	"errors"
	"strings"
	"sync"
	"testing"
	"time"

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

type fakeUser struct{ name string }

func (f fakeUser) MarshalLog(kv KeyValue) error {
	if f.name == "fail" {
		return errors.New("fail")
	}
	kv.AddString("name", f.name)
	return nil
}

func assertFieldJSON(t testing.TB, expected string, field Field) {
	enc := newJSONEncoder()
	defer enc.Free()

	field.addTo(enc)
	assert.Equal(t, expected, string(enc.bytes),
		"Unexpected JSON output after applying field %+v.", field)
}

func assertCanBeReused(t testing.TB, field Field) {
	var wg sync.WaitGroup

	for i := 0; i < 100; i++ {
		enc := newJSONEncoder()
		defer enc.Free()

		// Ensure using the field in multiple encoders in separate goroutines
		// does not cause any races or panics.
		wg.Add(1)
		go func() {
			defer wg.Done()
			assert.NotPanics(t, func() {
				field.addTo(enc)
			}, "Reusing a field should not cause issues")
		}()
	}

	wg.Wait()
}

func TestBoolField(t *testing.T) {
	assertFieldJSON(t, `"foo":true`, Bool("foo", true))
	assertCanBeReused(t, Bool("foo", true))
}

func TestFloat64Field(t *testing.T) {
	assertFieldJSON(t, `"foo":1.314`, Float64("foo", 1.314))
	assertCanBeReused(t, Float64("foo", 1.314))
}

func TestIntField(t *testing.T) {
	assertFieldJSON(t, `"foo":1`, Int("foo", 1))
	assertCanBeReused(t, Int("foo", 1))
}

func TestInt64Field(t *testing.T) {
	assertFieldJSON(t, `"foo":1`, Int64("foo", int64(1)))
	assertCanBeReused(t, Int64("foo", int64(1)))
}

func TestStringField(t *testing.T) {
	assertFieldJSON(t, `"foo":"bar"`, String("foo", "bar"))
	assertCanBeReused(t, String("foo", "bar"))
}

func TestTimeField(t *testing.T) {
	assertFieldJSON(t, `"foo":0`, Time("foo", time.Unix(0, 0)))
	assertCanBeReused(t, Time("foo", time.Unix(0, 0)))
}

func TestErrField(t *testing.T) {
	assertFieldJSON(t, `"error":"fail"`, Err(errors.New("fail")))
	assertCanBeReused(t, Err(errors.New("fail")))
}

func TestDurationField(t *testing.T) {
	assertFieldJSON(t, `"foo":1`, Duration("foo", time.Nanosecond))
	assertCanBeReused(t, Duration("foo", time.Nanosecond))
}

func TestObjectField(t *testing.T) {
	// Marshaling the user failed, so we expect an empty object.
	assertFieldJSON(t, `"foo":{}`, Object("foo", fakeUser{"fail"}))

	assertFieldJSON(t, `"foo":{"name":"phil"}`, Object("foo", fakeUser{"phil"}))
	assertCanBeReused(t, Object("foo", fakeUser{"phil"}))
}

func TestNestField(t *testing.T) {
	assertFieldJSON(t, `"foo":{"name":"phil","age":42}`,
		Nest("foo", String("name", "phil"), Int("age", 42)),
	)
	// Marshaling the user failed, so we expect an empty object.
	assertFieldJSON(t, `"foo":{"user":{}}`,
		Nest("foo", Object("user", fakeUser{"fail"})),
	)

	nest := Nest("foo", String("name", "phil"), Int("age", 42))
	assertCanBeReused(t, nest)
}

func TestStackField(t *testing.T) {
	enc := newJSONEncoder()
	defer enc.Free()

	Stack().addTo(enc)
	output := string(enc.bytes)

	require.True(t, strings.HasPrefix(output, `"stacktrace":`), "Stacktrace added under an unexpected key.")
	assert.Contains(t, output[13:], "zap.TestStackField", "Expected stacktrace to contain caller.")
}
<commit_msg>Test unknown field types (#24)<commit_after>// Copyright (c) 2016 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

package zap

import (
	"errors"
	"strings"
	"sync"
	"testing"
	"time"

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

type fakeUser struct{ name string }

func (f fakeUser) MarshalLog(kv KeyValue) error {
	if f.name == "fail" {
		return errors.New("fail")
	}
	kv.AddString("name", f.name)
	return nil
}

func assertFieldJSON(t testing.TB, expected string, field Field) {
	enc := newJSONEncoder()
	defer enc.Free()

	field.addTo(enc)
	assert.Equal(t, expected, string(enc.bytes),
		"Unexpected JSON output after applying field %+v.", field)
}

func assertCanBeReused(t testing.TB, field Field) {
	var wg sync.WaitGroup

	for i := 0; i < 100; i++ {
		enc := newJSONEncoder()
		defer enc.Free()

		// Ensure using the field in multiple encoders in separate goroutines
		// does not cause any races or panics.
		wg.Add(1)
		go func() {
			defer wg.Done()
			assert.NotPanics(t, func() {
				field.addTo(enc)
			}, "Reusing a field should not cause issues")
		}()
	}

	wg.Wait()
}

func TestBoolField(t *testing.T) {
	assertFieldJSON(t, `"foo":true`, Bool("foo", true))
	assertCanBeReused(t, Bool("foo", true))
}

func TestFloat64Field(t *testing.T) {
	assertFieldJSON(t, `"foo":1.314`, Float64("foo", 1.314))
	assertCanBeReused(t, Float64("foo", 1.314))
}

func TestIntField(t *testing.T) {
	assertFieldJSON(t, `"foo":1`, Int("foo", 1))
	assertCanBeReused(t, Int("foo", 1))
}

func TestInt64Field(t *testing.T) {
	assertFieldJSON(t, `"foo":1`, Int64("foo", int64(1)))
	assertCanBeReused(t, Int64("foo", int64(1)))
}

func TestStringField(t *testing.T) {
	assertFieldJSON(t, `"foo":"bar"`, String("foo", "bar"))
	assertCanBeReused(t, String("foo", "bar"))
}

func TestTimeField(t *testing.T) {
	assertFieldJSON(t, `"foo":0`, Time("foo", time.Unix(0, 0)))
	assertCanBeReused(t, Time("foo", time.Unix(0, 0)))
}

func TestErrField(t *testing.T) {
	assertFieldJSON(t, `"error":"fail"`, Err(errors.New("fail")))
	assertCanBeReused(t, Err(errors.New("fail")))
}

func TestDurationField(t *testing.T) {
	assertFieldJSON(t, `"foo":1`, Duration("foo", time.Nanosecond))
	assertCanBeReused(t, Duration("foo", time.Nanosecond))
}

func TestObjectField(t *testing.T) {
	// Marshaling the user failed, so we expect an empty object.
	assertFieldJSON(t, `"foo":{}`, Object("foo", fakeUser{"fail"}))

	assertFieldJSON(t, `"foo":{"name":"phil"}`, Object("foo", fakeUser{"phil"}))
	assertCanBeReused(t, Object("foo", fakeUser{"phil"}))
}

func TestNestField(t *testing.T) {
	assertFieldJSON(t, `"foo":{"name":"phil","age":42}`,
		Nest("foo", String("name", "phil"), Int("age", 42)),
	)
	// Marshaling the user failed, so we expect an empty object.
	assertFieldJSON(t, `"foo":{"user":{}}`,
		Nest("foo", Object("user", fakeUser{"fail"})),
	)

	nest := Nest("foo", String("name", "phil"), Int("age", 42))
	assertCanBeReused(t, nest)
}

func TestStackField(t *testing.T) {
	enc := newJSONEncoder()
	defer enc.Free()

	Stack().addTo(enc)
	output := string(enc.bytes)

	require.True(t, strings.HasPrefix(output, `"stacktrace":`), "Stacktrace added under an unexpected key.")
	assert.Contains(t, output[13:], "zap.TestStackField", "Expected stacktrace to contain caller.")
}

func TestUnknownField(t *testing.T) {
	enc := newJSONEncoder()
	defer enc.Free()

	for _, ft := range []fieldType{unknownType, -42} {
		field := Field{fieldType: ft}
		assert.Panics(t, func() { field.addTo(enc) }, "Expected panic when using a field of unknown type.")
	}
}
<|endoftext|>


<commit_before>package fields

import (
	"encoding/json"
	"github.com/cjtoolkit/form"
	"strconv"
	"strings"
)

/*
Implement:
	FormFieldInterface in "github.com/cjtoolkit/form"
*/
type Int struct {
	Name     string  // Mandatory
	Label    string  // Mandatory
	Norm     *string // Mandatory
	Model    *int64  // Mandatory
	Err      *error  // Mandatory
	Required bool
	Min      int64
	MinZero  bool
	Max      int64
	MaxZero  bool
	Step     int64
	InList   []int64
	Extra    func()
}

type intJson struct {
	Type     string  `json:"type"`
	Name     string  `json:"name"`
	Required bool    `json:"required"`
	Success  bool    `json:"success"`
	Error    string  `json:"error,omitempty"`
	Min      int64   `json:"min,omitempty"`
	MinZero  bool    `json:"minZero,omitempty"`
	Max      int64   `json:"max,omitempty"`
	MaxZero  bool    `json:"maxZero,omitempty"`
	Step     int64   `json:"step,omitempty"`
	List     []int64 `json:"list,omitempty"`
}

const (
	INT_DECIMAL = 10
	INT_BIT     = 64
)

func (i Int) MarshalJSON() ([]byte, error) {
	return json.Marshal(intJson{
		Type:     "int",
		Name:     i.Name,
		Required: i.Required,
		Success:  nil == *i.Err,
		Min:      i.Min,
		MinZero:  i.MinZero,
		Max:      i.Max,
		MaxZero:  i.MaxZero,
		Step:     i.Step,
		List:     i.InList,
	})
}

func (i Int) PreCheck() {
	switch {
	case "" == strings.TrimSpace(i.Name):
		panic(form.ErrorPreCheck("Int Field: Name cannot be empty string"))
	case "" == strings.TrimSpace(i.Label):
		panic(form.ErrorPreCheck("Int Field: " + i.Name + ": Label cannot be empty string"))
	case nil == i.Norm:
		panic(form.ErrorPreCheck("Int Field: " + i.Name + ": Norm cannot be nil value"))
	case nil == i.Model:
		panic(form.ErrorPreCheck("Int Field: " + i.Name + ": Model cannot be nil value"))
	case nil == i.Err:
		panic(form.ErrorPreCheck("Int Field: " + i.Name + ": Err cannot be nil value"))
	}
}

func (i Int) GetErrorPtr() *error {
	return i.Err
}

func (i Int) PopulateNorm(values form.ValuesInterface) {
	*i.Norm = values.GetOne(i.Name)
}

func (i Int) Transform() {
	*i.Norm = strconv.FormatInt(*i.Model, INT_DECIMAL)
}

func (i Int) ReverseTransform() {
	num, err := strconv.ParseInt(strings.TrimSpace(*i.Norm), INT_BIT, INT_DECIMAL)
	ExecFuncIfErrIsNotNil(err, func() {
		panic(&form.ErrorReverseTransform{
			Key: form.LANG_NOT_INT,
			Value: map[string]interface{}{
				"Label": i.Label,
			},
		})
	})
	*i.Model = num
}

func (i Int) ValidateModel() {
	i.validateRequired()
	i.validateMin()
	i.validateMax()
	i.validateStep()
	i.validateInList()
	execFnIfNotNil(i.Extra)
}

func (i Int) validateRequired() {
	switch {
	case !i.Required:
		return
	case 0 == *i.Model:
		panic(&form.ErrorValidateModel{
			Key: form.LANG_FIELD_REQUIRED,
			Value: map[string]interface{}{
				"Label": i.Label,
			},
		})
	}
}

func (i Int) validateMin() {
	switch {
	case 0 == i.Min && !i.MinZero:
		return
	case i.Min > *i.Model:
		panic(&form.ErrorValidateModel{
			Key: form.LANG_NUMBER_MIN,
			Value: map[string]interface{}{
				"Label": i.Label,
				"Min":   i.Min,
			},
		})
	}
}

func (i Int) validateMax() {
	switch {
	case 0 == i.Max && !i.MaxZero:
		return
	case i.Max < *i.Model:
		panic(&form.ErrorValidateModel{
			Key: form.LANG_NUMBER_MAX,
			Value: map[string]interface{}{
				"Label": i.Label,
				"Max":   i.Max,
			},
		})
	}
}

func (i Int) validateStep() {
	switch {
	case 0 == i.Step:
		return
	case 0 != *i.Model%i.Step:
		panic(&form.ErrorValidateModel{
			Key: form.LANG_NUMBER_STEP,
			Value: map[string]interface{}{
				"Label": i.Label,
				"Step":  i.Step,
			},
		})
	}
}

func (i Int) validateInList() {
	if nil == i.InList {
		return
	}

	model := *i.Model

	for _, value := range i.InList {
		if model == value {
			return
		}
	}

	panic(&form.ErrorValidateModel{
		Key: form.LANG_IN_LIST,
		Value: map[string]interface{}{
			"Label": i.Label,
			"List":  i.InList,
		},
	})
}
<commit_msg>Let not forget about the error message<commit_after>package fields

import (
	"encoding/json"
	"github.com/cjtoolkit/form"
	"strconv"
	"strings"
)

/*
Implement:
	FormFieldInterface in "github.com/cjtoolkit/form"
*/
type Int struct {
	Name     string  // Mandatory
	Label    string  // Mandatory
	Norm     *string // Mandatory
	Model    *int64  // Mandatory
	Err      *error  // Mandatory
	Required bool
	Min      int64
	MinZero  bool
	Max      int64
	MaxZero  bool
	Step     int64
	InList   []int64
	Extra    func()
}

type intJson struct {
	Type     string  `json:"type"`
	Name     string  `json:"name"`
	Required bool    `json:"required"`
	Success  bool    `json:"success"`
	Error    string  `json:"error,omitempty"`
	Min      int64   `json:"min,omitempty"`
	MinZero  bool    `json:"minZero,omitempty"`
	Max      int64   `json:"max,omitempty"`
	MaxZero  bool    `json:"maxZero,omitempty"`
	Step     int64   `json:"step,omitempty"`
	List     []int64 `json:"list,omitempty"`
}

const (
	INT_DECIMAL = 10
	INT_BIT     = 64
)

func (i Int) MarshalJSON() ([]byte, error) {
	return json.Marshal(intJson{
		Type:     "int",
		Name:     i.Name,
		Required: i.Required,
		Success:  nil == *i.Err,
		Error:    getMessageFromError(*i.Err),
		Min:      i.Min,
		MinZero:  i.MinZero,
		Max:      i.Max,
		MaxZero:  i.MaxZero,
		Step:     i.Step,
		List:     i.InList,
	})
}

func (i Int) PreCheck() {
	switch {
	case "" == strings.TrimSpace(i.Name):
		panic(form.ErrorPreCheck("Int Field: Name cannot be empty string"))
	case "" == strings.TrimSpace(i.Label):
		panic(form.ErrorPreCheck("Int Field: " + i.Name + ": Label cannot be empty string"))
	case nil == i.Norm:
		panic(form.ErrorPreCheck("Int Field: " + i.Name + ": Norm cannot be nil value"))
	case nil == i.Model:
		panic(form.ErrorPreCheck("Int Field: " + i.Name + ": Model cannot be nil value"))
	case nil == i.Err:
		panic(form.ErrorPreCheck("Int Field: " + i.Name + ": Err cannot be nil value"))
	}
}

func (i Int) GetErrorPtr() *error {
	return i.Err
}

func (i Int) PopulateNorm(values form.ValuesInterface) {
	*i.Norm = values.GetOne(i.Name)
}

func (i Int) Transform() {
	*i.Norm = strconv.FormatInt(*i.Model, INT_DECIMAL)
}

func (i Int) ReverseTransform() {
	num, err := strconv.ParseInt(strings.TrimSpace(*i.Norm), INT_BIT, INT_DECIMAL)
	ExecFuncIfErrIsNotNil(err, func() {
		panic(&form.ErrorReverseTransform{
			Key: form.LANG_NOT_INT,
			Value: map[string]interface{}{
				"Label": i.Label,
			},
		})
	})
	*i.Model = num
}

func (i Int) ValidateModel() {
	i.validateRequired()
	i.validateMin()
	i.validateMax()
	i.validateStep()
	i.validateInList()
	execFnIfNotNil(i.Extra)
}

func (i Int) validateRequired() {
	switch {
	case !i.Required:
		return
	case 0 == *i.Model:
		panic(&form.ErrorValidateModel{
			Key: form.LANG_FIELD_REQUIRED,
			Value: map[string]interface{}{
				"Label": i.Label,
			},
		})
	}
}

func (i Int) validateMin() {
	switch {
	case 0 == i.Min && !i.MinZero:
		return
	case i.Min > *i.Model:
		panic(&form.ErrorValidateModel{
			Key: form.LANG_NUMBER_MIN,
			Value: map[string]interface{}{
				"Label": i.Label,
				"Min":   i.Min,
			},
		})
	}
}

func (i Int) validateMax() {
	switch {
	case 0 == i.Max && !i.MaxZero:
		return
	case i.Max < *i.Model:
		panic(&form.ErrorValidateModel{
			Key: form.LANG_NUMBER_MAX,
			Value: map[string]interface{}{
				"Label": i.Label,
				"Max":   i.Max,
			},
		})
	}
}

func (i Int) validateStep() {
	switch {
	case 0 == i.Step:
		return
	case 0 != *i.Model%i.Step:
		panic(&form.ErrorValidateModel{
			Key: form.LANG_NUMBER_STEP,
			Value: map[string]interface{}{
				"Label": i.Label,
				"Step":  i.Step,
			},
		})
	}
}

func (i Int) validateInList() {
	if nil == i.InList {
		return
	}

	model := *i.Model

	for _, value := range i.InList {
		if model == value {
			return
		}
	}

	panic(&form.ErrorValidateModel{
		Key: form.LANG_IN_LIST,
		Value: map[string]interface{}{
			"Label": i.Label,
			"List":  i.InList,
		},
	})
}
<|endoftext|>


<commit_before>//
//
// File generated from our OpenAPI spec
//
//

// Package reporttype provides the /reporting/report_types APIs
package reporttype

import (
	"net/http"

	stripe "github.com/stripe/stripe-go/v72"
	"github.com/stripe/stripe-go/v72/form"
)

// Client is used to invoke /reporting/report_types APIs.
type Client struct {
	B   stripe.Backend
	Key string
}

// Get returns the details of a report type.
func Get(id string, params *stripe.ReportTypeParams) (*stripe.ReportType, error) {
	return getC().Get(id, params)
}

// Get returns the details of a report type.
func (c Client) Get(id string, params *stripe.ReportTypeParams) (*stripe.ReportType, error) {
	path := stripe.FormatURLPath("/v1/reporting/report_types/%s", id)
	reporttype := &stripe.ReportType{}
	err := c.B.Call(http.MethodGet, path, c.Key, params, reporttype)
	return reporttype, err
}

// List returns a list of report types.
func List(params *stripe.ReportTypeListParams) *Iter {
	return getC().List(params)
}

// List returns a list of report types.
func (c Client) List(listParams *stripe.ReportTypeListParams) *Iter {
	return &Iter{
		Iter: stripe.GetIter(listParams, func(p *stripe.Params, b *form.Values) ([]interface{}, stripe.ListContainer, error) {
			list := &stripe.ReportTypeList{}
			err := c.B.CallRaw(http.MethodGet, "/v1/reporting/report_types", c.Key, b, p, list)

			ret := make([]interface{}, len(list.Data))
			for i, v := range list.Data {
				ret[i] = v
			}

			return ret, list, err
		}),
	}
}

// Iter is an iterator for reporting report types.
type Iter struct {
	*stripe.Iter
}

// ReportType returns the reporting report type which the iterator is currently pointing to.
func (i *Iter) ReportType() *stripe.ReportType {
	return i.Current().(*stripe.ReportType)
}

// ReportTypeList returns the current list object which the iterator is
// currently using. List objects will change as new API calls are made to
// continue pagination.
func (i *Iter) ReportTypeList() *stripe.ReportTypeList {
	return i.List().(*stripe.ReportTypeList)
}

func getC() Client {
	return Client{stripe.GetBackend(stripe.APIBackend), stripe.Key}
}
<commit_msg>Fix comments<commit_after>//
//
// File generated from our OpenAPI spec
//
//

// Package reporttype provides the /reporting/report_types APIs
package reporttype

import (
	"net/http"

	stripe "github.com/stripe/stripe-go/v72"
	"github.com/stripe/stripe-go/v72/form"
)

// Client is used to invoke /reporting/report_types APIs.
type Client struct {
	B   stripe.Backend
	Key string
}

// Get returns the details of a report type.
func Get(id string, params *stripe.ReportTypeParams) (*stripe.ReportType, error) {
	return getC().Get(id, params)
}

// Get returns the details of a report type.
func (c Client) Get(id string, params *stripe.ReportTypeParams) (*stripe.ReportType, error) {
	path := stripe.FormatURLPath("/v1/reporting/report_types/%s", id)
	reporttype := &stripe.ReportType{}
	err := c.B.Call(http.MethodGet, path, c.Key, params, reporttype)
	return reporttype, err
}

// List returns a list of report types.
func List(params *stripe.ReportTypeListParams) *Iter {
	return getC().List(params)
}

// List returns a list of report types.
func (c Client) List(listParams *stripe.ReportTypeListParams) *Iter {
	return &Iter{
		Iter: stripe.GetIter(listParams, func(p *stripe.Params, b *form.Values) ([]interface{}, stripe.ListContainer, error) {
			list := &stripe.ReportTypeList{}
			err := c.B.CallRaw(http.MethodGet, "/v1/reporting/report_types", c.Key, b, p, list)

			ret := make([]interface{}, len(list.Data))
			for i, v := range list.Data {
				ret[i] = v
			}

			return ret, list, err
		}),
	}
}

// Iter is an iterator for report types.
type Iter struct {
	*stripe.Iter
}

// ReportType returns the report type which the iterator is currently pointing to.
func (i *Iter) ReportType() *stripe.ReportType {
	return i.Current().(*stripe.ReportType)
}

// ReportTypeList returns the current list object which the iterator is
// currently using. List objects will change as new API calls are made to
// continue pagination.
func (i *Iter) ReportTypeList() *stripe.ReportTypeList {
	return i.List().(*stripe.ReportTypeList)
}

func getC() Client {
	return Client{stripe.GetBackend(stripe.APIBackend), stripe.Key}
}
<|endoftext|>


<commit_before>package yml

import (
	"bytes"
	"github.com/spf13/viper"
	"github.com/zouyx/agollo/v3/constant"
	"github.com/zouyx/agollo/v3/extension"
	"github.com/zouyx/agollo/v3/utils"
)

var vp = viper.New()

func init() {
	extension.AddFormatParser(constant.YML, &Parser{})
	vp.SetConfigType("yml")
}

// Parser properties转换器
type Parser struct {
}

// Parse 内存内容=>yml文件转换器
func (d *Parser) Parse(configContent string) (map[string]string, error) {
	if utils.Empty == configContent {
		return nil, nil
	}

	buffer := bytes.NewBufferString(configContent)
	// 使用viper解析
	err := vp.ReadConfig(buffer)
	if err != nil {
		return nil, err
	}

	return convertToMap(vp), nil
}

func convertToMap(vp *viper.Viper) map[string]string {
	if vp == nil {
		return nil
	}

	m := make(map[string]string)
	for _, key := range vp.AllKeys() {
		m[key] = vp.GetString(key)
	}
	return m
}
<commit_msg>添加yaml格式支持<commit_after>package yml

import (
	"bytes"
	"github.com/spf13/viper"
	"github.com/zouyx/agollo/v3/constant"
	"github.com/zouyx/agollo/v3/extension"
	"github.com/zouyx/agollo/v3/utils"
)

var vp = viper.New()

func init() {
	parser := &Parser{}
	extension.AddFormatParser(constant.YML, parser)
	extension.AddFormatParser(constant.YAML, parser)
	vp.SetConfigType("yml")
}

// Parser properties转换器
type Parser struct {
}

// Parse 内存内容=>yml文件转换器
func (d *Parser) Parse(configContent string) (map[string]string, error) {
	if utils.Empty == configContent {
		return nil, nil
	}

	buffer := bytes.NewBufferString(configContent)
	// 使用viper解析
	err := vp.ReadConfig(buffer)
	if err != nil {
		return nil, err
	}

	return convertToMap(vp), nil
}

func convertToMap(vp *viper.Viper) map[string]string {
	if vp == nil {
		return nil
	}

	m := make(map[string]string)
	for _, key := range vp.AllKeys() {
		m[key] = vp.GetString(key)
	}
	return m
}
<|endoftext|>


<commit_before>package chaos

// Owners are all GitHub handlers of all maintainers.
var Owners = []string{"bradbeam", "chrisohaver", "darshanime", "dilyevsky", "ekleiner", "fastest963", "greenpau", "ihac", "inigohu", "isolus", "johnbelamaric", "miekg", "nchrisdk", "nitisht", "pmoroney", "rajansandeep", "rdrozhdzh", "rtreffer", "stp-ip", "superq", "varyoo", "ykhr53", "yongtang"}
<commit_msg>Run go generate (#3856)<commit_after>package chaos

// Owners are all GitHub handlers of all maintainers.
var Owners = []string{"bradbeam", "chrisohaver", "darshanime", "dilyevsky", "ekleiner", "fastest963", "greenpau", "ihac", "inigohu", "isolus", "johnbelamaric", "miekg", "nchrisdk", "nitisht", "pmoroney", "rajansandeep", "rdrozhdzh", "rtreffer", "stp-ip", "superq", "varyoo", "ykhr53", "yongtang", "zouyee"}
<|endoftext|>