<commit_before>package cairo

//#cgo pkg-config: cairo
//#include <cairo/cairo.h>
import "C"

//Version returns the version of libcairo.
func Version() string {
	return C.GoString(C.cairo_version_string())
}
<commit_msg>inital context implementation<commit_after>package cairo

//#cgo pkg-config: cairo
//#include <cairo/cairo.h>
import "C"

import (
	"image/color"
	"runtime"
	"unsafe"
)

//Version returns the version of libcairo.

func Version() string {
	return C.GoString(C.cairo_version_string())
}

//The Context is the main object used when drawing with cairo.
//
//Defaults
//
//The default source pattern is equivalent to
//	cairo.NewSolidPattern(color.Black)
//
//The default fill rule is FillRuleWinding.
//
//The default line cap rule is LineCapButt.
//
//The default line join is LineJoinMiter.
//
//The default line width is 2.
//
//The default miter limit is 10.
//
//The default operator is OpOver.
//
//The default tolerance is 0.1.
//
//Originally cairo_t.
type Context struct {
	c *C.cairo_t
	s Surface
}

//New creates a new drawing context that draws on the target surface.
//
//Originally cairo_create.
func New(target Surface) (*Context, error) {
	s := target.ExtensionRaw()
	c := &Context{
		c: C.cairo_create(s),
		s: target,
	}
	runtime.SetFinalizer(c, (*Context).Close)
	return c, c.Err()
}

//Close destroys c.
//
//Originally cairo_destroy.
func (c *Context) Close() error {
	if c == nil || c.c == nil {
		return nil
	}
	runtime.SetFinalizer(c, nil)
	err := c.Err()
	C.cairo_destroy(c.c)
	c.c = nil
	c.s = nil
	return err
}

//Err reports the current error state of c.
//
//Originally cairo_status.
func (c *Context) Err() error {
	return toerr(C.cairo_status(c.c))
}

//Save makes a copy of the current drawing state on an internal stack
//of drawing states.
//
//Further calls on c will affect the current state but no saved states.
//A call to Restore returns c to the state it was in at the last invocation
//of Save.
//
//Originally cairo_save.
func (c *Context) Save() *Context {
	C.cairo_save(c.c)
	return c
}

//Restore the last drawing state saved with Save and
//remove that state from the stack of saved states.
//
//It is malformed to call Restore without a previous call to Save.
//
//Originally cairo_restore.
func (c *Context) Restore() error {
	C.cairo_restore(c.c)
	return c.Err()
}

//SaveRestore saves the current drawing state, runs f on c, and then restores
//the current drawing state.
func (c *Context) SaveRestore(f func(*Context) error) (err error) {
	c.Save()
	defer func() {
		e := c.Restore()
		if err != nil {
			err = e
		}
	}()
	err = f(c)
	return
}

//Target returns the surface passed to New.
//
//Originally cairo_get_target
func (c *Context) Target() Surface {
	return c.s
}

//PushGroup temporarily redirects drawing to an intermediate surface known
//as a group.
//The redirection lasts until the group is completed by a call to PopGroup
//or PopGroupToSource.
//These calls provide the result of any drawing to the group as a pattern,
//either as an explicit object or set as the source pattern.
//
//This group functionality can be convenient for performing intermediate
//compositing.
//One common use of a group is to render objects as opaque within the group,
//so that they occlude each other, and then blend the result with translucence
//onto the destination.
//
//Groups can be nested arbitrarily deep by making balanced calls to PushGroup
//and PopGroup/PopGroupToSource.
//Each call pushes/pops the new target group onto/from a stack.
//
//Like Save, any changes to the drawing state following PushGroup will not
//be visible after a call to PopGroup/PopGroupToSource.
//
//By default, this intermediate group will have a content type of
//ContentColorAlpha.
//Other content types may be specified by calling PushGroupWithContent instead.
//
//An example of a translucent filled and stroked path without any portion of the
//visible under the stroke:
//
//	c.PushGroup().
//		SetSource(fillPattern).
//		FillPreserve().
//		SetSource(strokePattern).
//		Stroke().
//		PopGroupToSource()
//	c.PaintWithAlpha(alpha)
//
//Originally cairo_push_group.
func (c *Context) PushGroup() *Context {
	C.cairo_push_group(c.c)
	return c
}

//PushGroupWithContent is similar to PushGroup except for additionally setting
//the content of the group.
//
//See the documentation for PushGroup for more information.
//
//Originally cairo_push_group_with_content.
func (c *Context) PushGroupWithContent(content content) *Context {
	C.cairo_push_group_with_content(c.c, content.c())
	return c
}

//PopGroup terminates the redirection begun by a call to PushGroup
//or PushGroupWithContent and returns a new Pattern.
//
//The drawing state of c is reset to what it was before the call to
//PushGroup/PushGroupWithContent.
//
//See the documentation for PushGroup for more information.
//
//Originally cairo_pop_group.
func (c *Context) PopGroup() (Pattern, error) {
	p := C.cairo_pop_group(c.c)
	if err := c.Err(); err != nil {
		return nil, err
	}
	return cPattern(p)
}

//PopGroupToSource terminates the redirection begun by a call to PushGroup
//or PushGroupWithContent and installs the resultant pattern as the source
//pattern in c.
//
//The drawing state of c is reset to what it was before the call to
//PushGroup/PushGroupWithContent.
//
//It is a convenience method equivalent to
//	func PopGroupToSource(c *Context) error {
//		p, err := c.PopGroup()
//		if err != nil {
//			return err
//		}
//		c.SetSource(p)
//		return p.Close()
//	}
//
//See the documentation for PushGroup for more information.
//
//Originally cairo_pop_group_to_source.
func (c *Context) PopGroupToSource() error {
	C.cairo_pop_group_to_source(c.c)
	return c.Err()
}

//GroupTarget returns the current destination surface for c.
//If there have been no calls to PushGroup/PushGroupWithContent,
//this is equivalent to Target.
//Otherwise,
//Originally cairo_get_group_target.
func (c *Context) GroupTarget() (Surface, error) {
	//XXX should we track group depth and return c.Target(), nil if 0?
	s := C.cairo_get_group_target(c.c)
	s = C.cairo_surface_reference(s)
	return cSurface(s)
}

//SetSourceColor sets the source pattern to col.
//This color will be used for any subsequent drawing operations, until a new
//source pattern is set.
//
//Originally cairo_set_source_rgba.
func (c *Context) SetSourceColor(col color.Color) *Context {
	r, g, b, a := colorToAlpha(col).c()
	C.cairo_set_source_rgba(c.c, r, g, b, a)
	return c
}

//SetSource sets the source pattern of c to source.
//This pattern will be used for any subsequent drawing operations, until a new
//source pattern is set.
//
//Note
//
//The pattern's transformation matrix will be locked to the user space in effect
//at the time of SetSource.
//This means that further modifications of the current transformation matrix will
//not affect the source pattern.
//See Pattern.SetMatrix.
//
//Originally cairo_set_source.
func (c *Context) SetSource(source Pattern) *Context {
	C.cairo_set_source(c.c, source.c())
	return c
}

//SetSourceSurface is a convenience function for creating a pattern
//from a surface and setting it as the source pattern in c
//with SetSource.
//
//The originDisplacement vector gives the user-space coordinates
//at which the surface origin should appear.
//The surface origin is its upper-left corner before any transformation
//has been applied.
//The x and y components of the vector are negated and then set
//as the translation values in the pattern matrix.
//
//Other than the initial pattern matrix, described above, all other
//pattern attributes are set to their default values.
//The resulting pattern can be retrieved by calling Source.
//
//Originally cairo_set_source_surface.
func (c *Context) SetSourceSurface(s Surface, originDisplacement Point) error {
	sr := s.ExtensionRaw()
	x, y := originDisplacement.c()
	C.cairo_set_source_surface(c.c, sr, x, y)
	return c.Err()
}

//Source returns the current source pattern for c.
//
//Originally cairo_get_source.
func (c *Context) Source() (Pattern, error) {
	p := C.cairo_get_source(c.c)
	p = C.cairo_pattern_reference(p)
	return cPattern(p)
}

//SetAntialiasMode sets the antialiasing mode of the rasterizer used
//for drawing shapes.
//This value is a hint, and a particular backend may or may not support
//a particular value.
//
//At the current time, no backend supports AntialiasSubpixel when drawing shapes.
//
//SetAntialiasMode does not affect text rendering, instead use
//FontOptions.SetAntialiasMode.
//
//Originally cairo_set_antialias.
func (c *Context) SetAntialiasMode(a antialias) *Context {
	C.cairo_set_antialias(c.c, a.c())
	return c
}

//AntialiasMode reports the current shape antialiasing mode.
//
//Originally cairo_get_antialias.
func (c *Context) AntialiasMode() antialias {
	return antialias(C.cairo_get_antialias(c.c))
}

//SetDash sets the dash pattern to be used by Stroke.
//
//A dash pattern is specified by a sequence of positive float64s.
//
//Each float64 represents the length of alternating "on" and "off"
//portions of the stroke.
//
//The offset specifies an offset into the pattern at which the stroke begins.
//
//Each "on" segment will have caps applied as if the segment were a separate
//sub-path.
//It is valid to use an "on" length of 0 with LineCapRound or LineCapSquare
//in order to distribute dots or squares along a path.
//
//Note
//
//The length values are in user-space units as evaluated
//at the time of stroking, which is not necessarily the same as the user space
//at the time SetDash is called.
//
//Special Cases
//
//If the length of dashes is 0, dashing is disabled.
//
//If the length of dashes is 1, a symmetric pattern is assumed,
//where the alternating off and on portions are of the single length provided.
//That is
//	SetDash(0, .5)
//and
//	SetDash(0, .5, .5)
//are equivalent.
//
//Errors
//
//If any of the elements of dashes is negative or all are zero,
//ErrInvalidDash is returned and the dash is not set.
//This differs from libcairo, which puts c into an error mode.
//
//Orginally cairo_set_dash.
func (c *Context) SetDash(offset float64, dashes ...float64) error {
	off := C.double(offset)
	nd := len(dashes)

	arr := make([]C.double, nd)
	allZero := true
	for i, d := range dashes {
		if d < 0 {
			return ErrInvalidDash
		}
		if d > 0 {
			allZero = false
		}
		arr[i] = C.double(d)
	}
	if allZero {
		return ErrInvalidDash
	}

	C.cairo_set_dash(c.c, &arr[0], C.int(nd), off)
	return nil
}

//DashCount reports the length of the dash sequence or 0 if dashing is not
//currently in effect.
//
//Originally cairo_get_dash_count.
func (c *Context) DashCount() int {
	return int(C.cairo_get_dash_count(c.c))
}

//Dashes reports the current dash sequence.
//If dashing is not currently in effect the length of dashes
//is 0.
//
//Originally cairo_get_dash
func (c *Context) Dashes() (offset float64, dashes []float64) {
	ln := c.DashCount()
	if ln == 0 {
		return
	}

	var off C.double
	arr := make([]C.double, ln)
	C.cairo_get_dash(c.c, &arr[0], &off)
	offset = float64(off)

	dashes = make([]float64, ln)
	for i, v := range arr {
		dashes[i] = float64(v)
	}

	return
}

//SetFillRule sets the fill rule on c.
//The fill rule is used to determine which regions are inside or outside
//a complex, potentially self-intersecting, path.
//
//The fill rule affects Fill and Clip.
//
//Originally cairo_set_fill_rule.
func (c *Context) SetFillRule(f fillRule) *Context {
	C.cairo_set_fill_rule(c.c, f.c())
	return c
}

//FillRule reports the current fill rule.
//
//Originally cairo_get_fill_rule.
func (c *Context) FillRule() fillRule {
	return fillRule(C.cairo_get_fill_rule(c.c))
}

//SetLineCap sets the line cap style.
//
//Originally cairo_set_line_cap
func (c *Context) SetLineCap(lc lineCap) *Context {
	C.cairo_set_line_cap(c.c, lc.c())
	return c
}

//LineCap reports the current line cap.
//
//Originally cairo_get_line_cap.
func (c *Context) LineCap() lineCap {
	return lineCap(C.cairo_get_line_cap(c.c))
}

//SetLineJoin sets the line join style.
//
//Originally cairo_set_line_join
func (c *Context) SetLineJoin(l lineJoin) *Context {
	C.cairo_set_line_join(c.c, l.c())
	return c
}

//LineJoin reports the current line join style.
//
//Originally cairo_get_line_join.
func (c *Context) LineJoin() lineJoin {
	return lineJoin(C.cairo_get_line_join(c.c))
}

//SetLineWidth sets the current line width.
//The line width specifies the diameter of a pen that is circular
//in user space, though the device space pen may be an ellipse due
//to shearing in the coordinate transform matrix.
//The user space and coordinate transform matrix referred to above are computed
//at stroke time, not at the time SetLineWidth is called.
//
//Originally cairo_set_line_width.
func (c *Context) SetLineWidth(width float64) *Context {
	C.cairo_set_line_width(c.c, C.double(width))
	return c
}

//LineWidth reports the line width as set by SetLineWidth and does not
//take any intervening changes to the coordinate transform matrix into account.
//
//Originally cairo_get_line_width
func (c *Context) LineWidth() float64 {
	return float64(C.cairo_get_line_width(c.c))
}

//SetMiterLimit sets the miter limit.
//
//When the current line join style is LineJoinMiter, the miter limit is used to
//determine whether the lines should be joined with a bevel instead of a miter.
//
//Cairo divides the length of the miter by the line width.
//If the result is greater than the miter limit, the style is converted to a
//bevel.
//
//A miter limit for a given angle can be computed by:
//	miter limit = 1/sin(angle/2)
//
//Examples
//
//For the default of 10, joins with interior angles less than 11 degrees are
//converted from miters to bevels.
//
//For reference, a mite limit of 2 makes the miter cutoff at 60 degrees,
//and a miter limit of 1.414 makes the cutoff at 90 degrees.
//
//Originally cairo_set_miter_limit.
func (c *Context) SetMiterLimit(ml float64) *Context {
	C.cairo_set_miter_limit(c.c, C.double(ml))
	return c
}

//MiterLimit returns the current miter limit as set by SetMiterLimit.
//
//Originally cairo_get_miter_limit.
func (c *Context) MiterLimit() float64 {
	return float64(C.cairo_get_miter_limit(c.c))
}

//SetOperator sets the compositing operator used for all drawing operations.
//
//Originally cairo_set_operator.
func (c *Context) SetOperator(op op) *Context {
	C.cairo_set_operator(c.c, op.c())
	return c
}

//Operator reports the current compositing operator.
//
//Originally cairo_get_operator.
func (c *Context) Operator() op {
	return op(C.cairo_get_operator(c.c))
}

//SetTolerance sets the tolerance, in device units, when converting paths into
//trapezoids.
//Curved segments of the path will be subdivided until the maximum deviation
//between the original path and the polygonal approximation is less than
//tolerance.
//
//A larger value than the default of 0.1 will give better performance.
//While in general a lower value improves appearance, it is unlikely a value
//lower than .1 will improve appearance significantly.
//
//The accuracy of paths within libcairo is limited by the precision of its
//internal arithmetic and tolerance is restricted by the smallest representable
//internal value.
//
//Originally cairo_set_tolerance.
func (c *Context) SetTolerance(tolerance float64) *Context {
	C.cairo_set_tolerance(c.c, C.double(tolerance))
	return c
}

//Tolerance reports the tolerance in device units.
//
//Originally cairo_get_tolerance.
func (c *Context) Tolerance() float64 {
	return float64(C.cairo_get_tolerance(c.c))
}

//Clip establishes a new clip region by intersecting the current clip region
//with the current path as it would be filled by Fill and according to the
//current fill rule.
//
//After Clip, the current path will be cleared from the cairo context.
//
//The current clip region affects all drawing operations by effectively masking
//out any changes to the surface that are outside the current clip region.
//
//Clip can only make the clip region smaller, never larger.
//But the current clip is part of the graphics state, so a temporary restriction
//of the clip region can be achieved by calling Clip within a Save/Restore pair.
//The only other means of increasing the size of the clip region is ResetClip.
//
//Originally cairo_clip.
func (c *Context) Clip() *Context {
	C.cairo_clip(c.c)
	return c
}

//ClipPreserve is identical Clip but preserves the path in c.
//
//Originally cairo_clip_preserve.
func (c *Context) ClipPreserve() *Context {
	C.cairo_clip_preserve(c.c)
	return c
}

//ClipExtents computes a bounding box in user coordinates covering the area
//inside the current clip.
//
//Originally cairo_clip_extents.
func (c *Context) ClipExtents() Rectangle {
	var x0, y0, x1, y1 C.double
	C.cairo_clip_extents(c.c, &x0, &y0, &x1, &y1)
	return cRect(x0, y0, x1, y1)
}

//InClip reports whether pt is in the currently visible area defined by the
//clipping region.
//
//Originally cairo_in_clip.
func (c *Context) InClip(pt Point) bool {
	x, y := pt.c()
	return C.cairo_in_clip(c.c, x, y) == 1
}

//ResetClip resets the current clip region to its original, unrestricted state.
//That is, set the clip region to an infinitely large shape containing
//the target surface.
//Equivalently, one can imagine the clip region being reset to the exact bounds
//of the target surface.
//
//Note that code meant to be reusable should not call ResetClip as it will
//cause results unexpected by higher-level code which calls ResetClip.
//Consider using Save and Restore around Clip as a more robust means of
//temporarily restricting the clip region.
//
//Originally cairo_reset_clip.
func (c *Context) ResetClip() *Context {
	C.cairo_reset_clip(c.c)
	return c
}

//ClipRectangles reports the current clip region as a list of rectangles
//in user coordinates or an error if the clip region cannot be so represented.
//
//Originally cairo_copy_clip_rectangle_list.
func (c *Context) ClipRectangles() (list []Rectangle, err error) {
	rects := C.cairo_copy_clip_rectangle_list(c.c)
	if err := toerr(rects.status); err != nil {
		return nil, err
	}

	n := int(rects.num_rectangles)
	if n == 0 {
		return nil, nil
	}
	rs := (*[1 << 30]C.cairo_rectangle_t)(unsafe.Pointer(rects.rectangles))[:n:n]
	list = make([]Rectangle, n)
	for i, v := range rs {
		list[i] = cRect(v.x, v.y, v.x+v.width, v.y+v.height)
	}

	C.cairo_rectangle_list_destroy(rects)

	return
}

//Fill fills the current path according to the current fill rule,
//(each sub-path is implicitly closed before being filled).
//After fill, the current path will be cleared from the cairo context.
//
//Originally cairo_fill.
func (c *Context) Fill() *Context {
	C.cairo_fill(c.c)
	return c
}

//FillPreserve is identical to Fill except it does not clear the current path.
//
//Originally cairo_fill_preserve.
func (c *Context) FillPreserve() *Context {
	C.cairo_fill_preserve(c.c)
	return c
}

//FillExtents computes a bounding box in user coordinates covering the area that
//would be affected, (the "inked" area), by a Fill operation given the current
//path and fill parameters.
//If the current path is empty, it returns ZR.
//Surface dimensions and clipping are not taken into account.
//
//Contrast with PathExtents, which is similar, but returns non-zero extents
//for some paths with no inked area, (such as a simple line segment).
//
//FillExtents must necessarily do more work to compute the precise inked areas
//in light of the fill rule, so PathExtents may be more desirable for sake of
//performance if the non-inked path extents are desired.
//
//Originally cairo_fill_extents.
func (c *Context) FillExtents() Rectangle {
	var x1, y1, x2, y2 C.double
	C.cairo_fill_extents(c.c, &x1, &y1, &x2, &y2)
	return cRect(x1, y1, x2, y2)
}

//InFill reports whether the given point is inside the area that would be
//affected by a Fill, given the current path and filling parameters.
//Surface dimensions and clipping are not taken into account.
//
//Originally cairo_in_fill.
func (c *Context) InFill(pt Point) bool {
	x, y := pt.c()
	return C.cairo_in_fill(c.c, x, y) == 1
}

//Mask paints the current source using the alpha channel of pattern as a mask.
//Opaque areas of pattern are painted with the source, transparent areas are
//not painted.
//
//Originally cairo_mask.
func (c *Context) Mask(p Pattern) *Context {
	C.cairo_mask(c.c, p.c())
	return c
}

//MaskSurface paints the current source using the alpha channel of surface
//as a mask.
//Opaque areas of surface are painted with the source, transparent areas are
//not painted.
//
//Originally cairo_mask_surface.
func (c *Context) MaskSurface(s Surface, offsetVector Point) *Context {
	x, y := offsetVector.c()
	C.cairo_mask_surface(c.c, s.ExtensionRaw(), x, y)
	return c
}

//Paint paints the current source everywhere within the current clip region.
//
//originally cairo_paint.
func (c *Context) Paint() *Context {
	C.cairo_paint(c.c)
	return c
}

//PaintAlpha paints the current source everywhere within the current clip
//region, using a mask of constant alpha value alpha.
//
//The effect is similar to Paint, but the drawing is faded out using
//the alpha value.
//
//originally cairo_paint.
func (c *Context) PaintAlpha(alpha float64) *Context {
	C.cairo_paint_with_alpha(c.c, C.double(alpha))
	return c
}

//Stroke strokes the current path according to the current line width,
//line join, line cap, and dash settings.
//
//After Stroke, the current path will be cleared from the cairo context.
//
//Degenerate segments and sub-paths are treated specially and provide a useful
//result.
//These can result in two different situations:
//
//1. Zero-length "on" segments set in SetDash.
//If the cap style is LineCapRound or LineCapSquare then these segments will be
//drawn as circular dots or squares respectively.
//In the case of LineCapSquare, the orientation of the squares is determined by
//the direction of the underlying path.
//
//2. A sub-path created by MoveTo followed by either a ClosePath or one or more
//calls to LineTo to the same coordinate as the MoveTo.
//If the cap style is LineCapRound then these sub-paths will be drawn as
//circular dots.
//Note that in the case of LineCapSquare a degenerate sub-path will not be drawn
//at all, as the correct orientation is indeterminate.
//
//In no case will a cap style of LineCapButt cause anything to be drawn in the
//case of either degenerate segments or sub-paths.
//
//Originally cairo_stroke.
func (c *Context) Stroke() *Context {
	C.cairo_stroke(c.c)
	return c
}

//StrokePreserve is identical to Stroke except the path is not cleared.
//
//Originally cairo_stroke_preserve.
func (c *Context) StrokePreserve() *Context {
	C.cairo_stroke_preserve(c.c)
	return c
}

//StrokeExtents computes a bounding box in user coordinates covering the area
//that would be affected, (the "inked" area), by a Stroke operation given the
//current path and stroke parameters.
//If the current path is empty, returns the empty rectangle ZR.
//Surface dimensions and clipping are not taken into account.
//
//Note that StrokeExtents must necessarily do more work to compute the precise
//inked areas in light of the stroke parameters, so PathExtents may be more
//desirable for sake of performance if non-inked path extents are desired.
//
//Originally cairo_stroke_extents.
func (c *Context) StrokeExtents() Rectangle {
	var x1, y1, x2, y2 C.double
	C.cairo_stroke_extents(c.c, &x1, &y1, &x2, &y2)
	return cRect(x1, y1, x2, y2)
}

//InStroke reports whether the given point is inside the area that would be
//affected by a Stroke operation given the current path and stroking
//parameters.
//Surface dimensions and clipping are not taken into account.
//
//Originally cairo_in_stroke.
func (c *Context) InStroke(pt Point) bool {
	x, y := pt.c()
	return C.cairo_in_stroke(c.c, x, y) == 1
}

//CopyPage emits the current page for backends that support multiple pages,
//but doesn't clear it, so, the contents of the current page will be retained
//for the next page too.
//
//Use ShowPage if you want to get an empty page after the emission.
//
//This is a convenience function that simply calls CopyPage on c's target.
//
//Originally cairo_copy_page.
func (c *Context) CopyPage() *Context {
	C.cairo_copy_page(c.c)
	return c
}

//ShowPage emits and clears the current page for backends that support multiple
//pages.
//
//Use CopyPage if you don't want to clear the page.
//
//This is a convenience function that simply calls ShowPage on c's target.
//
//Originally cairo_show_page.
func (c *Context) ShowPage() *Context {
	C.cairo_show_page(c.c)
	return c
}
<|endoftext|>


<commit_before>package ginkgo

import (
	_ "github.com/go-task/slim-sprig"
	_ "golang.org/x/tools/go/ast/inspector"
)

// This file imports the CLI dependencies so that consuming packages have all the dependenceies they need to compile and run the Ginkgo CLI
<commit_msg>add all cli dependencies<commit_after>package ginkgo

import (
	_ "github.com/go-task/slim-sprig"
	_ "github.com/google/pprof/profile"
	_ "golang.org/x/tools/go/ast/inspector"
)

// This file imports the CLI dependencies so that consuming packages have all the dependenceies they need to compile and run the Ginkgo CLI
<|endoftext|>


<commit_before>package tachymeter

import (
	"math"
	"sort"
	"time"
)

// Satisfy sort for timeSlice.
// Sorts in increasing order of duration.

func (p timeSlice) Len() int {
	return len(p)
}

func (p timeSlice) Less(i, j int) bool {
	return int64(p[i]) < int64(p[j])
}

func (p timeSlice) Swap(i, j int) {
	p[i], p[j] = p[j], p[i]
}

// Calc calcs data held in a *Tachymeter
// and returns a *Metrics.
func (m *Tachymeter) Calc() *Metrics {
	m.Lock()
	defer m.Unlock()

	m.Times = m.Times[:m.TimesUsed]
	sort.Sort(m.Times)

	metrics := &Metrics{}
	metrics.Samples = m.TimesUsed
	metrics.Count = m.Count
	metrics.Time.Total = calcTotal(m.Times)
	metrics.Time.Avg = calcAvg(metrics.Time.Total, metrics.Samples)
	metrics.Time.p95 = calcp95(m.Times)
	metrics.Time.Long5p = calcLong5p(m.Times)
	metrics.Time.Short5p = calcShort5p(m.Times)
	metrics.Time.Max = m.Times[metrics.Samples-1]
	metrics.Time.Min = m.Times[0]
	rateTime := float64(metrics.Samples) / float64(metrics.Time.Total)
	metrics.Rate.Second = rateTime * 1e9

	return metrics
}

// These should be self-explanatory:

func calcTotal(d []time.Duration) time.Duration {
	var t time.Duration
	for _, d := range d {
		t += d
	}

	return t
}

func calcAvg(d time.Duration, c int) time.Duration {
	return time.Duration(int(d) / c)
}

func calcp95(d []time.Duration) time.Duration {
	set := d[int(float64(len(d))*0.95):]

	var t time.Duration
	var i int
	for _, n := range set {
		t += n
		i++
	}

	return time.Duration(int(t) / i)
}

func calcLong5p(d []time.Duration) time.Duration {
	set := d[:int(math.Ceil(float64(len(d))*0.05))]

	var t time.Duration
	var i int
	for _, n := range set {
		t += n
		i++
	}

	return time.Duration(int(t) / i)
}

func calcShort5p(d []time.Duration) time.Duration {
	set := d[:int(float64(len(d))*0.05)]
	if len(set) == 0 {
		return time.Millisecond * 0
	}

	var t time.Duration
	var i int
	for _, n := range set {
		t += n
		i++
	}

	return time.Duration(int(t) / i)
}
<commit_msg>updated calc<commit_after>package tachymeter

import (
	"math"
	"sort"
	"time"
)

// Satisfy sort for timeSlice.
// Sorts in increasing order of duration.

func (p timeSlice) Len() int {
	return len(p)
}

func (p timeSlice) Less(i, j int) bool {
	return int64(p[i]) < int64(p[j])
}

func (p timeSlice) Swap(i, j int) {
	p[i], p[j] = p[j], p[i]
}

// Calc calcs data held in a *Tachymeter
// and returns a *Metrics.
func (m *Tachymeter) Calc() *Metrics {
	m.Lock()
	defer m.Unlock()

	m.Times = m.Times[:m.TimesUsed]
	sort.Sort(m.Times)

	metrics := &Metrics{}
	metrics.Samples = m.TimesUsed
	metrics.Count = m.Count
	metrics.Time.Total = calcTotal(m.Times)
	metrics.Time.Avg = calcAvg(metrics.Time.Total, metrics.Samples)
	metrics.Time.p95 = calcp95(m.Times)
	metrics.Time.Long5p = calcLong5p(m.Times)
	metrics.Time.Short5p = calcShort5p(m.Times)
	metrics.Time.Max = m.Times[metrics.Samples-1]
	metrics.Time.Min = m.Times[0]
	rateTime := float64(metrics.Samples) / float64(metrics.Time.Total)
	metrics.Rate.Second = rateTime * 1e9

	return metrics
}

// These should be self-explanatory:

func calcTotal(d []time.Duration) time.Duration {
	var t time.Duration
	for _, d := range d {
		t += d
	}

	return t
}

func calcAvg(d time.Duration, c int) time.Duration {
	return time.Duration(int(d) / c)
}

func calcp95(d []time.Duration) time.Duration {
	return d[int(float64(len(d))*0.95)]
}

func calcLong5p(d []time.Duration) time.Duration {
        set := d[int(float64(len(d))*0.95):]

	var t time.Duration
	var i int
	for _, n := range set {
		t += n
		i++
	}

	return time.Duration(int(t) / i)
}

func calcShort5p(d []time.Duration) time.Duration {
	set := d[:int(math.Ceil(float64(len(d))*0.05))]

	var t time.Duration
	var i int
	for _, n := range set {
		t += n
		i++
	}

	return time.Duration(int(t) / i)
}
<|endoftext|>


<commit_before>package analyze

import (
	"encoding/json"
	"errors"
	"fmt"
	"net/http"
	"regexp"

	"github.com/deckarep/golang-set"
	"github.com/jzelinskie/geddit"
)

func AnalyzeComments(s *geddit.OAuthSession, comments []*geddit.Comment) error {
	r, err := regexp.Compile(`github\.com\/\w+\/\w+`)
	if err != nil {
		return err
	}
	for _, comment := range comments {
		if comment.Author == "github-stats-bot" {
			continue
		}
		if r.MatchString(comment.Body) {
			linkSet := mapset.NewSet()
			for _, link := range r.FindAllString(comment.Body, -1) {
				linkSet.Add(link)
			}
			var links []string
			for _, link := range linkSet.ToSlice() {
				links = append(links, link.(string))
			}
			if err = postReply(s, comment, links); err != nil {
				return err
			}
		}
	}
	return nil
}

func postReply(s *geddit.OAuthSession, comment *geddit.Comment, links []string) error {
	footer := "***\n^(This is Earth radio, and now here's human music ♫)\n\n^[Source](https://github.com/anaskhan96/github-stats-bot) ^| ^[PMme](https://np.reddit.com/message/compose?to=github-stats-bot)"
	var reply string
	for _, link := range links {
		var data map[string]interface{}
		if err := getStats(link, &data); err != nil {
			return err
		}
		if data["message"] == "Not Found" {
			return errors.New("Wrong GitHub API endpoint")
		}
		description := data["description"].(string)
		stargazers := int(data["stargazers_count"].(float64))
		forks := int(data["forks_count"].(float64))
		issuesURL := "https://" + link + "/issues"
		pullsURL := "https://" + link + "/pulls"
		reply += fmt.Sprintf("\n[%s](https://%s)\n\n> *Description*: %s\n\n> *Stars*: %d\n\n> *Forks*: %d\n\n> [Issues](%s) | [Pull Requests](%s)\n\n",
			link[11:], link, description, stargazers, forks, issuesURL, pullsURL)
	}
	reply += footer
	if _, err := s.Reply(comment, reply); err != nil {
		return err
	}
	return nil
}

func getStats(link string, data *map[string]interface{}) error {
	res, err := http.Get("https://api.github.com/repos/" + link[11:])
	if err != nil {
		return err
	}
	defer res.Body.Close()
	if err = json.NewDecoder(res.Body).Decode(&data); err != nil {
		return err
	}
	return nil
}
<commit_msg>fixing interface panic error<commit_after>package analyze

import (
	"encoding/json"
	"errors"
	"fmt"
	"net/http"
	"regexp"

	"github.com/deckarep/golang-set"
	"github.com/jzelinskie/geddit"
)

func AnalyzeComments(s *geddit.OAuthSession, comments []*geddit.Comment) error {
	r, err := regexp.Compile(`github\.com\/\w+\/\w+`)
	if err != nil {
		return err
	}
	for _, comment := range comments {
		if comment.Author == "github-stats-bot" {
			continue
		}
		if r.MatchString(comment.Body) {
			linkSet := mapset.NewSet()
			for _, link := range r.FindAllString(comment.Body, -1) {
				linkSet.Add(link)
			}
			var links []string
			for _, link := range linkSet.ToSlice() {
				links = append(links, link.(string))
			}
			if err = postReply(s, comment, links); err != nil {
				return err
			}
		}
	}
	return nil
}

func postReply(s *geddit.OAuthSession, comment *geddit.Comment, links []string) error {
	footer := "***\n^(This is Earth radio, and now here's human music ♫)\n\n^[Source](https://github.com/anaskhan96/github-stats-bot) ^| ^[PMme](https://np.reddit.com/message/compose?to=github-stats-bot)"
	var reply string
	for _, link := range links {
		var data map[string]interface{}
		if err := getStats(link, &data); err != nil {
			return err
		}
		if data["message"] == "Not Found" {
			return errors.New("Wrong GitHub API endpoint")
		}
		description := data["description"]
		stargazers := int(data["stargazers_count"].(float64))
		forks := int(data["forks_count"].(float64))
		issuesURL := "https://" + link + "/issues"
		pullsURL := "https://" + link + "/pulls"
		reply += fmt.Sprintf("\n[%s](https://%s)\n\n> *Description*: %v\n\n> *Stars*: %d\n\n> *Forks*: %d\n\n> [Issues](%s) | [Pull Requests](%s)\n\n",
			link[11:], link, description, stargazers, forks, issuesURL, pullsURL)
	}
	reply += footer
	if _, err := s.Reply(comment, reply); err != nil {
		return err
	}
	return nil
}

func getStats(link string, data *map[string]interface{}) error {
	res, err := http.Get("https://api.github.com/repos/" + link[11:])
	if err != nil {
		return err
	}
	defer res.Body.Close()
	if err = json.NewDecoder(res.Body).Decode(&data); err != nil {
		return err
	}
	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"log"
	"strings"

	"k8s.io/client-go/rest"
	"k8s.io/client-go/tools/clientcmd"

	flags "github.com/jessevdk/go-flags"
	"github.com/rubenv/kube-appdeploy"
)

func main() {
	err := do()
	if err != nil {
		log.Fatal(err)
	}
}

type GlobalOptions struct {
	Context     string            `short:"c" long:"context" description:"Kubernetes context to use"`
	Variables   map[string]string `short:"v" long:"variable" description:"Extra variables to set"`
	PullSecrets []string          `short:"i" long:"imagepullsecret" description:"Image pull secrets to configure"`

	Args struct {
		Folder string `positional-arg-name:"folder" description:"Path to the configuration files"`
	} `positional-args:"yes" required:"yes"`
}

var globalOpts = &GlobalOptions{}
var parser = flags.NewParser(globalOpts, flags.Default)

func do() error {
	_, err := parser.Parse()
	if e, ok := err.(*flags.Error); ok && e.Type == flags.ErrHelp {
		return nil
	}
	if err != nil {
		return err
	}

	var target appdeploy.Target
	src, err := appdeploy.NewFolderSource(globalOpts.Args.Folder)
	if err != nil {
		return err
	}

	vars, err := src.Variables()
	if err != nil {
		return err
	}

	for k, v := range globalOpts.Variables {
		vars.Variables[k] = v
	}
	vars.ImagePullSecrets = globalOpts.PullSecrets

	contextName := globalOpts.Context

	// Prepare Kubernetes client
	po := clientcmd.NewDefaultPathOptions()

	c, err := po.GetStartingConfig()
	if err != nil {
		return err
	}

	if contextName == "" {
		contextName = c.CurrentContext
	}

	context, ok := c.Contexts[contextName]
	if !ok {
		names := make([]string, 0)
		for name, _ := range c.Contexts {
			names = append(names, name)
		}

		return fmt.Errorf("Unknown context: %s, should be one of: %s", contextName, strings.Join(names, ", "))
	}

	authinfo, ok := c.AuthInfos[context.AuthInfo]
	if !ok {
		return fmt.Errorf("Badly configured context, unknown auth: %s", context.AuthInfo)
	}

	cluster, ok := c.Clusters[context.Cluster]
	if !ok {
		return fmt.Errorf("Badly configured context, unknown cluster: %s", context.Cluster)
	}

	config := &rest.Config{
		Host:        cluster.Server,
		BearerToken: authinfo.Token,
		TLSClientConfig: rest.TLSClientConfig{
			CAFile:   cluster.CertificateAuthority,
			CertFile: authinfo.ClientCertificate,
			KeyFile:  authinfo.ClientKey,
		},
	}

	target = appdeploy.NewKubernetesTarget(config)

	return appdeploy.Process(src, target)
}
<commit_msg>Support relative file references in kubeconfig<commit_after>package main

import (
	"fmt"
	"log"
	"strings"

	"k8s.io/client-go/rest"
	"k8s.io/client-go/tools/clientcmd"

	flags "github.com/jessevdk/go-flags"
	"github.com/rubenv/kube-appdeploy"
)

func main() {
	err := do()
	if err != nil {
		log.Fatal(err)
	}
}

type GlobalOptions struct {
	Context     string            `short:"c" long:"context" description:"Kubernetes context to use"`
	Variables   map[string]string `short:"v" long:"variable" description:"Extra variables to set"`
	PullSecrets []string          `short:"i" long:"imagepullsecret" description:"Image pull secrets to configure"`

	Args struct {
		Folder string `positional-arg-name:"folder" description:"Path to the configuration files"`
	} `positional-args:"yes" required:"yes"`
}

var globalOpts = &GlobalOptions{}
var parser = flags.NewParser(globalOpts, flags.Default)

func do() error {
	_, err := parser.Parse()
	if e, ok := err.(*flags.Error); ok && e.Type == flags.ErrHelp {
		return nil
	}
	if err != nil {
		return err
	}

	var target appdeploy.Target
	src, err := appdeploy.NewFolderSource(globalOpts.Args.Folder)
	if err != nil {
		return err
	}

	vars, err := src.Variables()
	if err != nil {
		return err
	}

	for k, v := range globalOpts.Variables {
		vars.Variables[k] = v
	}
	vars.ImagePullSecrets = globalOpts.PullSecrets

	contextName := globalOpts.Context

	// Prepare Kubernetes client
	po := clientcmd.NewDefaultPathOptions()
	po.LoadingRules.DoNotResolvePaths = false

	c, err := po.GetStartingConfig()
	if err != nil {
		return err
	}

	if contextName == "" {
		contextName = c.CurrentContext
	}

	context, ok := c.Contexts[contextName]
	if !ok {
		names := make([]string, 0)
		for name, _ := range c.Contexts {
			names = append(names, name)
		}

		return fmt.Errorf("Unknown context: %s, should be one of: %s", contextName, strings.Join(names, ", "))
	}

	authinfo, ok := c.AuthInfos[context.AuthInfo]
	if !ok {
		return fmt.Errorf("Badly configured context, unknown auth: %s", context.AuthInfo)
	}

	cluster, ok := c.Clusters[context.Cluster]
	if !ok {
		return fmt.Errorf("Badly configured context, unknown cluster: %s", context.Cluster)
	}

	config := &rest.Config{
		Host:        cluster.Server,
		BearerToken: authinfo.Token,
		TLSClientConfig: rest.TLSClientConfig{
			CAFile:   cluster.CertificateAuthority,
			CertFile: authinfo.ClientCertificate,
			KeyFile:  authinfo.ClientKey,
		},
	}

	target = appdeploy.NewKubernetesTarget(config)

	return appdeploy.Process(src, target)
}
<|endoftext|>


<commit_before>/*
Package lmdbscan provides a wrapper for lmdb.Cursor to simplify iteration.
This package is experimental and it's API may change.
*/
package lmdbscan

import (
	"fmt"

	"github.com/bmatsuo/lmdb-go/lmdb"
)

// errClosed is an error returned to the user when attempting to operate on a
// closed Scanner.
var errClosed = fmt.Errorf("scanner is closed")

// Scanner is a low level construct for scanning databases inside a
// transaction.
type Scanner struct {
	dbi    lmdb.DBI
	cur    *lmdb.Cursor
	op     uint
	setop  *uint
	setkey []byte
	setval []byte
	key    []byte
	val    []byte
	err    error
}

// New allocates and intializes a Scanner for dbi within txn.  When the Scanner
// returned by New is no longer needed its Close method must be called.
func New(txn *lmdb.Txn, dbi lmdb.DBI) *Scanner {
	s := &Scanner{
		dbi: dbi,
		op:  lmdb.Next,
	}

	s.cur, s.err = txn.OpenCursor(dbi)
	return s
}

// Cursor returns the lmdb.Cursor underlying s.  Cursor returns nil if the s is
// closed.
func (s *Scanner) Cursor() *lmdb.Cursor {
	return s.cur
}

// Del will delete the key at the current cursor location.
//
// Del is deprecated.  Instead use s.Cursor().Del(flags).
func (s *Scanner) Del(flags uint) error {
	if s.cur == nil {
		return errClosed
	}
	return s.cur.Del(flags)
}

// Key returns the key read during the last call to Scan.
func (s *Scanner) Key() []byte {
	return s.key
}

// Val returns the value read during the last call to Scan.
func (s *Scanner) Val() []byte {
	return s.val
}

// Set marks the starting position for iteration.  On the next call to s.Scan()
// the underlying cursor will be moved as c.Get(k, v, opset).
func (s *Scanner) Set(k, v []byte, opset uint) {
	if s.err != nil {
		return
	}
	s.setop = new(uint)
	*s.setop = opset
	s.setkey = k
	s.setval = v
}

// SetNext determines the cursor behavior for subsequent calls to s.Scan().
// The immediately following call to s.Scan() behaves as if s.Set(k,v,opset)
// was called.  Subsequent calls move the cursor as c.Get(nil, nil, opnext)
func (s *Scanner) SetNext(k, v []byte, opset, opnext uint) {
	s.Set(k, v, opset)
	s.op = opnext
}

// Scan gets successive key-value pairs using the underlying cursor.  Scan
// returns false when key-value pairs are exhausted or another error is
// encountered.
func (s *Scanner) Scan() bool {
	if !s.checkOpen() {
		return false
	}
	if s.setop == nil {
		s.key, s.val, s.err = s.cur.Get(nil, nil, s.op)
	} else {
		s.key, s.val, s.err = s.cur.Get(s.setkey, s.setval, *s.setop)
		s.setkey = nil
		s.setval = nil
		s.setop = nil
	}
	return s.err == nil
}

func (s *Scanner) checkOpen() bool {
	if s.cur != nil {
		return true
	}
	if s.err == nil {
		s.err = errClosed
	}
	return false
}

// Err returns a non-nil error if and only if the previous call to s.Scan()
// resulted in an error other than lmdb.ErrNotFound.
func (s *Scanner) Err() error {
	if lmdb.IsNotFound(s.err) {
		return nil
	}
	return s.err
}

// Close closes the cursor underlying s and clears its ows internal structures.
// Close does not attempt to terminate the enclosing transaction.
//
// Scan must not be called after Close.
func (s *Scanner) Close() {
	if s.cur != nil {
		s.cur.Close()
		s.cur = nil
	}
}
<commit_msg>Docs: typo<commit_after>/*
Package lmdbscan provides a wrapper for lmdb.Cursor to simplify iteration.
This package is experimental and it's API may change.
*/
package lmdbscan

import (
	"fmt"

	"github.com/bmatsuo/lmdb-go/lmdb"
)

// errClosed is an error returned to the user when attempting to operate on a
// closed Scanner.
var errClosed = fmt.Errorf("scanner is closed")

// Scanner is a low level construct for scanning databases inside a
// transaction.
type Scanner struct {
	dbi    lmdb.DBI
	cur    *lmdb.Cursor
	op     uint
	setop  *uint
	setkey []byte
	setval []byte
	key    []byte
	val    []byte
	err    error
}

// New allocates and intializes a Scanner for dbi within txn.  When the Scanner
// returned by New is no longer needed its Close method must be called.
func New(txn *lmdb.Txn, dbi lmdb.DBI) *Scanner {
	s := &Scanner{
		dbi: dbi,
		op:  lmdb.Next,
	}

	s.cur, s.err = txn.OpenCursor(dbi)
	return s
}

// Cursor returns the lmdb.Cursor underlying s.  Cursor returns nil if s is
// closed.
func (s *Scanner) Cursor() *lmdb.Cursor {
	return s.cur
}

// Del will delete the key at the current cursor location.
//
// Del is deprecated.  Instead use s.Cursor().Del(flags).
func (s *Scanner) Del(flags uint) error {
	if s.cur == nil {
		return errClosed
	}
	return s.cur.Del(flags)
}

// Key returns the key read during the last call to Scan.
func (s *Scanner) Key() []byte {
	return s.key
}

// Val returns the value read during the last call to Scan.
func (s *Scanner) Val() []byte {
	return s.val
}

// Set marks the starting position for iteration.  On the next call to s.Scan()
// the underlying cursor will be moved as c.Get(k, v, opset).
func (s *Scanner) Set(k, v []byte, opset uint) {
	if s.err != nil {
		return
	}
	s.setop = new(uint)
	*s.setop = opset
	s.setkey = k
	s.setval = v
}

// SetNext determines the cursor behavior for subsequent calls to s.Scan().
// The immediately following call to s.Scan() behaves as if s.Set(k,v,opset)
// was called.  Subsequent calls move the cursor as c.Get(nil, nil, opnext)
func (s *Scanner) SetNext(k, v []byte, opset, opnext uint) {
	s.Set(k, v, opset)
	s.op = opnext
}

// Scan gets successive key-value pairs using the underlying cursor.  Scan
// returns false when key-value pairs are exhausted or another error is
// encountered.
func (s *Scanner) Scan() bool {
	if !s.checkOpen() {
		return false
	}
	if s.setop == nil {
		s.key, s.val, s.err = s.cur.Get(nil, nil, s.op)
	} else {
		s.key, s.val, s.err = s.cur.Get(s.setkey, s.setval, *s.setop)
		s.setkey = nil
		s.setval = nil
		s.setop = nil
	}
	return s.err == nil
}

func (s *Scanner) checkOpen() bool {
	if s.cur != nil {
		return true
	}
	if s.err == nil {
		s.err = errClosed
	}
	return false
}

// Err returns a non-nil error if and only if the previous call to s.Scan()
// resulted in an error other than lmdb.ErrNotFound.
func (s *Scanner) Err() error {
	if lmdb.IsNotFound(s.err) {
		return nil
	}
	return s.err
}

// Close closes the cursor underlying s and clears its ows internal structures.
// Close does not attempt to terminate the enclosing transaction.
//
// Scan must not be called after Close.
func (s *Scanner) Close() {
	if s.cur != nil {
		s.cur.Close()
		s.cur = nil
	}
}
<|endoftext|>


<commit_before>package plastic

import (
	"bitbucket.org/oakmoundstudio/plasticpiston/plastic/collision"
	"bitbucket.org/oakmoundstudio/plasticpiston/plastic/event"
	"bitbucket.org/oakmoundstudio/plasticpiston/plastic/render"
	"fmt"
	"image"
	"image/color"
	"log"
	"time"

	"golang.org/x/exp/shiny/driver"
	"golang.org/x/exp/shiny/screen"
	"golang.org/x/mobile/event/key"
	"golang.org/x/mobile/event/lifecycle"
	"golang.org/x/mobile/event/mouse"
	"golang.org/x/mobile/event/paint"
	"golang.org/x/mobile/event/size"
)

var (
	initCh       = make(chan bool)
	sceneCh      = make(chan bool)
	quitCh       = make(chan bool)
	screenWidth  = 640
	screenHeight = 480
	press        = key.DirPress
	release      = key.DirRelease
	runEventLoop = false
	black        = color.RGBA{0x00, 0x00, 0x00, 0xff}
	b            screen.Buffer
)

func Init(scene string) {
	collision.Init()

	go driver.Main(eventLoop)

	prevScene := ""
	sceneMap[scene].active = true
	<-initCh
	close(initCh)
	for {
		sceneMap[scene].start(prevScene)
		cont := true
		runEventLoop = true
		for cont {
			select {
			case <-quitCh:
				return

			case <-sceneCh:
				cont = sceneMap[scene].loop()
			}
		}
		runEventLoop = false
		prevScene = scene
		scene = sceneMap[scene].end()
	}
}

func eventLoop(s screen.Screen) {
	b, _ = s.NewBuffer(image.Point{screenWidth, screenHeight})
	w, err := s.NewWindow(&screen.NewWindowOptions{screenWidth, screenHeight})
	if err != nil {
		log.Fatal(err)
	}
	defer w.Release()

	render.SetScreen((&s))

	frameRate := 60
	frameCh := make(chan bool, 100)

	go func(frameCh chan bool, frameRate int64) {
		c := time.Tick(time.Second / time.Duration(frameRate))
		for range c {
			frameCh <- true
		}
	}(frameCh, int64(frameRate))

	eb := event.GetEventBus()

	go func(eb event.EventBus, w screen.Window) {
		for {
			for runEventLoop {

				<-frameCh

				eb.Trigger("EnterFrame", nil)

				sceneCh <- true

				// To satisfy pc master race,
				// could pull this out into another
				// channel which happens as fast as possible
				// fillScreen(w, black)
				eb.Trigger("Draw", b)

				w.Upload(image.Point{0, 0}, b, b.Bounds())
				// x := w.Publish()
				// fmt.Println(x)

				eb.Trigger("ExitFrame", nil)
			}
		}
	}(eb, w)

	initCh <- true

	for {
		// Handle window events
		e := w.NextEvent()
		// This print message is to help programmers learn what events this
		// example program generates. A real program shouldn't print such
		// messages; they're not important to end users.
		format := "got %#v\n"
		if _, ok := e.(fmt.Stringer); ok {
			format = "got %v\n"
		}
		fmt.Printf(format, e)

		switch e := e.(type) {

		case lifecycle.Event:
			if e.To == lifecycle.StageDead {
				quitCh <- true
				return
			}

		case key.Event:
			if e.Direction == press {
				fmt.Println("--------------------", e.Code.String()[4:])
				SetDown(e.Code.String()[4:])
			} else if e.Direction == release {
				SetUp(e.Code.String()[4:])
			}

		case mouse.Event:

		case paint.Event:

		case size.Event:

		case error:
			log.Print(e)
		}
	}
}

func fillScreen(w screen.Window, c color.RGBA) {
	w.Fill(b.Bounds(), black, screen.Src)
}
<commit_msg>Quitting with ESC now supported. Many print statements are now controlled by local debug vars. Mediocre connection alg in place that doesnt overwrite rooms.<commit_after>package plastic

import (
	"bitbucket.org/oakmoundstudio/plasticpiston/plastic/collision"
	"bitbucket.org/oakmoundstudio/plasticpiston/plastic/event"
	"bitbucket.org/oakmoundstudio/plasticpiston/plastic/render"
	"fmt"
	"image"
	"image/color"
	"log"
	"time"

	"golang.org/x/exp/shiny/driver"
	"golang.org/x/exp/shiny/screen"
	"golang.org/x/mobile/event/key"
	"golang.org/x/mobile/event/lifecycle"
	"golang.org/x/mobile/event/mouse"
	"golang.org/x/mobile/event/paint"
	"golang.org/x/mobile/event/size"
)

var (
	initCh       = make(chan bool)
	sceneCh      = make(chan bool)
	quitCh       = make(chan bool)
	screenWidth  = 640
	screenHeight = 480
	press        = key.DirPress
	release      = key.DirRelease
	runEventLoop = false
	black        = color.RGBA{0x00, 0x00, 0x00, 0xff}
	b            screen.Buffer
	esc          = false
	l_debug      = false
)

func Init(scene string) {
	collision.Init()

	go driver.Main(eventLoop)

	prevScene := ""
	sceneMap[scene].active = true
	<-initCh
	close(initCh)
	for {
		sceneMap[scene].start(prevScene)
		cont := true
		runEventLoop = true
		for cont {
			select {
			case <-quitCh:
				return

			case <-sceneCh:
				cont = sceneMap[scene].loop()
			}
		}
		runEventLoop = false
		prevScene = scene
		scene = sceneMap[scene].end()
	}
}

func eventLoop(s screen.Screen) {
	b, _ = s.NewBuffer(image.Point{screenWidth, screenHeight})
	w, err := s.NewWindow(&screen.NewWindowOptions{screenWidth, screenHeight})
	if err != nil {
		log.Fatal(err)
	}
	defer w.Release()

	render.SetScreen((&s))

	frameRate := 60
	frameCh := make(chan bool, 100)

	go func(frameCh chan bool, frameRate int64) {
		c := time.Tick(time.Second / time.Duration(frameRate))
		for range c {
			frameCh <- true
		}
	}(frameCh, int64(frameRate))

	eb := event.GetEventBus()

	go func(eb event.EventBus, w screen.Window) {
		for {
			for runEventLoop {

				<-frameCh

				eb.Trigger("EnterFrame", nil)

				sceneCh <- true

				// To satisfy pc master race,
				// could pull this out into another
				// channel which happens as fast as possible
				// fillScreen(w, black)
				eb.Trigger("Draw", b)

				w.Upload(image.Point{0, 0}, b, b.Bounds())
				// x := w.Publish()
				// fmt.Println(x)

				eb.Trigger("ExitFrame", nil)
			}
		}
	}(eb, w)

	initCh <- true

	for {
		// Handle window events
		e := w.NextEvent()
		// This print message is to help programmers learn what events this
		// example program generates. A real program shouldn't print such
		// messages; they're not important to end users.
		format := "got %#v\n"
		if _, ok := e.(fmt.Stringer); ok {
			format = "got %v\n"
		}
		if l_debug {
			fmt.Printf(format, e)
		}
		switch e := e.(type) {

		case lifecycle.Event:
			if e.To == lifecycle.StageDead {
				quitCh <- true
				return
			}

		case key.Event:
			if e.Direction == press {
				fmt.Println("--------------------", e.Code.String()[4:])
				SetDown(e.Code.String()[4:])
			} else if e.Direction == release {
				SetUp(e.Code.String()[4:])
			}

		case mouse.Event:

		case paint.Event:

		case size.Event:

		case error:
			log.Print(e)
		}
		if IsDown("Escape") {
			if esc {
				fmt.Println("\n\n~~~~~~~~~~~~Now Escaping~~~~~~~~~~~~~~\n\n\n")
				ev := lifecycle.Event{0, 0, nil}
				w.Send(ev)
			}
			esc = true
		} else {
			esc = false
		}
	}
}

func fillScreen(w screen.Window, c color.RGBA) {
	w.Fill(b.Bounds(), black, screen.Src)
}
<|endoftext|>


<commit_before>package tachyon

import (
	"errors"
	"fmt"
	"github.com/flynn/go-shlex"
	"os"
	"path"
	"path/filepath"
)

type VarsFiles []interface{}

type Notifications []string

type TaskData map[string]interface{}

type Play struct {
	Hosts      string
	Connection string
	Vars       Scope
	VarsFiles  VarsFiles
	Tasks      Tasks
	Handlers   Tasks
	baseDir    string
}

type Playbook struct {
	Path    string
	baseDir string
	Plays   []*Play
	Env     *Environment
	Vars    *NestedScope
}

func NewPlaybook(env *Environment, p string) (*Playbook, error) {
	baseDir, err := filepath.Abs(filepath.Dir(p))
	if err != nil {
		return nil, err
	}

	pb := &Playbook{
		Path:    p,
		baseDir: baseDir,
		Env:     env,
		Vars:    NewNestedScope(env.Vars),
	}

	pb.Vars.Set("playbook_dir", baseDir)

	plays, err := pb.LoadPlays(p, pb.Vars)
	if err != nil {
		return nil, err
	}

	pb.Plays = plays

	return pb, nil
}

func processTasks(datas []TaskData) Tasks {
	tasks := make(Tasks, len(datas))

	for idx, data := range datas {
		task := &Task{data: data}
		task.Init()

		tasks[idx] = task
	}

	return tasks
}

var eInvalidPlaybook = errors.New("Invalid playbook yaml")

func (pb *Playbook) LoadPlays(fpath string, s Scope) ([]*Play, error) {
	var seq []map[string]interface{}

	var plays []*Play

	err := yamlFile(fpath, &seq)

	if err != nil {
		return nil, err
	}

	for _, item := range seq {
		if x, ok := item["include"]; ok {
			spath, ok := x.(string)

			if !ok {
				return nil, eInvalidPlaybook
			}

			// Make a new scope and put the vars into it. The subplays
			// will use this scope as their parent.
			ns := NewNestedScope(s)

			if vars, ok := item["vars"]; ok {
				ns.addVars(vars)
			}

			parts, err := shlex.Split(spath)
			if err == nil {
				spath = parts[0]
				for _, tok := range parts[1:] {
					if k, v, ok := split2(tok, "="); ok {
						ns.Set(k, inferString(v))
					}
				}
			}

			sub, err := pb.LoadPlays(path.Join(pb.baseDir, spath), ns.Flatten())

			if err != nil {
				return nil, err
			}

			if !ns.Empty() {
				for _, play := range sub {
					play.Vars = SpliceOverrides(play.Vars, ns)
				}
			}

			plays = append(plays, sub...)
		} else {
			play, err := parsePlay(s, pb.baseDir, item)

			if err != nil {
				return nil, err
			}

			plays = append(plays, play)
		}
	}

	return plays, nil
}

func formatError(where string) error {
	return fmt.Errorf("Invalid playbook yaml: %s", where)
}

func (p *Play) castTasks(s Scope, x interface{}) ([]TaskData, error) {
	xs, ok := x.([]interface{})
	if !ok {
		return nil, formatError("tasks not the right format")
	}

	var tds []TaskData

	for _, x := range xs {
		if am, ok := x.(map[interface{}]interface{}); ok {
			if _, ok := am["include"]; ok {
				tasks, err := p.loadTasksFile(s, am)
				if err != nil {
					return nil, err
				}

				tds = append(tds, tasks...)
			} else {
				td := make(TaskData)

				for k, v := range am {
					if sk, ok := k.(string); ok {
						td[sk] = v
					} else {
						return nil, formatError("non-string key in task")
					}
				}

				tds = append(tds, td)
			}
		} else {
			return nil, formatError("task was not a map")
		}
	}

	return tds, nil
}

func (p *Play) loadTasksFile(s Scope, am map[interface{}]interface{}) ([]TaskData, error) {
	path, ok := am["include"].(string)
	if !ok {
		return nil, formatError("include was not a string")
	}

	path, err := ExpandVars(s, path)
	if err != nil {
		return nil, err
	}

	var tds []TaskData

	err = yamlFile(p.path(path), &tds)

	return tds, err
}

func parsePlay(s Scope, dir string, m map[string]interface{}) (*Play, error) {
	var play Play

	if x, ok := m["hosts"]; ok {
		if str, ok := x.(string); ok {
			play.Hosts = str
		} else {
			return nil, formatError("hosts not a string")
		}
	} else {
		return nil, formatError("hosts missing")
	}

	play.Vars = NewNestedScope(s)

	if x, ok := m["vars"]; ok {
		if im, ok := x.(map[interface{}]interface{}); ok {
			for ik, iv := range im {
				if sk, ok := ik.(string); ok {
					play.Vars.Set(sk, iv)
				} else {
					return nil, formatError("vars key not a string")
				}
			}
		} else {
			return nil, formatError("vars not a map")
		}
	}

	if x, ok := m["vars_files"]; ok {
		if vf, ok := x.([]interface{}); ok {
			play.VarsFiles = vf
		} else {
			return nil, formatError("vars_files not the right format")
		}
	}

	play.baseDir = dir

	for _, file := range play.VarsFiles {
		switch file := file.(type) {
		case string:
			ImportVarsFile(play.Vars, play.path(file))
			break
		case []interface{}:
			for _, ent := range file {
				exp, err := ExpandVars(play.Vars, ent.(string))

				if err != nil {
					continue
				}

				epath := play.path(exp)

				if _, err := os.Stat(epath); err == nil {
					err = ImportVarsFile(play.Vars, epath)

					if err != nil {
						return nil, err
					}

					break
				}
			}
		}
	}

	var tasks []TaskData

	if x, ok := m["tasks"]; ok {
		tds, err := play.castTasks(s, x)

		if err != nil {
			return nil, err
		}

		tasks = tds
	}

	var handlers []TaskData

	if x, ok := m["handlers"]; ok {
		tds, err := play.castTasks(s, x)

		if err != nil {
			return nil, err
		}

		handlers = tds
	}

	play.Tasks = processTasks(tasks)
	play.Handlers = processTasks(handlers)

	return &play, nil
}

func (play *Play) path(file string) string {
	return path.Join(play.baseDir, file)
}

func boolify(str string) bool {
	switch str {
	case "", "false", "no":
		return false
	default:
		return true
	}
}
<commit_msg>Cleanup play parsing<commit_after>package tachyon

import (
	"errors"
	"fmt"
	"github.com/flynn/go-shlex"
	"os"
	"path"
	"path/filepath"
)

type VarsFiles []interface{}

type Notifications []string

type TaskData map[string]interface{}

type Play struct {
	Hosts      string
	Connection string
	Vars       Scope
	VarsFiles  VarsFiles
	Tasks      Tasks
	Handlers   Tasks
	baseDir    string
}

type Playbook struct {
	Path    string
	baseDir string
	Plays   []*Play
	Env     *Environment
	Vars    *NestedScope
}

func NewPlaybook(env *Environment, p string) (*Playbook, error) {
	baseDir, err := filepath.Abs(filepath.Dir(p))
	if err != nil {
		return nil, err
	}

	pb := &Playbook{
		Path:    p,
		baseDir: baseDir,
		Env:     env,
		Vars:    NewNestedScope(env.Vars),
	}

	pb.Vars.Set("playbook_dir", baseDir)

	plays, err := pb.LoadPlays(p, pb.Vars)
	if err != nil {
		return nil, err
	}

	pb.Plays = plays

	return pb, nil
}

func processTasks(datas []TaskData) Tasks {
	tasks := make(Tasks, len(datas))

	for idx, data := range datas {
		task := &Task{data: data}
		task.Init()

		tasks[idx] = task
	}

	return tasks
}

type playData struct {
	Include    string
	Vars       strmap
	Hosts      string
	Vars_files []interface{}
	Tasks      []TaskData
	Handlers   []TaskData
}

var eInvalidPlaybook = errors.New("Invalid playbook yaml")

func (pb *Playbook) LoadPlays(fpath string, s Scope) ([]*Play, error) {
	var seq []playData

	var plays []*Play

	err := yamlFile(fpath, &seq)

	if err != nil {
		return nil, err
	}

	for _, item := range seq {
		if item.Include != "" {
			spath := item.Include

			// Make a new scope and put the vars into it. The subplays
			// will use this scope as their parent.
			ns := NewNestedScope(s)

			if item.Vars != nil {
				ns.addVars(item.Vars)
			}

			parts, err := shlex.Split(spath)
			if err == nil {
				spath = parts[0]
				for _, tok := range parts[1:] {
					if k, v, ok := split2(tok, "="); ok {
						ns.Set(k, inferString(v))
					}
				}
			}

			sub, err := pb.LoadPlays(path.Join(pb.baseDir, spath), ns.Flatten())

			if err != nil {
				return nil, err
			}

			if !ns.Empty() {
				for _, play := range sub {
					play.Vars = SpliceOverrides(play.Vars, ns)
				}
			}

			plays = append(plays, sub...)
		} else {
			play, err := parsePlay(s, pb.baseDir, &item)

			if err != nil {
				return nil, err
			}

			plays = append(plays, play)
		}
	}

	return plays, nil
}

func formatError(where string) error {
	return fmt.Errorf("Invalid playbook yaml: %s", where)
}

func (p *Play) castTasks(s Scope, t []TaskData) ([]TaskData, error) {
	var tds []TaskData

	for _, x := range t {
		if _, ok := x["include"]; ok {
			tasks, err := p.loadTasksFile(s, x)
			if err != nil {
				return nil, err
			}

			tds = append(tds, tasks...)
		} else {
			tds = append(tds, x)
		}
	}

	return tds, nil
}

func (p *Play) loadTasksFile(s Scope, td TaskData) ([]TaskData, error) {
	path, ok := td["include"].(string)
	if !ok {
		return nil, formatError("include was not a string")
	}

	path, err := ExpandVars(s, path)
	if err != nil {
		return nil, err
	}

	var tds []TaskData

	err = yamlFile(p.path(path), &tds)

	return tds, err
}

func parsePlay(s Scope, dir string, m *playData) (*Play, error) {
	var play Play

	if m.Hosts == "" {
		return nil, formatError("hosts missing")
	}

	play.Hosts = m.Hosts
	play.Vars = NewNestedScope(s)

	for sk, iv := range m.Vars {
		play.Vars.Set(sk, iv)
	}

	play.VarsFiles = m.Vars_files
	play.baseDir = dir

	for _, file := range play.VarsFiles {
		switch file := file.(type) {
		case string:
			ImportVarsFile(play.Vars, play.path(file))
			break
		case []interface{}:
			for _, ent := range file {
				exp, err := ExpandVars(play.Vars, ent.(string))

				if err != nil {
					continue
				}

				epath := play.path(exp)

				if _, err := os.Stat(epath); err == nil {
					err = ImportVarsFile(play.Vars, epath)

					if err != nil {
						return nil, err
					}

					break
				}
			}
		}
	}

	var tasks []TaskData
	if len(m.Tasks) > 0 {
		tds, err := play.castTasks(s, m.Tasks)

		if err != nil {
			return nil, err
		}

		tasks = tds
	}

	var handlers []TaskData

	if len(m.Handlers) > 0 {
		tds, err := play.castTasks(s, m.Handlers)

		if err != nil {
			return nil, err
		}

		handlers = tds
	}

	play.Tasks = processTasks(tasks)
	play.Handlers = processTasks(handlers)

	return &play, nil
}

func (play *Play) path(file string) string {
	return path.Join(play.baseDir, file)
}

func boolify(str string) bool {
	switch str {
	case "", "false", "no":
		return false
	default:
		return true
	}
}
<|endoftext|>


<commit_before>package client

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

	"github.com/cozy/cozy-stack/client/request"
)

// Instance is a struct holding the representation of an instance on the API.
type Instance struct {
	ID    string `json:"id"`
	Rev   string `json:"rev"`
	Attrs struct {
		Domain               string    `json:"domain"`
		Locale               string    `json:"locale"`
		Dev                  bool      `json:"dev"`
		OnboardingFinished   bool      `json:"onboarding_finished"`
		BytesDiskQuota       int64     `json:"disk_quota,string,omitempty"`
		IndexViewsVersion    int       `json:"indexes_version"`
		PassphraseResetToken []byte    `json:"passphrase_reset_token"`
		PassphraseResetTime  time.Time `json:"passphrase_reset_time"`
		RegisterToken        []byte    `json:"register_token,omitempty"`
	} `json:"attributes"`
}

// InstanceOptions contains the options passed on instance creation.
type InstanceOptions struct {
	Domain             string
	Locale             string
	Timezone           string
	Email              string
	PublicName         string
	Settings           string
	DiskQuota          *int64
	Apps               []string
	Dev                bool
	Passphrase         string
	Debug              *bool
	OnboardingFinished *bool
}

// TokenOptions is a struct holding all the options to generate a token.
type TokenOptions struct {
	Domain   string
	Subject  string
	Audience string
	Scope    []string
	Expire   time.Duration
}

// OAuthClientOptions is a struct holding all the options to generate an OAuth
// client associated to an instance.
type OAuthClientOptions struct {
	Domain      string
	RedirectURI string
	ClientName  string
	SoftwareID  string
}

// UpdatesOptions is a struct holding all the options to launch an update.
type UpdatesOptions struct {
	Domain string
	Slugs  []string
}

// ImportOptions is a struct with the options for importing a tarball.
type ImportOptions struct {
	Filename    string
	Destination string
}

// GetInstance returns the instance associated with the specified domain.
func (c *Client) GetInstance(domain string) (*Instance, error) {
	res, err := c.Req(&request.Options{
		Method: "GET",
		Path:   "/instances/" + domain,
	})
	if err != nil {
		return nil, err
	}
	return readInstance(res)
}

// CreateInstance is used to create a new cozy instance of the specified domain
// and locale.
func (c *Client) CreateInstance(opts *InstanceOptions) (*Instance, error) {
	if !validDomain(opts.Domain) {
		return nil, fmt.Errorf("Invalid domain: %s", opts.Domain)
	}
	q := url.Values{
		"Domain":     {opts.Domain},
		"Locale":     {opts.Locale},
		"Timezone":   {opts.Timezone},
		"Email":      {opts.Email},
		"PublicName": {opts.PublicName},
		"Settings":   {opts.Settings},
		"Apps":       {strings.Join(opts.Apps, ",")},
		"Dev":        {strconv.FormatBool(opts.Dev)},
		"Passphrase": {opts.Passphrase},
	}
	if opts.DiskQuota != nil {
		q.Add("DiskQuota", strconv.FormatInt(*opts.DiskQuota, 10))
	}
	res, err := c.Req(&request.Options{
		Method:  "POST",
		Path:    "/instances",
		Queries: q,
	})
	if err != nil {
		return nil, err
	}
	return readInstance(res)
}

// ListInstances returns the list of instances recorded on the stack.
func (c *Client) ListInstances() ([]*Instance, error) {
	res, err := c.Req(&request.Options{
		Method: "GET",
		Path:   "/instances",
	})
	if err != nil {
		return nil, err
	}
	var list []*Instance
	if err = readJSONAPI(res.Body, &list); err != nil {
		return nil, err
	}
	return list, nil
}

// ModifyInstance is used to update an instance.
func (c *Client) ModifyInstance(domain string, opts *InstanceOptions) (*Instance, error) {
	if !validDomain(domain) {
		return nil, fmt.Errorf("Invalid domain: %s", domain)
	}
	q := url.Values{
		"Locale": {opts.Locale},
	}
	if opts.Debug != nil {
		q.Add("Debug", strconv.FormatBool(*opts.Debug))
	}
	if opts.OnboardingFinished != nil {
		q.Add("OnboardingFinished", strconv.FormatBool(*opts.OnboardingFinished))
	}
	if opts.DiskQuota != nil {
		q.Add("DiskQuota", strconv.FormatInt(*opts.DiskQuota, 10))
	}
	res, err := c.Req(&request.Options{
		Method:  "PATCH",
		Path:    "/instances/" + domain,
		Queries: q,
	})
	if err != nil {
		return nil, err
	}
	return readInstance(res)
}

// DestroyInstance is used to delete an instance and all its data.
func (c *Client) DestroyInstance(domain string) error {
	if !validDomain(domain) {
		return fmt.Errorf("Invalid domain: %s", domain)
	}
	_, err := c.Req(&request.Options{
		Method:     "DELETE",
		Path:       "/instances/" + domain,
		NoResponse: true,
	})
	return err
}

// FsckInstance returns the list of the inconsistencies in the VFS.
func (c *Client) FsckInstance(domain string) ([]map[string]interface{}, error) {
	if !validDomain(domain) {
		return nil, fmt.Errorf("Invalid domain: %s", domain)
	}
	res, err := c.Req(&request.Options{
		Method: "GET",
		Path:   "/instances/" + domain + "/fsck",
	})
	if err != nil {
		return nil, err
	}
	var list []map[string]interface{}
	if err = json.NewDecoder(res.Body).Decode(&list); err != nil {
		return nil, err
	}
	return list, nil
}

// GetToken is used to generate a toke with the specified options.
func (c *Client) GetToken(opts *TokenOptions) (string, error) {
	q := url.Values{
		"Domain":   {opts.Domain},
		"Subject":  {opts.Subject},
		"Audience": {opts.Audience},
		"Scope":    {strings.Join(opts.Scope, " ")},
		"Expire":   {opts.Expire.String()},
	}
	res, err := c.Req(&request.Options{
		Method:  "POST",
		Path:    "/instances/token",
		Queries: q,
	})
	if err != nil {
		return "", err
	}
	defer res.Body.Close()
	b, err := ioutil.ReadAll(res.Body)
	if err != nil {
		return "", err
	}
	return string(b), nil
}

// RegisterOAuthClient register a new OAuth client associated to the specified
// instance.
func (c *Client) RegisterOAuthClient(opts *OAuthClientOptions) (map[string]interface{}, error) {
	q := url.Values{
		"Domain":      {opts.Domain},
		"RedirectURI": {opts.RedirectURI},
		"ClientName":  {opts.ClientName},
		"SoftwareID":  {opts.SoftwareID},
	}
	res, err := c.Req(&request.Options{
		Method:  "POST",
		Path:    "/instances/oauth_client",
		Queries: q,
	})
	if err != nil {
		return nil, err
	}
	defer res.Body.Close()
	var client map[string]interface{}
	if err = json.NewDecoder(res.Body).Decode(&client); err != nil {
		return nil, err
	}
	return client, nil
}

// Updates launch the updating process of the applications. When no Domain is
// specified, the updates are launched for all the existing instances.
func (c *Client) Updates(opts *UpdatesOptions) error {
	q := url.Values{
		"Domain": {opts.Domain},
		"Slugs":  {strings.Join(opts.Slugs, ",")},
	}
	_, err := c.Req(&request.Options{
		Method:     "POST",
		Path:       "/instances/updates",
		Queries:    q,
		NoResponse: true,
	})
	return err
}

// Export launch the creation of a tarball to export data from an instance.
func (c *Client) Export(domain string) error {
	if !validDomain(domain) {
		return fmt.Errorf("Invalid domain: %s", domain)
	}
	_, err := c.Req(&request.Options{
		Method:     "POST",
		Path:       "/instances/" + domain + "/export",
		NoResponse: true,
	})
	return err
}

// Import launch the import of a tarball with data to put in an instance.
func (c *Client) Import(domain string, opts *ImportOptions) error {
	if !validDomain(domain) {
		return fmt.Errorf("Invalid domain: %s", domain)
	}
	q := url.Values{
		"Filename":    {opts.Filename},
		"Destination": {opts.Destination},
	}
	_, err := c.Req(&request.Options{
		Method:     "POST",
		Path:       "/instances/" + domain + "/import",
		Queries:    q,
		NoResponse: true,
	})
	return err
}

// RebuildRedis puts the triggers in redis.
func (c *Client) RebuildRedis() error {
	_, err := c.Req(&request.Options{
		Method:     "POST",
		Path:       "/instances/redis",
		NoResponse: true,
	})
	return err
}

func readInstance(res *http.Response) (*Instance, error) {
	in := &Instance{}
	if err := readJSONAPI(res.Body, &in); err != nil {
		return nil, err
	}
	return in, nil
}

func validDomain(domain string) bool {
	return !strings.ContainsAny(domain, " /?#@\t\r\n")
}
<commit_msg>Fix a typo for importing tarballs<commit_after>package client

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

	"github.com/cozy/cozy-stack/client/request"
)

// Instance is a struct holding the representation of an instance on the API.
type Instance struct {
	ID    string `json:"id"`
	Rev   string `json:"rev"`
	Attrs struct {
		Domain               string    `json:"domain"`
		Locale               string    `json:"locale"`
		Dev                  bool      `json:"dev"`
		OnboardingFinished   bool      `json:"onboarding_finished"`
		BytesDiskQuota       int64     `json:"disk_quota,string,omitempty"`
		IndexViewsVersion    int       `json:"indexes_version"`
		PassphraseResetToken []byte    `json:"passphrase_reset_token"`
		PassphraseResetTime  time.Time `json:"passphrase_reset_time"`
		RegisterToken        []byte    `json:"register_token,omitempty"`
	} `json:"attributes"`
}

// InstanceOptions contains the options passed on instance creation.
type InstanceOptions struct {
	Domain             string
	Locale             string
	Timezone           string
	Email              string
	PublicName         string
	Settings           string
	DiskQuota          *int64
	Apps               []string
	Dev                bool
	Passphrase         string
	Debug              *bool
	OnboardingFinished *bool
}

// TokenOptions is a struct holding all the options to generate a token.
type TokenOptions struct {
	Domain   string
	Subject  string
	Audience string
	Scope    []string
	Expire   time.Duration
}

// OAuthClientOptions is a struct holding all the options to generate an OAuth
// client associated to an instance.
type OAuthClientOptions struct {
	Domain      string
	RedirectURI string
	ClientName  string
	SoftwareID  string
}

// UpdatesOptions is a struct holding all the options to launch an update.
type UpdatesOptions struct {
	Domain string
	Slugs  []string
}

// ImportOptions is a struct with the options for importing a tarball.
type ImportOptions struct {
	Filename    string
	Destination string
}

// GetInstance returns the instance associated with the specified domain.
func (c *Client) GetInstance(domain string) (*Instance, error) {
	res, err := c.Req(&request.Options{
		Method: "GET",
		Path:   "/instances/" + domain,
	})
	if err != nil {
		return nil, err
	}
	return readInstance(res)
}

// CreateInstance is used to create a new cozy instance of the specified domain
// and locale.
func (c *Client) CreateInstance(opts *InstanceOptions) (*Instance, error) {
	if !validDomain(opts.Domain) {
		return nil, fmt.Errorf("Invalid domain: %s", opts.Domain)
	}
	q := url.Values{
		"Domain":     {opts.Domain},
		"Locale":     {opts.Locale},
		"Timezone":   {opts.Timezone},
		"Email":      {opts.Email},
		"PublicName": {opts.PublicName},
		"Settings":   {opts.Settings},
		"Apps":       {strings.Join(opts.Apps, ",")},
		"Dev":        {strconv.FormatBool(opts.Dev)},
		"Passphrase": {opts.Passphrase},
	}
	if opts.DiskQuota != nil {
		q.Add("DiskQuota", strconv.FormatInt(*opts.DiskQuota, 10))
	}
	res, err := c.Req(&request.Options{
		Method:  "POST",
		Path:    "/instances",
		Queries: q,
	})
	if err != nil {
		return nil, err
	}
	return readInstance(res)
}

// ListInstances returns the list of instances recorded on the stack.
func (c *Client) ListInstances() ([]*Instance, error) {
	res, err := c.Req(&request.Options{
		Method: "GET",
		Path:   "/instances",
	})
	if err != nil {
		return nil, err
	}
	var list []*Instance
	if err = readJSONAPI(res.Body, &list); err != nil {
		return nil, err
	}
	return list, nil
}

// ModifyInstance is used to update an instance.
func (c *Client) ModifyInstance(domain string, opts *InstanceOptions) (*Instance, error) {
	if !validDomain(domain) {
		return nil, fmt.Errorf("Invalid domain: %s", domain)
	}
	q := url.Values{
		"Locale": {opts.Locale},
	}
	if opts.Debug != nil {
		q.Add("Debug", strconv.FormatBool(*opts.Debug))
	}
	if opts.OnboardingFinished != nil {
		q.Add("OnboardingFinished", strconv.FormatBool(*opts.OnboardingFinished))
	}
	if opts.DiskQuota != nil {
		q.Add("DiskQuota", strconv.FormatInt(*opts.DiskQuota, 10))
	}
	res, err := c.Req(&request.Options{
		Method:  "PATCH",
		Path:    "/instances/" + domain,
		Queries: q,
	})
	if err != nil {
		return nil, err
	}
	return readInstance(res)
}

// DestroyInstance is used to delete an instance and all its data.
func (c *Client) DestroyInstance(domain string) error {
	if !validDomain(domain) {
		return fmt.Errorf("Invalid domain: %s", domain)
	}
	_, err := c.Req(&request.Options{
		Method:     "DELETE",
		Path:       "/instances/" + domain,
		NoResponse: true,
	})
	return err
}

// FsckInstance returns the list of the inconsistencies in the VFS.
func (c *Client) FsckInstance(domain string) ([]map[string]interface{}, error) {
	if !validDomain(domain) {
		return nil, fmt.Errorf("Invalid domain: %s", domain)
	}
	res, err := c.Req(&request.Options{
		Method: "GET",
		Path:   "/instances/" + domain + "/fsck",
	})
	if err != nil {
		return nil, err
	}
	var list []map[string]interface{}
	if err = json.NewDecoder(res.Body).Decode(&list); err != nil {
		return nil, err
	}
	return list, nil
}

// GetToken is used to generate a toke with the specified options.
func (c *Client) GetToken(opts *TokenOptions) (string, error) {
	q := url.Values{
		"Domain":   {opts.Domain},
		"Subject":  {opts.Subject},
		"Audience": {opts.Audience},
		"Scope":    {strings.Join(opts.Scope, " ")},
		"Expire":   {opts.Expire.String()},
	}
	res, err := c.Req(&request.Options{
		Method:  "POST",
		Path:    "/instances/token",
		Queries: q,
	})
	if err != nil {
		return "", err
	}
	defer res.Body.Close()
	b, err := ioutil.ReadAll(res.Body)
	if err != nil {
		return "", err
	}
	return string(b), nil
}

// RegisterOAuthClient register a new OAuth client associated to the specified
// instance.
func (c *Client) RegisterOAuthClient(opts *OAuthClientOptions) (map[string]interface{}, error) {
	q := url.Values{
		"Domain":      {opts.Domain},
		"RedirectURI": {opts.RedirectURI},
		"ClientName":  {opts.ClientName},
		"SoftwareID":  {opts.SoftwareID},
	}
	res, err := c.Req(&request.Options{
		Method:  "POST",
		Path:    "/instances/oauth_client",
		Queries: q,
	})
	if err != nil {
		return nil, err
	}
	defer res.Body.Close()
	var client map[string]interface{}
	if err = json.NewDecoder(res.Body).Decode(&client); err != nil {
		return nil, err
	}
	return client, nil
}

// Updates launch the updating process of the applications. When no Domain is
// specified, the updates are launched for all the existing instances.
func (c *Client) Updates(opts *UpdatesOptions) error {
	q := url.Values{
		"Domain": {opts.Domain},
		"Slugs":  {strings.Join(opts.Slugs, ",")},
	}
	_, err := c.Req(&request.Options{
		Method:     "POST",
		Path:       "/instances/updates",
		Queries:    q,
		NoResponse: true,
	})
	return err
}

// Export launch the creation of a tarball to export data from an instance.
func (c *Client) Export(domain string) error {
	if !validDomain(domain) {
		return fmt.Errorf("Invalid domain: %s", domain)
	}
	_, err := c.Req(&request.Options{
		Method:     "POST",
		Path:       "/instances/" + domain + "/export",
		NoResponse: true,
	})
	return err
}

// Import launch the import of a tarball with data to put in an instance.
func (c *Client) Import(domain string, opts *ImportOptions) error {
	if !validDomain(domain) {
		return fmt.Errorf("Invalid domain: %s", domain)
	}
	q := url.Values{
		"filename":    {opts.Filename},
		"destination": {opts.Destination},
	}
	_, err := c.Req(&request.Options{
		Method:     "POST",
		Path:       "/instances/" + domain + "/import",
		Queries:    q,
		NoResponse: true,
	})
	return err
}

// RebuildRedis puts the triggers in redis.
func (c *Client) RebuildRedis() error {
	_, err := c.Req(&request.Options{
		Method:     "POST",
		Path:       "/instances/redis",
		NoResponse: true,
	})
	return err
}

func readInstance(res *http.Response) (*Instance, error) {
	in := &Instance{}
	if err := readJSONAPI(res.Body, &in); err != nil {
		return nil, err
	}
	return in, nil
}

func validDomain(domain string) bool {
	return !strings.ContainsAny(domain, " /?#@\t\r\n")
}
<|endoftext|>


<commit_before>package server

import (
	"bytes"
	"compress/bzip2"
	"crypto/sha256"
	"fmt"
	"io"
	"net/http"
	"os"
	"path"
	"strconv"
	"time"
)

const (
	assetsDirectory = "assets/"
	// Downloading all assets from GitHub can be very slow and easily exceed
	// the 10 min time limit imposed by CI
	envSkipDownload = "SKIP_DOWNLOAD_FOR_TEST"
)

func init() {
	err := os.MkdirAll(assetsDirectory, os.ModeDir|0700)
	if err != nil {
		log.Fatalf("Could not create directory for storing assets: %q", err)
	}
}

// downloadAsset downloads the body of the given URL and stores it into
// $ASSETS_DIRECTORY/$BASENAME.SHA256_SUM($URL)
func downloadAsset(uri string) (localfile string, err error) {
	basename := path.Base(uri)
	fileExt := path.Ext(basename)

	// The sha256 hash uses 64 chars, we'll append this hash to the name. The name
	// doesn't matter that much so we'll just use 60 chars from it.
	if len(basename) > 60 {
		basename = basename[:60]
	}

	localfile = assetsDirectory + fmt.Sprintf("%s.%x", basename, sha256.Sum256([]byte(uri)))

	if !fileExists(localfile) {
		var body io.Reader = bytes.NewBufferString("some content for test")
		if skip, _ := strconv.ParseBool(os.Getenv(envSkipDownload)); skip {
			log.Debugf("Skip downloading %v in tests", uri)
		} else {
			var res *http.Response

			c := http.Client{Timeout: time.Second * 30}
			if res, err = c.Get(uri); err != nil {
				return "", err
			}
			defer res.Body.Close()

			if res.StatusCode != http.StatusOK {
				return "", fmt.Errorf("Expecting 200 OK, got: %s", res.Status)
			}

			if fileExt == ".bz2" {
				body = bzip2.NewReader(res.Body)
			} else {
				body = res.Body
			}
		}

		var fp *os.File

		if fp, err = os.Create(localfile); err != nil {
			return "", err
		}
		defer fp.Close()

		if _, err = io.Copy(fp, body); err != nil {
			return "", err
		}

	}

	return localfile, nil
}
<commit_msg>generate random content for test<commit_after>package server

import (
	"bytes"
	"compress/bzip2"
	"crypto/sha256"
	"fmt"
	"io"
	"math/rand"
	"net/http"
	"os"
	"path"
	"strconv"
	"time"
)

const (
	assetsDirectory = "assets/"
	// Downloading all assets from GitHub can be very slow and easily exceed
	// the 10 min time limit imposed by CI
	envSkipDownload = "SKIP_DOWNLOAD_FOR_TEST"
)

func init() {
	err := os.MkdirAll(assetsDirectory, os.ModeDir|0700)
	if err != nil {
		log.Fatalf("Could not create directory for storing assets: %q", err)
	}
}

// downloadAsset downloads the body of the given URL and stores it into
// $ASSETS_DIRECTORY/$BASENAME.SHA256_SUM($URL)
func downloadAsset(uri string) (localfile string, err error) {
	basename := path.Base(uri)
	fileExt := path.Ext(basename)

	// The sha256 hash uses 64 chars, we'll append this hash to the name. The name
	// doesn't matter that much so we'll just use 60 chars from it.
	if len(basename) > 60 {
		basename = basename[:60]
	}

	localfile = assetsDirectory + fmt.Sprintf("%s.%x", basename, sha256.Sum256([]byte(uri)))

	if !fileExists(localfile) {
		var body io.Reader = bytes.NewBufferString(strconv.FormatInt(rand.Int63(), 10))
		if skip, _ := strconv.ParseBool(os.Getenv(envSkipDownload)); skip {
			log.Debugf("Skip downloading %v in tests", uri)
		} else {
			var res *http.Response

			c := http.Client{Timeout: time.Second * 30}
			if res, err = c.Get(uri); err != nil {
				return "", err
			}
			defer res.Body.Close()

			if res.StatusCode != http.StatusOK {
				return "", fmt.Errorf("Expecting 200 OK, got: %s", res.Status)
			}

			if fileExt == ".bz2" {
				body = bzip2.NewReader(res.Body)
			} else {
				body = res.Body
			}
		}

		var fp *os.File

		if fp, err = os.Create(localfile); err != nil {
			return "", err
		}
		defer fp.Close()

		if _, err = io.Copy(fp, body); err != nil {
			return "", err
		}

	}

	return localfile, nil
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2013, fromkeith
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
 *
 * * Redistributions of source code must retain the above copyright notice, this
 *   list of conditions and the following disclaimer.
 *
 * * Redistributions in binary form must reproduce the above copyright notice, this
 *   list of conditions and the following disclaimer in the documentation and/or
 *   other materials provided with the distribution.
 *
 * * Neither the name of the fromkeith nor the names of its
 *   contributors may be used to endorse or promote products derived from
 *   this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

package cloudsearch

import (
    "github.com/fromkeith/awsgo"
    "errors"
    "encoding/json"
    "fmt"
)

var (
    Verification_Error_EndpointEmpty = errors.New("Endpoint can not be empty!")
    NoPermission_For_Endpoint = errors.New("403 Invalid permissions to hit endpoint.")
)

type DocumentInfo struct {
    // 'add' or 'delete'
    Type            string      `json:"type"`
    Id              string      `json:"id"`
    Fields          interface{} `json:"fields,omitempty"`
}

type BatchDocumentRequest struct {
    awsgo.RequestBuilder

    Items           []DocumentInfo
    // if you full endpoint is blah.us-west-2.cloudsearch.amazonaws.com
    // then set this to 'blah'
    Endpoint        string      `json:"-"`
}

type BatchDocumentMessage struct {
    Message         string  `json:"message"`
}

type BatchDocumentResponse struct {
    Status          string      `json:"status"`
    Adds            int         `json:"adds"`
    Deletes         int         `json:"deletes"`
    Errors          []BatchDocumentMessage `json:"errors"`
    Warnings        []BatchDocumentMessage `json:"warnings"`
    StatusCode      int
}

// Creates a new BatchDocumentRequest, populating in some defaults
func NewBatchDocumentRequest() *BatchDocumentRequest {
    req := new(BatchDocumentRequest)
    req.Host.Service = "cloudsearch"
    req.Host.Region = ""
    req.Host.Domain = "amazonaws.com"
    req.Key.AccessKeyId = ""
    req.Key.SecretAccessKey = ""
    req.Headers = make(map[string]string)
    req.Headers["Content-Type"] = "application/json"
    req.RequestMethod = "POST"
    req.CanonicalUri = "/2013-01-01/documents/batch"
    return req
}

func (gir * BatchDocumentRequest) VerifyInput() (error) {
    if len(gir.Endpoint) == 0 {
        return Verification_Error_EndpointEmpty
    }
    gir.Host.Override = fmt.Sprintf("%s.%s.%s.%s", gir.Endpoint, gir.Host.Region, gir.Host.Service, gir.Host.Domain)
    return nil
}

func (gir BatchDocumentRequest) DeMarshalResponse(response []byte, headers map[string]string, statusCode int) (interface{}) {
    if statusCode == 403 {
        return NoPermission_For_Endpoint
    }
    resp := new(BatchDocumentResponse)
    err := json.Unmarshal(response, resp)
    if err != nil {
        return err
    }
    return resp
}

func (gir BatchDocumentRequest) Request() (*BatchDocumentResponse, error) {
    request, err := awsgo.NewAwsRequest(&gir, gir.Items)
    if err != nil {
        return nil, err
    }
    request.RequestSigningType = awsgo.RequestSigningType_AWS4
    resp, err := request.DoAndDemarshall(&gir)
    if resp == nil {
        return nil, err
    }
    return resp.(*BatchDocumentResponse), err
}
<commit_msg>Put status code back in.<commit_after>/*
 * Copyright (c) 2013, fromkeith
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
 *
 * * Redistributions of source code must retain the above copyright notice, this
 *   list of conditions and the following disclaimer.
 *
 * * Redistributions in binary form must reproduce the above copyright notice, this
 *   list of conditions and the following disclaimer in the documentation and/or
 *   other materials provided with the distribution.
 *
 * * Neither the name of the fromkeith nor the names of its
 *   contributors may be used to endorse or promote products derived from
 *   this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

package cloudsearch

import (
    "github.com/fromkeith/awsgo"
    "errors"
    "encoding/json"
    "fmt"
)

var (
    Verification_Error_EndpointEmpty = errors.New("Endpoint can not be empty!")
    NoPermission_For_Endpoint = errors.New("403 Invalid permissions to hit endpoint.")
)

type DocumentInfo struct {
    // 'add' or 'delete'
    Type            string      `json:"type"`
    Id              string      `json:"id"`
    Fields          interface{} `json:"fields,omitempty"`
}

type BatchDocumentRequest struct {
    awsgo.RequestBuilder

    Items           []DocumentInfo
    // if you full endpoint is blah.us-west-2.cloudsearch.amazonaws.com
    // then set this to 'blah'
    Endpoint        string      `json:"-"`
}

type BatchDocumentMessage struct {
    Message         string  `json:"message"`
}

type BatchDocumentResponse struct {
    Status          string      `json:"status"`
    Adds            int         `json:"adds"`
    Deletes         int         `json:"deletes"`
    Errors          []BatchDocumentMessage `json:"errors"`
    Warnings        []BatchDocumentMessage `json:"warnings"`
    StatusCode      int
}

// Creates a new BatchDocumentRequest, populating in some defaults
func NewBatchDocumentRequest() *BatchDocumentRequest {
    req := new(BatchDocumentRequest)
    req.Host.Service = "cloudsearch"
    req.Host.Region = ""
    req.Host.Domain = "amazonaws.com"
    req.Key.AccessKeyId = ""
    req.Key.SecretAccessKey = ""
    req.Headers = make(map[string]string)
    req.Headers["Content-Type"] = "application/json"
    req.RequestMethod = "POST"
    req.CanonicalUri = "/2013-01-01/documents/batch"
    return req
}

func (gir * BatchDocumentRequest) VerifyInput() (error) {
    if len(gir.Endpoint) == 0 {
        return Verification_Error_EndpointEmpty
    }
    gir.Host.Override = fmt.Sprintf("%s.%s.%s.%s", gir.Endpoint, gir.Host.Region, gir.Host.Service, gir.Host.Domain)
    return nil
}

func (gir BatchDocumentRequest) DeMarshalResponse(response []byte, headers map[string]string, statusCode int) (interface{}) {
    if statusCode == 403 {
        return NoPermission_For_Endpoint
    }
    resp := new(BatchDocumentResponse)
    err := json.Unmarshal(response, resp)
    if err != nil {
        return err
    }
    resp.StatusCode = statusCode
    return resp
}

func (gir BatchDocumentRequest) Request() (*BatchDocumentResponse, error) {
    request, err := awsgo.NewAwsRequest(&gir, gir.Items)
    if err != nil {
        return nil, err
    }
    request.RequestSigningType = awsgo.RequestSigningType_AWS4
    resp, err := request.DoAndDemarshall(&gir)
    if resp == nil {
        return nil, err
    }
    return resp.(*BatchDocumentResponse), err
}
<|endoftext|>