<commit_before>// Copyright (C) 2012-2014 by krepa098. All rights reserved.
// Use of this source code is governed by a zlib-style
// license that can be found in the license.txt file.

package gosfml2

// #include <SFML/Graphics/Image.h>
// #include <stdlib.h>
// sfUint8 sfImage_getPixelsPtrValue(const sfImage* image, int index) { return sfImage_getPixelsPtr(image)[index]; }
import "C"

import (
	"errors"
	"runtime"
	"unsafe"
)

/////////////////////////////////////
///		STRUCTS
/////////////////////////////////////

type Image struct {
	cptr *C.sfImage
}

/////////////////////////////////////
///		FUNCS
/////////////////////////////////////

func newImageFromPtr(cptr *C.sfImage) *Image {
	image := &Image{cptr}
	runtime.SetFinalizer(image, (*Image).destroy)
	return image
}

// Create an image from a file on disk
//
// The supported image formats are bmp, png, tga, jpg, gif,
// psd, hdr and pic. Some format options are not supported,
// like progressive jpeg.
//
// file: Path of the image file to load
func NewImageFromFile(file string) (*Image, error) {
	cFile := C.CString(file)
	defer C.free(unsafe.Pointer(cFile))

	if cptr := C.sfImage_createFromFile(cFile); cptr != nil {
		image := &Image{cptr}
		runtime.SetFinalizer(image, (*Image).destroy)
		return image, nil
	}

	return nil, genericError
}

// Create an image
//
// This image is filled with black pixels.
//
// 	width:  Width of the image
// 	height: Height of the image
func NewImage(width, height uint) (*Image, error) {
	if cptr := C.sfImage_create(C.uint(width), C.uint(height)); cptr != nil {
		image := &Image{}
		runtime.SetFinalizer(image, (*Image).destroy)
		return image, nil
	}

	return nil, genericError
}

// Create an image and fill it with a unique color
//
// 	width:  Width of the image
// 	height: Height of the image
// 	color:  Fill color
func NewImageFromColor(width, height uint, color Color) (*Image, error) {
	if cptr := C.sfImage_createFromColor(C.uint(width), C.uint(height), color.toC()); cptr != nil {
		image := &Image{cptr}
		runtime.SetFinalizer(image, (*Image).destroy)
		return image, nil
	}

	return nil, genericError
}

// Create an image from an array of pixels
//
// The pixel array is assumed to contain 32-bits RGBA pixels,
// and have the given width and height. If not, this is
// an undefined behaviour.
// If pixels is nil, an empty image is created.
//
// 	width:  Width of the image
// 	height: Height of the image
// 	pixels: Slice of pixels to copy to the image
func NewImageFromPixels(width, height uint, data []byte) (*Image, error) {
	if len(data) == 0 {
		return nil, errors.New("NewImageFromPixels: len(data)==0")
	}

	if cptr := C.sfImage_createFromPixels(C.uint(width), C.uint(height), (*C.sfUint8)(&data[0])); cptr != nil {
		image := &Image{cptr}
		runtime.SetFinalizer(image, (*Image).destroy)
		return image, nil
	}

	return nil, genericError
}

// Create an image from a file in memory
//
// The supported image formats are bmp, png, tga, jpg, gif,
// psd, hdr and pic. Some format options are not supported,
// like progressive jpeg.
//
// 	data: Slice containing the file data
func NewImageFromMemory(data []byte) (*Image, error) {
	if len(data) == 0 {
		return nil, errors.New("NewImageFromMemory: len(data)==0")
	}

	if cptr := C.sfImage_createFromMemory(unsafe.Pointer(&data[0]), C.size_t(len(data))); cptr != nil {
		image := &Image{cptr}
		runtime.SetFinalizer(image, (*Image).destroy)
		return image, nil
	}
	return nil, genericError
}

// Copy an existing image
func (this *Image) Copy() *Image {
	image := &Image{C.sfImage_copy(this.cptr)}
	runtime.SetFinalizer(image, (*Image).destroy)
	return image
}

// Destroy an existing image
func (this *Image) destroy() {
	C.sfImage_destroy(this.cptr)
}

// Save an image to a file on disk
//
// The format of the image is automatically deduced from
// the extension. The supported image formats are bmp, png,
// tga and jpg. The destination file is overwritten
// if it already exists. This function fails if the image is empty.
//
// 	filename: Path of the file to save
func (this *Image) SaveToFile(file string) error {
	cFile := C.CString(file)
	defer C.free(unsafe.Pointer(cFile))

	if !sfBool2Go(C.sfImage_saveToFile(this.cptr, cFile)) {
		return genericError
	}

	return nil
}

// Return the size of an image
func (this *Image) GetSize() (size Vector2u) {
	size.fromC(C.sfImage_getSize(this.cptr))
	return
}

// Create a transparency mask from a specified color-key
//
// This function sets the alpha value of every pixel matching
// the given color to alpha (0 by default), so that they
// become transparent.
//
// 	color: Color to make transparent
// 	alpha: Alpha value to assign to transparent pixels
func (this *Image) CreateMaskFromColor(color Color, alpha byte) {
	C.sfImage_createMaskFromColor(this.cptr, color.toC(), C.sfUint8(alpha))
}

// Copy pixels from an image onto another
//
// This function does a slow pixel copy and should not be
// used intensively. It can be used to prepare a complex
// static image from several others, but if you need this
// kind of feature in real-time you'd better use RenderTexture.
//
// If sourceRect is empty, the whole image is copied.
// If applyAlpha is set to true, the transparency of
// source pixels is applied. If it is false, the pixels are
// copied unchanged with their alpha value.
//
// 	source:     Source image to copy
// 	destX:      X coordinate of the destination position
// 	destY:      Y coordinate of the destination position
// 	sourceRect: Sub-rectangle of the source image to copy
// 	applyAlpha: Should the copy take in account the source transparency?
func (this *Image) CopyImage(source *Image, destX, destY uint, sourceRect IntRect, applyAlpha bool) {
	C.sfImage_copyImage(this.cptr, source.cptr, C.uint(destX), C.uint(destY), sourceRect.toC(), goBool2C(applyAlpha))
}

// Change the color of a pixel in an image
//
// This function doesn't check the validity of the pixel
// coordinates, using out-of-range values will result in
// an undefined behaviour.
//
// 	x:     X coordinate of pixel to change
// 	y:     Y coordinate of pixel to change
// 	color: New color of the pixel
func (this *Image) SetPixel(x, y uint, color Color) {
	C.sfImage_setPixel(this.cptr, C.uint(x), C.uint(y), color.toC())
}

// Get the color of a pixel in an image
//
// This function doesn't check the validity of the pixel
// coordinates, using out-of-range values will result in
// an undefined behaviour.
//
// 	x:     X coordinate of pixel to get
// 	y:     Y coordinate of pixel to get
func (this *Image) GetPixel(x, y uint) (color Color) {
	color.fromC(C.sfImage_getPixel(this.cptr, C.uint(x), C.uint(y)))
	return
}

// Get a slice of pixels of an image
//
// The length of the slice is width * height * 4 (RGBA).
func (this *Image) GetPixelData() []byte {
	data := make([]byte, this.GetSize().X*this.GetSize().Y*4)
	for i := 0; i < len(data); i++ {
		data[i] = byte(C.sfImage_getPixelsPtrValue(this.cptr, C.int(i)))
	}
	return data
}

// Flip an image horizontally (left <-> right)
func (this *Image) FlipHorizontally() {
	C.sfImage_flipHorizontally(this.cptr)
}

// Flip an image vertically (top <-> bottom)
func (this *Image) FlipVertically() {
	C.sfImage_flipVertically(this.cptr)
}

/////////////////////////////////////
///		GO <-> C
/////////////////////////////////////

func (this *Image) toCPtr() *C.sfImage {
	if this != nil {
		return this.cptr
	}
	return nil
}
<commit_msg>fixed issue #13<commit_after>// Copyright (C) 2012-2014 by krepa098. All rights reserved.
// Use of this source code is governed by a zlib-style
// license that can be found in the license.txt file.

package gosfml2

// #include <SFML/Graphics/Image.h>
// #include <stdlib.h>
// sfUint8 sfImage_getPixelsPtrValue(const sfImage* image, int index) { return sfImage_getPixelsPtr(image)[index]; }
import "C"

import (
	"errors"
	"runtime"
	"unsafe"
)

/////////////////////////////////////
///		STRUCTS
/////////////////////////////////////

type Image struct {
	cptr *C.sfImage
}

/////////////////////////////////////
///		FUNCS
/////////////////////////////////////

func newImageFromPtr(cptr *C.sfImage) *Image {
	image := &Image{cptr}
	runtime.SetFinalizer(image, (*Image).destroy)
	return image
}

// Create an image from a file on disk
//
// The supported image formats are bmp, png, tga, jpg, gif,
// psd, hdr and pic. Some format options are not supported,
// like progressive jpeg.
//
// file: Path of the image file to load
func NewImageFromFile(file string) (*Image, error) {
	cFile := C.CString(file)
	defer C.free(unsafe.Pointer(cFile))

	if cptr := C.sfImage_createFromFile(cFile); cptr != nil {
		image := &Image{cptr}
		runtime.SetFinalizer(image, (*Image).destroy)
		return image, nil
	}

	return nil, genericError
}

// Create an image
//
// This image is filled with black pixels.
//
// 	width:  Width of the image
// 	height: Height of the image
func NewImage(width, height uint) (*Image, error) {
	if cptr := C.sfImage_create(C.uint(width), C.uint(height)); cptr != nil {
		image := &Image{cptr}
		runtime.SetFinalizer(image, (*Image).destroy)
		return image, nil
	}

	return nil, genericError
}

// Create an image and fill it with a unique color
//
// 	width:  Width of the image
// 	height: Height of the image
// 	color:  Fill color
func NewImageFromColor(width, height uint, color Color) (*Image, error) {
	if cptr := C.sfImage_createFromColor(C.uint(width), C.uint(height), color.toC()); cptr != nil {
		image := &Image{cptr}
		runtime.SetFinalizer(image, (*Image).destroy)
		return image, nil
	}

	return nil, genericError
}

// Create an image from an array of pixels
//
// The pixel array is assumed to contain 32-bits RGBA pixels,
// and have the given width and height. If not, this is
// an undefined behaviour.
// If pixels is nil, an empty image is created.
//
// 	width:  Width of the image
// 	height: Height of the image
// 	pixels: Slice of pixels to copy to the image
func NewImageFromPixels(width, height uint, data []byte) (*Image, error) {
	if len(data) == 0 {
		return nil, errors.New("NewImageFromPixels: len(data)==0")
	}

	if cptr := C.sfImage_createFromPixels(C.uint(width), C.uint(height), (*C.sfUint8)(&data[0])); cptr != nil {
		image := &Image{cptr}
		runtime.SetFinalizer(image, (*Image).destroy)
		return image, nil
	}

	return nil, genericError
}

// Create an image from a file in memory
//
// The supported image formats are bmp, png, tga, jpg, gif,
// psd, hdr and pic. Some format options are not supported,
// like progressive jpeg.
//
// 	data: Slice containing the file data
func NewImageFromMemory(data []byte) (*Image, error) {
	if len(data) == 0 {
		return nil, errors.New("NewImageFromMemory: len(data)==0")
	}

	if cptr := C.sfImage_createFromMemory(unsafe.Pointer(&data[0]), C.size_t(len(data))); cptr != nil {
		image := &Image{cptr}
		runtime.SetFinalizer(image, (*Image).destroy)
		return image, nil
	}
	return nil, genericError
}

// Copy an existing image
func (this *Image) Copy() *Image {
	image := &Image{C.sfImage_copy(this.cptr)}
	runtime.SetFinalizer(image, (*Image).destroy)
	return image
}

// Destroy an existing image
func (this *Image) destroy() {
	C.sfImage_destroy(this.cptr)
}

// Save an image to a file on disk
//
// The format of the image is automatically deduced from
// the extension. The supported image formats are bmp, png,
// tga and jpg. The destination file is overwritten
// if it already exists. This function fails if the image is empty.
//
// 	filename: Path of the file to save
func (this *Image) SaveToFile(file string) error {
	cFile := C.CString(file)
	defer C.free(unsafe.Pointer(cFile))

	if !sfBool2Go(C.sfImage_saveToFile(this.cptr, cFile)) {
		return genericError
	}

	return nil
}

// Return the size of an image
func (this *Image) GetSize() (size Vector2u) {
	size.fromC(C.sfImage_getSize(this.cptr))
	return
}

// Create a transparency mask from a specified color-key
//
// This function sets the alpha value of every pixel matching
// the given color to alpha (0 by default), so that they
// become transparent.
//
// 	color: Color to make transparent
// 	alpha: Alpha value to assign to transparent pixels
func (this *Image) CreateMaskFromColor(color Color, alpha byte) {
	C.sfImage_createMaskFromColor(this.cptr, color.toC(), C.sfUint8(alpha))
}

// Copy pixels from an image onto another
//
// This function does a slow pixel copy and should not be
// used intensively. It can be used to prepare a complex
// static image from several others, but if you need this
// kind of feature in real-time you'd better use RenderTexture.
//
// If sourceRect is empty, the whole image is copied.
// If applyAlpha is set to true, the transparency of
// source pixels is applied. If it is false, the pixels are
// copied unchanged with their alpha value.
//
// 	source:     Source image to copy
// 	destX:      X coordinate of the destination position
// 	destY:      Y coordinate of the destination position
// 	sourceRect: Sub-rectangle of the source image to copy
// 	applyAlpha: Should the copy take in account the source transparency?
func (this *Image) CopyImage(source *Image, destX, destY uint, sourceRect IntRect, applyAlpha bool) {
	C.sfImage_copyImage(this.cptr, source.cptr, C.uint(destX), C.uint(destY), sourceRect.toC(), goBool2C(applyAlpha))
}

// Change the color of a pixel in an image
//
// This function doesn't check the validity of the pixel
// coordinates, using out-of-range values will result in
// an undefined behaviour.
//
// 	x:     X coordinate of pixel to change
// 	y:     Y coordinate of pixel to change
// 	color: New color of the pixel
func (this *Image) SetPixel(x, y uint, color Color) {
	C.sfImage_setPixel(this.cptr, C.uint(x), C.uint(y), color.toC())
}

// Get the color of a pixel in an image
//
// This function doesn't check the validity of the pixel
// coordinates, using out-of-range values will result in
// an undefined behaviour.
//
// 	x:     X coordinate of pixel to get
// 	y:     Y coordinate of pixel to get
func (this *Image) GetPixel(x, y uint) (color Color) {
	color.fromC(C.sfImage_getPixel(this.cptr, C.uint(x), C.uint(y)))
	return
}

// Get a slice of pixels of an image
//
// The length of the slice is width * height * 4 (RGBA).
func (this *Image) GetPixelData() []byte {
	data := make([]byte, this.GetSize().X*this.GetSize().Y*4)
	for i := 0; i < len(data); i++ {
		data[i] = byte(C.sfImage_getPixelsPtrValue(this.cptr, C.int(i)))
	}
	return data
}

// Flip an image horizontally (left <-> right)
func (this *Image) FlipHorizontally() {
	C.sfImage_flipHorizontally(this.cptr)
}

// Flip an image vertically (top <-> bottom)
func (this *Image) FlipVertically() {
	C.sfImage_flipVertically(this.cptr)
}

/////////////////////////////////////
///		GO <-> C
/////////////////////////////////////

func (this *Image) toCPtr() *C.sfImage {
	if this != nil {
		return this.cptr
	}
	return nil
}
<|endoftext|>


<commit_before>package goshopify

import (
	"fmt"
	"time"

	"github.com/shopspring/decimal"
)

const ordersBasePath = "admin/orders"

// OrderService is an interface for interfacing with the orders endpoints of
// the Shopify API.
// See: https://help.shopify.com/api/reference/order
type OrderService interface {
	List(interface{}) ([]Order, error)
	Count(interface{}) (int, error)
	Get(int, interface{}) (*Order, error)
}

// OrderServiceOp handles communication with the order related methods of the
// Shopify API.
type OrderServiceOp struct {
	client *Client
}

// A struct for all available order list options.
// See: https://help.shopify.com/api/reference/order#index
type OrderListOptions struct {
	Page              int       `url:"page,omitempty"`
	Limit             int       `url:"limit,omitempty"`
	SinceID           int       `url:"since_id,omitempty"`
	Status            string    `url:"status,omitempty"`
	FinancialStatus   string    `url:"financial_status,omitempty"`
	FulfillmentStatus string    `url:"fulfillment_status,omitempty"`
	CreatedAtMin      time.Time `url:"created_at_min,omitempty"`
	CreatedAtMax      time.Time `url:"created_at_max,omitempty"`
	UpdatedAtMin      time.Time `url:"updated_at_min,omitempty"`
	UpdatedAtMax      time.Time `url:"updated_at_max,omitempty"`
	ProcessedAtMin    time.Time `url:"processed_at_min,omitempty"`
	ProcessedAtMax    time.Time `url:"processed_at_max,omitempty"`
	Fields            string    `url:"fields,omitempty"`
	Order             string    `url:"order,omitempty"`
}

// Order represents a Shopify order
type Order struct {
	ID                    int              `json:"id"`
	Name                  string           `json:"name"`
	Email                 string           `json:"email"`
	CreatedAt             *time.Time       `json:"created_at"`
	UpdatedAt             *time.Time       `json:"updated_at"`
	CancelledAt           *time.Time       `json:"cancelled_at"`
	ClosedAt              *time.Time       `json:"closed_at"`
	ProcessedAt           *time.Time       `json:"processed_at"`
	Customer              *Customer        `json:"customer"`
	BillingAddress        *Address         `json:"billing_address"`
	ShippingAddress       *Address         `json:"shipping_address"`
	Currency              string           `json:"currency"`
	TotalPrice            *decimal.Decimal `json:"total_price"`
	SubtotalPrice         *decimal.Decimal `json:"subtotal_price"`
	TotalDiscounts        *decimal.Decimal `json:"total_discounts"`
	TotalLineItemsPrice   *decimal.Decimal `json:"total_line_items_price"`
	TaxesIncluded         bool             `json:"taxes_included"`
	TotalTax              *decimal.Decimal `json:"total_tax"`
	TaxLines              []TaxLine        `json:"tax_lines"`
	TotalWeight           int              `json:"total_weight"`
	FinancialStatus       string           `json:"financial_status"`
	FulfillmentStatus     string           `json:"fulfillment_status"`
	Token                 string           `json:"token"`
	CartToken             string           `json:"cart_token"`
	Number                int              `json:"number"`
	OrderNumber           int              `json:"order_number"`
	Note                  string           `json:"note"`
	Test                  bool             `json:"test"`
	BrowserIp             string           `json:"browser_ip"`
	BuyerAcceptsMarketing bool             `json:"buyer_accepts_marketing"`
	CancelReason          string           `json:"cancel_reason"`
	NoteAttributes        []NoteAttribute  `json:"note_attributes"`
	DiscountCodes         []DiscountCode   `json:"discount_codes"`
	LineItems             []LineItem       `json:"line_items"`
	ShippingLines         []ShippingLines  `json:"shipping_lines"`
	Transactions          []Transaction    `json:"transactions"`
	AppID                 int              `json:"app_id"`
	CustomerLocale        string           `json:"customer_locale"`
	LandingSite           string           `json:"landing_site"`
	ReferringSite         string           `json:"referring_site"`
	SourceName            string           `json:"source_name"`
}

type Address struct {
	ID           int     `json:"id"`
	Address1     string  `json:"address1"`
	Address2     string  `json:"address2"`
	City         string  `json:"city"`
	Company      string  `json:"company"`
	Country      string  `json:"country"`
	CountryCode  string  `json:"country_code"`
	FirstName    string  `json:"first_name"`
	LastName     string  `json:"last_name"`
	Latitude     float64 `json:"latitude"`
	Longitude    float64 `json:"longitude"`
	Name         string  `json:"name"`
	Phone        string  `json:"phone"`
	Province     string  `json:"province"`
	ProvinceCode string  `json:"province_code"`
	Zip          string  `json:"zip"`
}

type DiscountCode struct {
	Amount *decimal.Decimal `json:"amount"`
	Code   string           `json:"code"`
	Type   string           `json:"type"`
}

type LineItem struct {
	ID            int              `json:"id"`
	ProductID     int              `json:"product_id"`
	VariantID     int              `json:"variant_id"`
	Quantity      int              `json:"quantity"`
	Price         *decimal.Decimal `json:"price"`
	TotalDiscount *decimal.Decimal `json:"total_discount"`
	Title         string           `json:"title"`
	VariantTitle  string           `json:"variant_title"`
	Name          string           `json:"name"`
	SKU           string           `json:"sku"`
	Vendor        string           `json:"vendor"`
	GiftCard      bool             `json:"gift_card"`
	Taxable       bool             `json:"taxable"`
}

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

type NoteAttribute struct {
	Name  string `json:"Name"`
	Value string `json:"Value"`
}

// Represents the result from the orders/X.json endpoint
type OrderResource struct {
	Order *Order `json:"order"`
}

// Represents the result from the orders.json endpoint
type OrdersResource struct {
	Orders []Order `json:"orders"`
}

type PaymentDetails struct {
	AVSResultCode     string `json:"avs_result_code"`
	CreditCardBin     string `json:"credit_card_bin"`
	CVVResultCode     string `json:"cvv_result_code"`
	CreditCardNumber  string `json:"credit_card_number"`
	CreditCardCompany string `json:"credit_card_company"`
}

type ShippingLines struct {
	ID                            int              `json:"id"`
	Title                         string           `json:"title"`
	Price                         *decimal.Decimal `json:"price"`
	Code                          string           `json:"code"`
	Source                        string           `json:"source"`
	Phone                         string           `json:"phone"`
	RequestedFulfillmentServiceID string           `json:"requested_fulfillment_service_id"`
	DeliveryCategory              string           `json:"delivery_category"`
	CarrierIdentifier             string           `json:"carrier_identifier"`
	TaxLines                      []TaxLine        `json:"tax_lines"`
}

type TaxLine struct {
	Title string           `json:"title"`
	Price *decimal.Decimal `json:"price"`
	Rate  *decimal.Decimal `json:"rate"`
}

type Transaction struct {
	ID             int              `json:"id"`
	OrderID        int              `json:"order_id"`
	Amount         *decimal.Decimal `json:"amount"`
	Kind           string           `json:"kind"`
	Gateway        string           `json:"gateway"`
	Status         string           `json:"status"`
	Message        string           `json:"message"`
	CreatedAt      *time.Time       `json:"created_at"`
	Test           bool             `json:"test"`
	Authorization  string           `json:"authorization"`
	Currency       string           `json:"currency"`
	LocationID     *int             `json:"location_id"`
	UserID         *int             `json:"user_id"`
	ParentID       *int             `json:"parent_id"`
	DeviceID       *int             `json:"device_id"`
	ErrorCode      string           `json:"error_code"`
	SourceName     string           `json:"source_name"`
	PaymentDetails *PaymentDetails  `json:"payment_details"`
}

// List orders
func (s *OrderServiceOp) List(options interface{}) ([]Order, error) {
	path := fmt.Sprintf("%s.json", ordersBasePath)
	resource := new(OrdersResource)
	err := s.client.Get(path, resource, options)
	return resource.Orders, err
}

// Count orders
func (s *OrderServiceOp) Count(options interface{}) (int, error) {
	path := fmt.Sprintf("%s/count.json", ordersBasePath)
	return s.client.Count(path, options)
}

// Get individual order
func (s *OrderServiceOp) Get(orderID int, options interface{}) (*Order, error) {
	path := fmt.Sprintf("%s/%d.json", ordersBasePath, orderID)
	resource := new(OrderResource)
	err := s.client.Get(path, resource, options)
	return resource.Order, err
}
<commit_msg>Add fulfillments details to order (#60)<commit_after>package goshopify

import (
	"fmt"
	"time"

	"github.com/shopspring/decimal"
)

const ordersBasePath = "admin/orders"

// OrderService is an interface for interfacing with the orders endpoints of
// the Shopify API.
// See: https://help.shopify.com/api/reference/order
type OrderService interface {
	List(interface{}) ([]Order, error)
	Count(interface{}) (int, error)
	Get(int, interface{}) (*Order, error)
}

// OrderServiceOp handles communication with the order related methods of the
// Shopify API.
type OrderServiceOp struct {
	client *Client
}

// A struct for all available order list options.
// See: https://help.shopify.com/api/reference/order#index
type OrderListOptions struct {
	Page              int       `url:"page,omitempty"`
	Limit             int       `url:"limit,omitempty"`
	SinceID           int       `url:"since_id,omitempty"`
	Status            string    `url:"status,omitempty"`
	FinancialStatus   string    `url:"financial_status,omitempty"`
	FulfillmentStatus string    `url:"fulfillment_status,omitempty"`
	CreatedAtMin      time.Time `url:"created_at_min,omitempty"`
	CreatedAtMax      time.Time `url:"created_at_max,omitempty"`
	UpdatedAtMin      time.Time `url:"updated_at_min,omitempty"`
	UpdatedAtMax      time.Time `url:"updated_at_max,omitempty"`
	ProcessedAtMin    time.Time `url:"processed_at_min,omitempty"`
	ProcessedAtMax    time.Time `url:"processed_at_max,omitempty"`
	Fields            string    `url:"fields,omitempty"`
	Order             string    `url:"order,omitempty"`
}

// Order represents a Shopify order
type Order struct {
	ID                    int              `json:"id"`
	Name                  string           `json:"name"`
	Email                 string           `json:"email"`
	CreatedAt             *time.Time       `json:"created_at"`
	UpdatedAt             *time.Time       `json:"updated_at"`
	CancelledAt           *time.Time       `json:"cancelled_at"`
	ClosedAt              *time.Time       `json:"closed_at"`
	ProcessedAt           *time.Time       `json:"processed_at"`
	Customer              *Customer        `json:"customer"`
	BillingAddress        *Address         `json:"billing_address"`
	ShippingAddress       *Address         `json:"shipping_address"`
	Currency              string           `json:"currency"`
	TotalPrice            *decimal.Decimal `json:"total_price"`
	SubtotalPrice         *decimal.Decimal `json:"subtotal_price"`
	TotalDiscounts        *decimal.Decimal `json:"total_discounts"`
	TotalLineItemsPrice   *decimal.Decimal `json:"total_line_items_price"`
	TaxesIncluded         bool             `json:"taxes_included"`
	TotalTax              *decimal.Decimal `json:"total_tax"`
	TaxLines              []TaxLine        `json:"tax_lines"`
	TotalWeight           int              `json:"total_weight"`
	FinancialStatus       string           `json:"financial_status"`
	Fulfillments          []Fulfillment    `json:"fulfillments"`
	FulfillmentStatus     string           `json:"fulfillment_status"`
	Token                 string           `json:"token"`
	CartToken             string           `json:"cart_token"`
	Number                int              `json:"number"`
	OrderNumber           int              `json:"order_number"`
	Note                  string           `json:"note"`
	Test                  bool             `json:"test"`
	BrowserIp             string           `json:"browser_ip"`
	BuyerAcceptsMarketing bool             `json:"buyer_accepts_marketing"`
	CancelReason          string           `json:"cancel_reason"`
	NoteAttributes        []NoteAttribute  `json:"note_attributes"`
	DiscountCodes         []DiscountCode   `json:"discount_codes"`
	LineItems             []LineItem       `json:"line_items"`
	ShippingLines         []ShippingLines  `json:"shipping_lines"`
	Transactions          []Transaction    `json:"transactions"`
	AppID                 int              `json:"app_id"`
	CustomerLocale        string           `json:"customer_locale"`
	LandingSite           string           `json:"landing_site"`
	ReferringSite         string           `json:"referring_site"`
	SourceName            string           `json:"source_name"`
}

type Address struct {
	ID           int     `json:"id"`
	Address1     string  `json:"address1"`
	Address2     string  `json:"address2"`
	City         string  `json:"city"`
	Company      string  `json:"company"`
	Country      string  `json:"country"`
	CountryCode  string  `json:"country_code"`
	FirstName    string  `json:"first_name"`
	LastName     string  `json:"last_name"`
	Latitude     float64 `json:"latitude"`
	Longitude    float64 `json:"longitude"`
	Name         string  `json:"name"`
	Phone        string  `json:"phone"`
	Province     string  `json:"province"`
	ProvinceCode string  `json:"province_code"`
	Zip          string  `json:"zip"`
}

type DiscountCode struct {
	Amount *decimal.Decimal `json:"amount"`
	Code   string           `json:"code"`
	Type   string           `json:"type"`
}

type LineItem struct {
	ID                         int              `json:"id"`
	ProductID                  int              `json:"product_id"`
	VariantID                  int              `json:"variant_id"`
	Quantity                   int              `json:"quantity"`
	Price                      *decimal.Decimal `json:"price"`
	TotalDiscount              *decimal.Decimal `json:"total_discount"`
	Title                      string           `json:"title"`
	VariantTitle               string           `json:"variant_title"`
	Name                       string           `json:"name"`
	SKU                        string           `json:"sku"`
	Vendor                     string           `json:"vendor"`
	GiftCard                   bool             `json:"gift_card"`
	Taxable                    bool             `json:"taxable"`
	FulfillmentService         string           `json:"fulfillment_service"`
	RequiresShipping           bool             `json:"requires_shipping"`
	VariantInventoryManagement string           `json:"variant_inventory_management"`
	Properties                 []NoteAttribute  `json:"properties"`
	ProductExists              bool             `json:"product_exists"`
	FulfillableQuantity        int              `json:"fulfillable_quantity"`
	Grams                      int              `json:"grams"`
	FulfillmentStatus          string           `json:"fulfillment_status"`
	TaxLines                   []TaxLine        `json:"tax_lines"`
	OriginLocation             Address          `json:"origin_location"`
	DestinationLocation        Address          `json:"destination_location"`
}

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

type NoteAttribute struct {
	Name  string `json:"Name"`
	Value string `json:"Value"`
}

// Represents the result from the orders/X.json endpoint
type OrderResource struct {
	Order *Order `json:"order"`
}

// Represents the result from the orders.json endpoint
type OrdersResource struct {
	Orders []Order `json:"orders"`
}

type PaymentDetails struct {
	AVSResultCode     string `json:"avs_result_code"`
	CreditCardBin     string `json:"credit_card_bin"`
	CVVResultCode     string `json:"cvv_result_code"`
	CreditCardNumber  string `json:"credit_card_number"`
	CreditCardCompany string `json:"credit_card_company"`
}

type ShippingLines struct {
	ID                            int              `json:"id"`
	Title                         string           `json:"title"`
	Price                         *decimal.Decimal `json:"price"`
	Code                          string           `json:"code"`
	Source                        string           `json:"source"`
	Phone                         string           `json:"phone"`
	RequestedFulfillmentServiceID string           `json:"requested_fulfillment_service_id"`
	DeliveryCategory              string           `json:"delivery_category"`
	CarrierIdentifier             string           `json:"carrier_identifier"`
	TaxLines                      []TaxLine        `json:"tax_lines"`
}

type TaxLine struct {
	Title string           `json:"title"`
	Price *decimal.Decimal `json:"price"`
	Rate  *decimal.Decimal `json:"rate"`
}

type Transaction struct {
	ID             int              `json:"id"`
	OrderID        int              `json:"order_id"`
	Amount         *decimal.Decimal `json:"amount"`
	Kind           string           `json:"kind"`
	Gateway        string           `json:"gateway"`
	Status         string           `json:"status"`
	Message        string           `json:"message"`
	CreatedAt      *time.Time       `json:"created_at"`
	Test           bool             `json:"test"`
	Authorization  string           `json:"authorization"`
	Currency       string           `json:"currency"`
	LocationID     *int             `json:"location_id"`
	UserID         *int             `json:"user_id"`
	ParentID       *int             `json:"parent_id"`
	DeviceID       *int             `json:"device_id"`
	ErrorCode      string           `json:"error_code"`
	SourceName     string           `json:"source_name"`
	PaymentDetails *PaymentDetails  `json:"payment_details"`
}

type Fulfillment struct {
	ID              int        `json:"id"`
	OrderID         int        `json:"order_id"`
	Status          string     `json:"status"`
	CreatedAt       *time.Time `json:"created_at"`
	Service         string     `json:"service"`
	UpdatedAt       *time.Time `json:"updated_at"`
	TrackingCompany string     `json:"tracking_company"`
	ShipmentStatus  string     `json:"shipment_status"`
	TrackingNumber  string     `json:"tracking_number"`
	TrackingNumbers []string   `json:"tracking_numbers"`
	TrackingUrl     string     `json:"tracking_url"`
	TrackingUrls    []string   `json:"tracking_urls"`
	Receipt         Receipt    `json:"receipt"`
	LineItems       []LineItem `json:"line_items"`
}

type Receipt struct {
	TestCase      bool   `json:"testcase"`
	Authorization string `json:"authorization"`
}

// List orders
func (s *OrderServiceOp) List(options interface{}) ([]Order, error) {
	path := fmt.Sprintf("%s.json", ordersBasePath)
	resource := new(OrdersResource)
	err := s.client.Get(path, resource, options)
	return resource.Orders, err
}

// Count orders
func (s *OrderServiceOp) Count(options interface{}) (int, error) {
	path := fmt.Sprintf("%s/count.json", ordersBasePath)
	return s.client.Count(path, options)
}

// Get individual order
func (s *OrderServiceOp) Get(orderID int, options interface{}) (*Order, error) {
	path := fmt.Sprintf("%s/%d.json", ordersBasePath, orderID)
	resource := new(OrderResource)
	err := s.client.Get(path, resource, options)
	return resource.Order, err
}
<|endoftext|>


<commit_before>// Copyright 2018-2019 gf Author(https://github.com/gogf/gf). All Rights Reserved.
//
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://github.com/gogf/gf.

// Package gmutex implements graceful concurrent-safe mutex with more rich features.
package gmutex

import (
	"math"
	"runtime"

	"github.com/gogf/gf/g/container/gtype"
)

// The high level Mutex, which implements more rich features for mutex.
type Mutex struct {
	state   *gtype.Int32  // Indicates the state of mutex.
	writer  *gtype.Int32  // Pending Writer count.
	reader  *gtype.Int32  // Pending reader count.
	writing chan struct{} // Channel used for writer blocking.
	reading chan struct{} // Channel used for reader blocking.
}

// New creates and returns a new mutex.
func New() *Mutex {
	return &Mutex{
		state:   gtype.NewInt32(),
		writer:  gtype.NewInt32(),
		reader:  gtype.NewInt32(),
		writing: make(chan struct{}, 1),
		reading: make(chan struct{}, math.MaxInt32),
	}
}

// Lock locks the mutex for writing.
// If the lock is already locked for reading or writing,
// Lock blocks until the lock is available.
func (m *Mutex) Lock() {
	for {
		// If there're no readers pending and no writing lock currently,
		// then do the writing lock checks.
		if m.reader.Val() == 0 && m.state.Cas(0, -1) {
			return
		}
		m.writer.Add(1)
		<-m.writing
		m.writer.Add(-1)
	}
}

// Unlock unlocks the writing lock.
// It is safe to be called multiple times if there's any locks or not.
func (m *Mutex) Unlock() {
	if m.state.Cas(-1, 0) {
		// Writing lock unlocks, then first check the blocked readers.
		if n := m.reader.Val(); n > 0 {
			// If there're readers blocked, unlock them with preemption.
			for i := n; i > 0; i-- {
				m.reading <- struct{}{}
			}
			return
		}
		if m.writer.Val() > 0 {
			m.writing <- struct{}{}
			return
		}
	}
}

// TryLock tries locking the mutex for writing.
// It returns true if success, or if there's a write/reading lock on the mutex,
// it returns false.
func (m *Mutex) TryLock() bool {
	if m.reader.Val() == 0 && m.state.Cas(0, -1) {
		return true
	}
	return false
}

// RLock locks mutex for reading.
// If the mutex is already locked for writing,
// It blocks until the lock is available.
func (m *Mutex) RLock() {
	for {
		// If there no writing lock and no pending writers,
		// then do the reading lock checks.
		if n := m.state.Val(); n >= 0 && m.writer.Val() == 0 {
			if m.state.Cas(n, n+1) {
				return
			} else {
				runtime.Gosched()
			}
		}
		// Or else pending the reader.
		m.reader.Add(1)
		<-m.reading
		m.reader.Add(-1)
	}
}

// RUnlock unlocks the reading lock.
// It is safe to be called multiple times if there's any locks or not.
func (m *Mutex) RUnlock() {
	var n int32
	for {
		if n = m.state.Val(); n >= 1 {
			if m.state.Cas(n, n-1) {
				break
			} else {
				runtime.Gosched()
			}
		} else {
			break
		}
	}
	// Reading lock unlocks, then first check the blocked writers.
	if n == 1 && m.writer.Val() > 0 {
		// No readers blocked, then the writers can take place.
		m.writing <- struct{}{}
		return
	}
}

// TryRLock tries locking the mutex for reading.
// It returns true if success, or if there's a writing lock on the mutex, it returns false.
func (m *Mutex) TryRLock() bool {
	for {
		if n := m.state.Val(); n >= 0 && m.writer.Val() == 0 {
			if m.state.Cas(n, n+1) {
				return true
			} else {
				runtime.Gosched()
			}
		} else {
			return false
		}
	}
}

// IsLocked checks whether the mutex is locked with writing or reading lock.
// Note that the result might be changed after it's called,
// so it cannot be the criterion for atomic operations.
func (m *Mutex) IsLocked() bool {
	return m.state.Val() != 0
}

// IsWLocked checks whether the mutex is locked by writing lock.
// Note that the result might be changed after it's called,
// so it cannot be the criterion for atomic operations.
func (m *Mutex) IsWLocked() bool {
	return m.state.Val() < 0
}

// IsRLocked checks whether the mutex is locked by reading lock.
// Note that the result might be changed after it's called,
// so it cannot be the criterion for atomic operations.
func (m *Mutex) IsRLocked() bool {
	return m.state.Val() > 0
}

// TryLockFunc tries locking the mutex for writing with given callback function <f>.
// it returns true if success, or if there's a write/reading lock on the mutex,
// it returns false.
//
// It releases the lock after <f> is executed.
func (m *Mutex) TryLockFunc(f func()) bool {
	if m.TryLock() {
		defer m.Unlock()
		f()
		return true
	}
	return false
}

// TryRLockFunc tries locking the mutex for reading with given callback function <f>.
// It returns true if success, or if there's a writing lock on the mutex, it returns false.
//
// It releases the lock after <f> is executed.
func (m *Mutex) TryRLockFunc(f func()) bool {
	if m.TryRLock() {
		defer m.RUnlock()
		f()
		return true
	}
	return false
}

// LockFunc locks the mutex for writing with given callback function <f>.
// If there's a write/reading lock the mutex, it will blocks until the lock is released.
//
// It releases the lock after <f> is executed.
func (m *Mutex) LockFunc(f func()) {
	m.Lock()
	defer m.Unlock()
	f()
}

// RLockFunc locks the mutex for reading with given callback function <f>.
// If there's a writing lock the mutex, it will blocks until the lock is released.
//
// It releases the lock after <f> is executed.
func (m *Mutex) RLockFunc(f func()) {
	m.RLock()
	defer m.RUnlock()
	f()
}
<commit_msg>improve gmutex<commit_after>// Copyright 2018-2019 gf Author(https://github.com/gogf/gf). All Rights Reserved.
//
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://github.com/gogf/gf.

// Package gmutex implements graceful concurrent-safe mutex with more rich features.
package gmutex

import (
	"math"
	"runtime"

	"github.com/gogf/gf/g/container/gtype"
)

// The high level Mutex, which implements more rich features for mutex.
type Mutex struct {
	state   *gtype.Int32  // Indicates the state of mutex.
	writer  *gtype.Int32  // Pending writer count.
	reader  *gtype.Int32  // Pending reader count.
	writing chan struct{} // Channel used for writer blocking.
	reading chan struct{} // Channel used for reader blocking.
}

// New creates and returns a new mutex.
func New() *Mutex {
	return &Mutex{
		state:   gtype.NewInt32(),
		writer:  gtype.NewInt32(),
		reader:  gtype.NewInt32(),
		writing: make(chan struct{}, 1),
		reading: make(chan struct{}, math.MaxInt32),
	}
}

// Lock locks the mutex for writing.
// If the lock is already locked for reading or writing,
// Lock blocks until the lock is available.
func (m *Mutex) Lock() {
	for {
		// If there're no readers pending and writing lock currently,
		// then do the writing lock checks.
		if m.reader.Val() == 0 && m.state.Cas(0, -1) {
			return
		}
		m.writer.Add(1)
		<-m.writing
		m.writer.Add(-1)
	}
}

// Unlock unlocks the writing lock.
// It is safe to be called multiple times if there's any locks or not.
func (m *Mutex) Unlock() {
	if m.state.Cas(-1, 0) {
		// Writing lock unlocks, then first check the blocked readers.
		if n := m.reader.Val(); n > 0 {
			// If there're readers blocked, unlock them with preemption.
			for ; n > 0; n-- {
				m.reading <- struct{}{}
			}
			return
		}
		if m.writer.Val() > 0 {
			m.writing <- struct{}{}
		}
	}
}

// TryLock tries locking the mutex for writing.
// It returns true if success, or if there's a write/reading lock on the mutex,
// it returns false.
func (m *Mutex) TryLock() bool {
	if m.reader.Val() == 0 && m.state.Cas(0, -1) {
		return true
	}
	return false
}

// RLock locks mutex for reading.
// If the mutex is already locked for writing,
// It blocks until the lock is available.
func (m *Mutex) RLock() {
	var n int32
	for {
		// If there're no writing lock and pending writers currently,
		// then do the reading lock checks.
		if n = m.state.Val(); n >= 0 && m.writer.Val() == 0 {
			if m.state.Cas(n, n+1) {
				return
			} else {
				runtime.Gosched()
				continue
			}
		}
		// Or else pending the reader.
		m.reader.Add(1)
		<-m.reading
		m.reader.Add(-1)
	}
}

// RUnlock unlocks the reading lock.
// It is safe to be called multiple times if there's any locks or not.
func (m *Mutex) RUnlock() {
	var n int32
	for {
		if n = m.state.Val(); n >= 1 {
			if m.state.Cas(n, n-1) {
				break
			} else {
				runtime.Gosched()
			}
		} else {
			break
		}
	}
	// Reading lock unlocks, then first check the blocked writers.
	if n == 1 && m.writer.Val() > 0 {
		// No readers blocked, then the writers can take place.
		m.writing <- struct{}{}
		return
	}
}

// TryRLock tries locking the mutex for reading.
// It returns true if success, or if there's a writing lock on the mutex, it returns false.
func (m *Mutex) TryRLock() bool {
	var n int32
	for {
		if n = m.state.Val(); n >= 0 && m.writer.Val() == 0 {
			if m.state.Cas(n, n+1) {
				return true
			} else {
				runtime.Gosched()
			}
		} else {
			return false
		}
	}
}

// IsLocked checks whether the mutex is locked with writing or reading lock.
// Note that the result might be changed after it's called,
// so it cannot be the criterion for atomic operations.
func (m *Mutex) IsLocked() bool {
	return m.state.Val() != 0
}

// IsWLocked checks whether the mutex is locked by writing lock.
// Note that the result might be changed after it's called,
// so it cannot be the criterion for atomic operations.
func (m *Mutex) IsWLocked() bool {
	return m.state.Val() < 0
}

// IsRLocked checks whether the mutex is locked by reading lock.
// Note that the result might be changed after it's called,
// so it cannot be the criterion for atomic operations.
func (m *Mutex) IsRLocked() bool {
	return m.state.Val() > 0
}

// TryLockFunc tries locking the mutex for writing with given callback function <f>.
// it returns true if success, or if there's a write/reading lock on the mutex,
// it returns false.
//
// It releases the lock after <f> is executed.
func (m *Mutex) TryLockFunc(f func()) bool {
	if m.TryLock() {
		defer m.Unlock()
		f()
		return true
	}
	return false
}

// TryRLockFunc tries locking the mutex for reading with given callback function <f>.
// It returns true if success, or if there's a writing lock on the mutex, it returns false.
//
// It releases the lock after <f> is executed.
func (m *Mutex) TryRLockFunc(f func()) bool {
	if m.TryRLock() {
		defer m.RUnlock()
		f()
		return true
	}
	return false
}

// LockFunc locks the mutex for writing with given callback function <f>.
// If there's a write/reading lock the mutex, it will blocks until the lock is released.
//
// It releases the lock after <f> is executed.
func (m *Mutex) LockFunc(f func()) {
	m.Lock()
	defer m.Unlock()
	f()
}

// RLockFunc locks the mutex for reading with given callback function <f>.
// If there's a writing lock the mutex, it will blocks until the lock is released.
//
// It releases the lock after <f> is executed.
func (m *Mutex) RLockFunc(f func()) {
	m.RLock()
	defer m.RUnlock()
	f()
}
<|endoftext|>


<commit_before>package sparse

import (
	"math"
	"sort"

	"github.com/gonum/floats"
	"gonum.org/v1/gonum/mat"
)

var (
	_ Sparser    = (*VecCOO)(nil)
	_ mat.Matrix = (*VecCOO)(nil)
)

// VecCOO is a sparse vector format.  It implements the mat.Vector
// interface but is optimised for sparsely populated vectors where
// most of the elements contain zero values by only storing and
// processing the non-zero values.  The format is similar to the
// triplet format used by COO matrices (and CSR/CSC) but only uses
// 2 arrays because the vector is 1 dimensional rather than 2.
type VecCOO struct {
	len  int
	ind  []int
	data []float64
}

// NewVecCOO returns a new sparse vector of length len with
// elements specified by ind[] containing the values conatined
// within data.  VecCOO will reuse the same storage as the slices
// passed in and so any changes to the vector will be reflected
// in the slices and vice versa.
func NewVecCOO(len int, ind []int, data []float64) *VecCOO {
	return &VecCOO{
		len:  len,
		ind:  ind,
		data: data,
	}
}

// Dims returns the dimensions of the vector.  This will be
// equivalent to Len(), 1
func (v *VecCOO) Dims() (r, c int) {
	return v.len, 1
}

// At returns the element at r, c.  At will panic if c != 0.
func (v *VecCOO) At(r, c int) float64 {
	if c != 0 {
		panic(mat.ErrColAccess)
	}
	return v.AtVec(r)
}

// T returns the transpose of the receiver.
func (v *VecCOO) T() mat.Matrix {
	return mat.TransposeVec{Vector: v}
}

// NNZ returns the number of non-zero elements in the vector.
func (v *VecCOO) NNZ() int {
	return len(v.data)
}

// AtVec returns the i'th element of the Vector.
func (v *VecCOO) AtVec(i int) float64 {
	if i < 0 || i >= v.len {
		panic(mat.ErrRowAccess)
	}

	idx := sort.SearchInts(v.ind, i)
	if idx < len(v.ind) && v.ind[idx] == i {
		return v.data[idx]
	}

	// for j := 0; j < len(v.ind); j++ {
	// 	if v.ind[j] == i {
	// 		return v.data[j]
	// 	}
	// }
	return 0.0
}

// Len returns the length of the vector
func (v *VecCOO) Len() int {
	return v.len
}

// DoNonZero calls the function fn for each of the non-zero elements of the receiver.
// The function fn takes a row/column index and the element value of the receiver at
// (i, j).
func (v *VecCOO) DoNonZero(fn func(i int, j int, v float64)) {
	for i := 0; i < len(v.ind); i++ {
		fn(v.ind[i], 0, v.data[i])
	}
}

// AddVec adds the vectors a and b, placing the result in the receiver.
// AddVec will panic if a and b are not the same length.  If a and b
// are both sparse VecCOO vectors then AddVec will only process the
// non-zero elements.
func (v *VecCOO) AddVec(a, b mat.Vector) {
	ar := a.Len()
	br := b.Len()

	if ar != br {
		panic(mat.ErrShape)
	}

	v.len = ar

	// Sparse specific optimised implementation
	sa, aIsSparse := a.(*VecCOO)
	sb, bIsSparse := b.(*VecCOO)
	if aIsSparse && bIsSparse {
		v.addVecSparse(sa, 1, sb)
		return
	}

	// fallback to basic vector addition with no optimisations
	// for sparseness
	ind, data := v.createWorkspace(0, false)

	for i := 0; i < v.len; i++ {
		p := a.AtVec(i) + b.AtVec(i)
		if p != 0 {
			ind = append(ind, i)
			data = append(data, p)
		}
	}

	v.commitWorkspace(ind, data)
}

// addVecSparse adds the vectors a and alpha*b.  This method is
// optimised for processing sparse VecCOO vectors and only processes
// non-zero elements.
func (v *VecCOO) addVecSparse(a *VecCOO, alpha float64, b *VecCOO) {
	ind, data := v.createWorkspace(0, false)

	var i, j int
	for i < len(a.ind) && j < len(b.ind) {
		if a.ind[i] == b.ind[j] {
			s := b.data[j]
			if alpha != 1 {
				s = alpha * b.data[j]
			}
			ind = append(ind, a.ind[i])
			data = append(data, a.data[i]+s)
			i++
			j++
			continue
		}
		if a.ind[i] < b.ind[j] {
			var k int
			for k = i; k < len(a.ind) && a.ind[k] < b.ind[j]; k++ {
				ind = append(ind, a.ind[k])
				data = append(data, a.data[k])
			}
			i = k
			continue
		}
		if a.ind[i] > b.ind[j] {
			var k int
			for k = j; k < len(b.ind) && b.ind[k] < a.ind[i]; k++ {
				s := b.data[j]
				if alpha != 1 {
					s = alpha * b.data[j]
				}
				ind = append(ind, b.ind[k])
				data = append(data, s)
			}
			j = k
			continue
		}
	}
	for k := i; k < len(a.ind); k++ {
		ind = append(ind, a.ind[k])
		data = append(data, a.data[k])
	}
	for k := j; k < len(b.ind); k++ {
		s := b.data[j]
		if alpha != 1 {
			s = alpha * b.data[j]
		}
		ind = append(ind, b.ind[k])
		data = append(data, s)
	}

	v.commitWorkspace(ind, data)
}

// ScaleVec scales the vector a by alpha, placing the result in the
// receiver.
func (v *VecCOO) ScaleVec(alpha float64, a mat.Vector) {
	v.len = a.Len()
	ind, data := v.createWorkspace(0, false)

	for i := 0; i < v.len; i++ {
		val := a.AtVec(i)
		if val != 0 {
			ind = append(ind, i)
			data = append(data, alpha*val)
		}
	}
	v.commitWorkspace(ind, data)
}

// AddScaledVec adds the vectors a and alpha*b, placing the result
// in the receiver.  AddScaledVec will panic if a and b are not the
// same length.
func (v *VecCOO) AddScaledVec(a mat.Vector, alpha float64, b mat.Vector) {
	ar := a.Len()
	br := b.Len()

	if ar != br {
		panic(mat.ErrShape)
	}

	v.len = ar

	// Sparse specific optimised implementation
	sa, aIsSparse := a.(*VecCOO)
	sb, bIsSparse := b.(*VecCOO)
	if aIsSparse && bIsSparse {
		v.addVecSparse(sa, alpha, sb)
		return
	}

	ind, data := v.createWorkspace(0, false)

	for i := 0; i < v.len; i++ {
		val := a.AtVec(i) + alpha*b.AtVec(i)
		if val != 0 {
			ind = append(ind, i)
			data = append(data, val)
		}
	}
	v.commitWorkspace(ind, data)
}

// Norm calculates the Norm of the vector only processing the
// non-zero elements.
// See Normer interface for more details.
func (v *VecCOO) Norm(L float64) float64 {
	if L == 2 {
		twoNorm := math.Pow(math.Abs(v.data[0]), 2)
		for i := 1; i < len(v.data); i++ {
			twoNorm += math.Pow(v.data[i], 2)
		}
		return math.Sqrt(twoNorm)
	}
	return floats.Norm(v.data, L)
}

// Dot returns the sum of the element-wise product of a and b.
// Dot panics if the matrix sizes are unequal.  If both vectors
// are sparse VecCOO then Dot will only process non-zero elements
// otherwise this method simply delegates to mat.Dot()
func Dot(a, b mat.Vector) float64 {
	if av, ok := a.(*VecCOO); ok {
		if bv, ok := b.(*VecCOO); ok {
			la := a.Len()
			lb := b.Len()
			if la != lb {
				panic(mat.ErrShape)
			}
			return dotSparse(av, bv)
		}
	}
	return mat.Dot(a, b)
}

// dotSparse returns the sum of the element-wise product of a and
// b where a and b are both sparse VecCOO vectors.  dotSparse
// will only process non-zero elements in the vectors.
func dotSparse(a, b *VecCOO) float64 {
	var result float64
	var lhs, rhs *VecCOO

	if a.NNZ() < b.NNZ() {
		lhs, rhs = a, b
	} else {
		lhs, rhs = b, a
	}

	var j int
	for k := 0; k < len(lhs.ind); k++ {
		var bi int
		for bi = j; bi < len(rhs.ind) && rhs.ind[bi] < lhs.ind[k]; bi++ {
			// empty
		}
		j = bi
		if j >= len(rhs.ind) {
			break
		}
		if lhs.ind[k] == rhs.ind[bi] {
			result += lhs.data[k] * rhs.data[bi]
		}
	}

	return result
}

// createWorkspace creates a temporary workspace to store the result
// of vector operations avoiding the issue of mutating operands mid
// operation where they overlap with the receiver
// e.g.
//	result.AddVec(result, a)
// createWorkspace will attempt to reuse previously allocated memory
// for the temporary workspace where ever possible to avoid allocating
// memory and placing strain on GC.
func (v *VecCOO) createWorkspace(size int, zero bool) ([]int, []float64) {
	ind := getInts(size, zero)
	data := getFloats(size, zero)

	return ind, data
}

// commitWorkspace commits a temporary workspace previously created
// with createWorkspace.  This has the effect of updaing the receiver
// with the values from the temporary workspace and returning the
// memory used by the workspace to the pool for other operations to
// reuse.
func (v *VecCOO) commitWorkspace(indexes []int, data []float64) {
	v.ind, indexes = indexes, v.ind
	v.data, data = data, v.data
	putInts(indexes)
	putFloats(data)
}
<commit_msg>added optimisations to ScaleVec() method<commit_after>package sparse

import (
	"math"
	"sort"

	"github.com/gonum/floats"
	"gonum.org/v1/gonum/mat"
)

var (
	_ Sparser    = (*VecCOO)(nil)
	_ mat.Matrix = (*VecCOO)(nil)
)

// VecCOO is a sparse vector format.  It implements the mat.Vector
// interface but is optimised for sparsely populated vectors where
// most of the elements contain zero values by only storing and
// processing the non-zero values.  The format is similar to the
// triplet format used by COO matrices (and CSR/CSC) but only uses
// 2 arrays because the vector is 1 dimensional rather than 2.
type VecCOO struct {
	len  int
	ind  []int
	data []float64
}

// NewVecCOO returns a new sparse vector of length len with
// elements specified by ind[] containing the values conatined
// within data.  VecCOO will reuse the same storage as the slices
// passed in and so any changes to the vector will be reflected
// in the slices and vice versa.
func NewVecCOO(len int, ind []int, data []float64) *VecCOO {
	return &VecCOO{
		len:  len,
		ind:  ind,
		data: data,
	}
}

// Dims returns the dimensions of the vector.  This will be
// equivalent to Len(), 1
func (v *VecCOO) Dims() (r, c int) {
	return v.len, 1
}

// At returns the element at r, c.  At will panic if c != 0.
func (v *VecCOO) At(r, c int) float64 {
	if c != 0 {
		panic(mat.ErrColAccess)
	}
	return v.AtVec(r)
}

// T returns the transpose of the receiver.
func (v *VecCOO) T() mat.Matrix {
	return mat.TransposeVec{Vector: v}
}

// NNZ returns the number of non-zero elements in the vector.
func (v *VecCOO) NNZ() int {
	return len(v.data)
}

// AtVec returns the i'th element of the Vector.
func (v *VecCOO) AtVec(i int) float64 {
	if i < 0 || i >= v.len {
		panic(mat.ErrRowAccess)
	}

	idx := sort.SearchInts(v.ind, i)
	if idx < len(v.ind) && v.ind[idx] == i {
		return v.data[idx]
	}

	// for j := 0; j < len(v.ind); j++ {
	// 	if v.ind[j] == i {
	// 		return v.data[j]
	// 	}
	// }
	return 0.0
}

// Len returns the length of the vector
func (v *VecCOO) Len() int {
	return v.len
}

// DoNonZero calls the function fn for each of the non-zero elements of the receiver.
// The function fn takes a row/column index and the element value of the receiver at
// (i, j).
func (v *VecCOO) DoNonZero(fn func(i int, j int, v float64)) {
	for i := 0; i < len(v.ind); i++ {
		fn(v.ind[i], 0, v.data[i])
	}
}

// AddVec adds the vectors a and b, placing the result in the receiver.
// AddVec will panic if a and b are not the same length.  If a and b
// are both sparse VecCOO vectors then AddVec will only process the
// non-zero elements.
func (v *VecCOO) AddVec(a, b mat.Vector) {
	ar := a.Len()
	br := b.Len()

	if ar != br {
		panic(mat.ErrShape)
	}

	v.len = ar

	// Sparse specific optimised implementation
	sa, aIsSparse := a.(*VecCOO)
	sb, bIsSparse := b.(*VecCOO)
	if aIsSparse && bIsSparse {
		v.addVecSparse(sa, 1, sb)
		return
	}

	// fallback to basic vector addition with no optimisations
	// for sparseness
	ind, data := v.createWorkspace(0, false)

	for i := 0; i < v.len; i++ {
		p := a.AtVec(i) + b.AtVec(i)
		if p != 0 {
			ind = append(ind, i)
			data = append(data, p)
		}
	}

	v.commitWorkspace(ind, data)
}

// addVecSparse adds the vectors a and alpha*b.  This method is
// optimised for processing sparse VecCOO vectors and only processes
// non-zero elements.
func (v *VecCOO) addVecSparse(a *VecCOO, alpha float64, b *VecCOO) {
	ind, data := v.createWorkspace(0, false)

	var i, j int
	for i < len(a.ind) && j < len(b.ind) {
		if a.ind[i] == b.ind[j] {
			s := b.data[j]
			if alpha != 1 {
				s = alpha * b.data[j]
			}
			ind = append(ind, a.ind[i])
			data = append(data, a.data[i]+s)
			i++
			j++
			continue
		}
		if a.ind[i] < b.ind[j] {
			var k int
			for k = i; k < len(a.ind) && a.ind[k] < b.ind[j]; k++ {
				ind = append(ind, a.ind[k])
				data = append(data, a.data[k])
			}
			i = k
			continue
		}
		if a.ind[i] > b.ind[j] {
			var k int
			for k = j; k < len(b.ind) && b.ind[k] < a.ind[i]; k++ {
				s := b.data[j]
				if alpha != 1 {
					s = alpha * b.data[j]
				}
				ind = append(ind, b.ind[k])
				data = append(data, s)
			}
			j = k
			continue
		}
	}
	for k := i; k < len(a.ind); k++ {
		ind = append(ind, a.ind[k])
		data = append(data, a.data[k])
	}
	for k := j; k < len(b.ind); k++ {
		s := b.data[j]
		if alpha != 1 {
			s = alpha * b.data[j]
		}
		ind = append(ind, b.ind[k])
		data = append(data, s)
	}

	v.commitWorkspace(ind, data)
}

// ScaleVec scales the vector a by alpha, placing the result in the
// receiver.
func (v *VecCOO) ScaleVec(alpha float64, a mat.Vector) {
	v.len = a.Len()

	if alpha == 0 {
		v.ind = v.ind[:0]
		v.data = v.data[:0]
		return
	}

	if s, isSparse := a.(*VecCOO); isSparse {
		ind, data := v.createWorkspace(s.NNZ(), false)
		copy(ind, s.ind)
		for i, val := range s.data {
			data[i] = alpha * val
		}
		v.commitWorkspace(ind, data)
		return
	}

	ind, data := v.createWorkspace(0, false)

	for i := 0; i < v.len; i++ {
		val := a.AtVec(i)
		if val != 0 {
			ind = append(ind, i)
			data = append(data, alpha*val)
		}
	}
	v.commitWorkspace(ind, data)
}

// AddScaledVec adds the vectors a and alpha*b, placing the result
// in the receiver.  AddScaledVec will panic if a and b are not the
// same length.
func (v *VecCOO) AddScaledVec(a mat.Vector, alpha float64, b mat.Vector) {
	ar := a.Len()
	br := b.Len()

	if ar != br {
		panic(mat.ErrShape)
	}

	v.len = ar

	// Sparse specific optimised implementation
	sa, aIsSparse := a.(*VecCOO)
	sb, bIsSparse := b.(*VecCOO)
	if aIsSparse && bIsSparse {
		v.addVecSparse(sa, alpha, sb)
		return
	}

	ind, data := v.createWorkspace(0, false)

	for i := 0; i < v.len; i++ {
		val := a.AtVec(i) + alpha*b.AtVec(i)
		if val != 0 {
			ind = append(ind, i)
			data = append(data, val)
		}
	}
	v.commitWorkspace(ind, data)
}

// Norm calculates the Norm of the vector only processing the
// non-zero elements.
// See Normer interface for more details.
func (v *VecCOO) Norm(L float64) float64 {
	if L == 2 {
		twoNorm := math.Pow(math.Abs(v.data[0]), 2)
		for i := 1; i < len(v.data); i++ {
			twoNorm += math.Pow(v.data[i], 2)
		}
		return math.Sqrt(twoNorm)
	}
	return floats.Norm(v.data, L)
}

// Dot returns the sum of the element-wise product of a and b.
// Dot panics if the matrix sizes are unequal.  If both vectors
// are sparse VecCOO then Dot will only process non-zero elements
// otherwise this method simply delegates to mat.Dot()
func Dot(a, b mat.Vector) float64 {
	if av, ok := a.(*VecCOO); ok {
		if bv, ok := b.(*VecCOO); ok {
			la := a.Len()
			lb := b.Len()
			if la != lb {
				panic(mat.ErrShape)
			}
			return dotSparse(av, bv)
		}
	}
	return mat.Dot(a, b)
}

// dotSparse returns the sum of the element-wise product of a and
// b where a and b are both sparse VecCOO vectors.  dotSparse
// will only process non-zero elements in the vectors.
func dotSparse(a, b *VecCOO) float64 {
	var result float64
	var lhs, rhs *VecCOO

	if a.NNZ() < b.NNZ() {
		lhs, rhs = a, b
	} else {
		lhs, rhs = b, a
	}

	var j int
	for k := 0; k < len(lhs.ind); k++ {
		var bi int
		for bi = j; bi < len(rhs.ind) && rhs.ind[bi] < lhs.ind[k]; bi++ {
			// empty
		}
		j = bi
		if j >= len(rhs.ind) {
			break
		}
		if lhs.ind[k] == rhs.ind[bi] {
			result += lhs.data[k] * rhs.data[bi]
		}
	}

	return result
}

// createWorkspace creates a temporary workspace to store the result
// of vector operations avoiding the issue of mutating operands mid
// operation where they overlap with the receiver
// e.g.
//	result.AddVec(result, a)
// createWorkspace will attempt to reuse previously allocated memory
// for the temporary workspace where ever possible to avoid allocating
// memory and placing strain on GC.
func (v *VecCOO) createWorkspace(size int, zero bool) ([]int, []float64) {
	ind := getInts(size, zero)
	data := getFloats(size, zero)

	return ind, data
}

// commitWorkspace commits a temporary workspace previously created
// with createWorkspace.  This has the effect of updaing the receiver
// with the values from the temporary workspace and returning the
// memory used by the workspace to the pool for other operations to
// reuse.
func (v *VecCOO) commitWorkspace(indexes []int, data []float64) {
	v.ind, indexes = indexes, v.ind
	v.data, data = data, v.data
	putInts(indexes)
	putFloats(data)
}
<|endoftext|>


<commit_before>// Copyright (c) 2015, Daniel Martí <mvdan@mvdan.cc>
// See LICENSE for licensing information

package fdroidcl

import (
	"encoding/xml"
	"fmt"
	"io"
	"sort"
	"strings"

	"github.com/mvdan/fdroidcl/adb"
)

type Index struct {
	Repo Repo  `xml:"repo"`
	Apps []App `xml:"application"`
}

type Repo struct {
	Name        string `xml:"name,attr"`
	PubKey      string `xml:"pubkey,attr"`
	Timestamp   int    `xml:"timestamp,attr"`
	URL         string `xml:"url,attr"`
	Version     int    `xml:"version,attr"`
	MaxAge      int    `xml:"maxage,attr"`
	Description string `xml:"description"`
}

// App is an Android application
type App struct {
	ID        string    `xml:"id"`
	Name      string    `xml:"name"`
	Summary   string    `xml:"summary"`
	Added     DateVal   `xml:"added"`
	Updated   DateVal   `xml:"lastupdated"`
	Icon      string    `xml:"icon"`
	Desc      string    `xml:"desc"`
	License   string    `xml:"license"`
	Categs    CommaList `xml:"categories"`
	Website   string    `xml:"web"`
	Source    string    `xml:"source"`
	Tracker   string    `xml:"tracker"`
	Changelog string    `xml:"changelog"`
	Donate    string    `xml:"donate"`
	Bitcoin   string    `xml:"bitcoin"`
	Litecoin  string    `xml:"litecoin"`
	FlattrID  string    `xml:"flattr"`
	Apks      []Apk     `xml:"package"`
	CVName    string    `xml:"marketversion"`
	CVCode    int       `xml:"marketvercode"`
}

type IconDensity uint

const (
	UnknownDensity IconDensity = 0
	LowDensity     IconDensity = 120
	MediumDensity  IconDensity = 160
	HighDensity    IconDensity = 240
	XHighDensity   IconDensity = 320
	XXHighDensity  IconDensity = 480
	XXXHighDensity IconDensity = 640
)

func getIconsDir(density IconDensity) string {
	if density == UnknownDensity {
		return "icons"
	}
	for _, d := range [...]IconDensity{
		XXXHighDensity,
		XXHighDensity,
		XHighDensity,
		HighDensity,
		MediumDensity,
	} {
		if density >= d {
			return fmt.Sprintf("icons-%d", d)
		}
	}
	return fmt.Sprintf("icons-%d", LowDensity)
}

func (a *App) IconURLForDensity(density IconDensity) string {
	if len(a.Apks) == 0 {
		return ""
	}
	return fmt.Sprintf("%s/%s/%s", a.Apks[0].Repo.URL,
		getIconsDir(density), a.Icon)
}

func (a *App) IconURL() string {
	return a.IconURLForDensity(UnknownDensity)
}

func (a *App) TextDesc(w io.Writer) {
	reader := strings.NewReader(a.Desc)
	decoder := xml.NewDecoder(reader)
	firstParagraph := true
	linePrefix := ""
	colsUsed := 0
	var links []string
	linked := false
	for {
		token, err := decoder.Token()
		if err == io.EOF || token == nil {
			break
		}
		switch t := token.(type) {
		case xml.StartElement:
			switch t.Name.Local {
			case "p":
				if firstParagraph {
					firstParagraph = false
				} else {
					fmt.Fprintln(w)
				}
				linePrefix = ""
				colsUsed = 0
			case "li":
				fmt.Fprint(w, "\n *")
				linePrefix = "   "
				colsUsed = 0
			case "a":
				for _, attr := range t.Attr {
					if attr.Name.Local == "href" {
						links = append(links, attr.Value)
						linked = true
						break
					}
				}
			}
		case xml.EndElement:
			switch t.Name.Local {
			case "p", "ul", "ol":
				fmt.Fprintln(w)
			}
		case xml.CharData:
			left := string(t)
			if linked {
				left += fmt.Sprintf("[%d]", len(links)-1)
				linked = false
			}
			limit := 80 - len(linePrefix) - colsUsed
			firstLine := true
			for len(left) > limit {
				last := 0
				for i, c := range left {
					if i >= limit {
						break
					}
					if c == ' ' {
						last = i
					}
				}
				if firstLine {
					firstLine = false
					limit += colsUsed
				} else {
					fmt.Fprint(w, linePrefix)
				}
				fmt.Fprintln(w, left[:last])
				left = left[last+1:]
				colsUsed = 0
			}
			if !firstLine {
				fmt.Fprint(w, linePrefix)
			}
			fmt.Fprint(w, left)
			colsUsed += len(left)
		}
	}
	if len(links) > 0 {
		fmt.Fprintln(w)
		for i, link := range links {
			fmt.Fprintf(w, "[%d] %s\n", i, link)
		}
	}
}

// Apk is an Android package
type Apk struct {
	VName   string    `xml:"version"`
	VCode   int       `xml:"versioncode"`
	Size    int64     `xml:"size"`
	MinSdk  int       `xml:"sdkver"`
	MaxSdk  int       `xml:"maxsdkver"`
	ABIs    CommaList `xml:"nativecode"`
	ApkName string    `xml:"apkname"`
	SrcName string    `xml:"srcname"`
	Sig     HexVal    `xml:"sig"`
	Added   DateVal   `xml:"added"`
	Perms   CommaList `xml:"permissions"`
	Feats   CommaList `xml:"features"`
	Hash    HexHash   `xml:"hash"`

	App  *App  `xml:"-"`
	Repo *Repo `xml:"-"`
}

func (a *Apk) URL() string {
	return fmt.Sprintf("%s/%s", a.Repo.URL, a.ApkName)
}

func (a *Apk) SrcURL() string {
	return fmt.Sprintf("%s/%s", a.Repo.URL, a.SrcName)
}

func (apk *Apk) IsCompatibleABI(ABIs []string) bool {
	if len(apk.ABIs) == 0 {
		return true // APK does not contain native code
	}
	for _, apkABI := range apk.ABIs {
		for _, abi := range ABIs {
			if apkABI == abi {
				return true
			}
		}
	}
	return false
}

func (apk *Apk) IsCompatibleAPILevel(sdk int) bool {
	return sdk >= apk.MinSdk && (apk.MaxSdk == 0 || sdk <= apk.MaxSdk)
}

func (apk *Apk) IsCompatible(device *adb.Device) bool {
	if device == nil {
		return true
	}
	return apk.IsCompatibleABI(device.ABIs) &&
		apk.IsCompatibleAPILevel(device.APILevel)
}

type AppList []App

func (al AppList) Len() int           { return len(al) }
func (al AppList) Swap(i, j int)      { al[i], al[j] = al[j], al[i] }
func (al AppList) Less(i, j int) bool { return al[i].ID < al[j].ID }

type ApkList []Apk

func (al ApkList) Len() int           { return len(al) }
func (al ApkList) Swap(i, j int)      { al[i], al[j] = al[j], al[i] }
func (al ApkList) Less(i, j int) bool { return al[i].VCode > al[j].VCode }

func LoadIndexXML(r io.Reader) (*Index, error) {
	var index Index
	decoder := xml.NewDecoder(r)
	if err := decoder.Decode(&index); err != nil {
		return nil, err
	}

	sort.Sort(AppList(index.Apps))

	for i := range index.Apps {
		app := &index.Apps[i]
		sort.Sort(ApkList(app.Apks))
		for j := range app.Apks {
			apk := &app.Apks[j]
			apk.App = app
			apk.Repo = &index.Repo
		}
	}
	return &index, nil
}

func (a *App) SuggestedApk(device *adb.Device) *Apk {
	for i := range a.Apks {
		apk := &a.Apks[i]
		if a.CVCode >= apk.VCode && apk.IsCompatible(device) {
			return apk
		}
	}
	// fall back to the first compatible apk
	for i := range a.Apks {
		apk := &a.Apks[i]
		if apk.IsCompatible(device) {
			return apk
		}
	}
	return nil
}
<commit_msg>Be consistent about Apk receiver names<commit_after>// Copyright (c) 2015, Daniel Martí <mvdan@mvdan.cc>
// See LICENSE for licensing information

package fdroidcl

import (
	"encoding/xml"
	"fmt"
	"io"
	"sort"
	"strings"

	"github.com/mvdan/fdroidcl/adb"
)

type Index struct {
	Repo Repo  `xml:"repo"`
	Apps []App `xml:"application"`
}

type Repo struct {
	Name        string `xml:"name,attr"`
	PubKey      string `xml:"pubkey,attr"`
	Timestamp   int    `xml:"timestamp,attr"`
	URL         string `xml:"url,attr"`
	Version     int    `xml:"version,attr"`
	MaxAge      int    `xml:"maxage,attr"`
	Description string `xml:"description"`
}

// App is an Android application
type App struct {
	ID        string    `xml:"id"`
	Name      string    `xml:"name"`
	Summary   string    `xml:"summary"`
	Added     DateVal   `xml:"added"`
	Updated   DateVal   `xml:"lastupdated"`
	Icon      string    `xml:"icon"`
	Desc      string    `xml:"desc"`
	License   string    `xml:"license"`
	Categs    CommaList `xml:"categories"`
	Website   string    `xml:"web"`
	Source    string    `xml:"source"`
	Tracker   string    `xml:"tracker"`
	Changelog string    `xml:"changelog"`
	Donate    string    `xml:"donate"`
	Bitcoin   string    `xml:"bitcoin"`
	Litecoin  string    `xml:"litecoin"`
	FlattrID  string    `xml:"flattr"`
	Apks      []Apk     `xml:"package"`
	CVName    string    `xml:"marketversion"`
	CVCode    int       `xml:"marketvercode"`
}

type IconDensity uint

const (
	UnknownDensity IconDensity = 0
	LowDensity     IconDensity = 120
	MediumDensity  IconDensity = 160
	HighDensity    IconDensity = 240
	XHighDensity   IconDensity = 320
	XXHighDensity  IconDensity = 480
	XXXHighDensity IconDensity = 640
)

func getIconsDir(density IconDensity) string {
	if density == UnknownDensity {
		return "icons"
	}
	for _, d := range [...]IconDensity{
		XXXHighDensity,
		XXHighDensity,
		XHighDensity,
		HighDensity,
		MediumDensity,
	} {
		if density >= d {
			return fmt.Sprintf("icons-%d", d)
		}
	}
	return fmt.Sprintf("icons-%d", LowDensity)
}

func (a *App) IconURLForDensity(density IconDensity) string {
	if len(a.Apks) == 0 {
		return ""
	}
	return fmt.Sprintf("%s/%s/%s", a.Apks[0].Repo.URL,
		getIconsDir(density), a.Icon)
}

func (a *App) IconURL() string {
	return a.IconURLForDensity(UnknownDensity)
}

func (a *App) TextDesc(w io.Writer) {
	reader := strings.NewReader(a.Desc)
	decoder := xml.NewDecoder(reader)
	firstParagraph := true
	linePrefix := ""
	colsUsed := 0
	var links []string
	linked := false
	for {
		token, err := decoder.Token()
		if err == io.EOF || token == nil {
			break
		}
		switch t := token.(type) {
		case xml.StartElement:
			switch t.Name.Local {
			case "p":
				if firstParagraph {
					firstParagraph = false
				} else {
					fmt.Fprintln(w)
				}
				linePrefix = ""
				colsUsed = 0
			case "li":
				fmt.Fprint(w, "\n *")
				linePrefix = "   "
				colsUsed = 0
			case "a":
				for _, attr := range t.Attr {
					if attr.Name.Local == "href" {
						links = append(links, attr.Value)
						linked = true
						break
					}
				}
			}
		case xml.EndElement:
			switch t.Name.Local {
			case "p", "ul", "ol":
				fmt.Fprintln(w)
			}
		case xml.CharData:
			left := string(t)
			if linked {
				left += fmt.Sprintf("[%d]", len(links)-1)
				linked = false
			}
			limit := 80 - len(linePrefix) - colsUsed
			firstLine := true
			for len(left) > limit {
				last := 0
				for i, c := range left {
					if i >= limit {
						break
					}
					if c == ' ' {
						last = i
					}
				}
				if firstLine {
					firstLine = false
					limit += colsUsed
				} else {
					fmt.Fprint(w, linePrefix)
				}
				fmt.Fprintln(w, left[:last])
				left = left[last+1:]
				colsUsed = 0
			}
			if !firstLine {
				fmt.Fprint(w, linePrefix)
			}
			fmt.Fprint(w, left)
			colsUsed += len(left)
		}
	}
	if len(links) > 0 {
		fmt.Fprintln(w)
		for i, link := range links {
			fmt.Fprintf(w, "[%d] %s\n", i, link)
		}
	}
}

// Apk is an Android package
type Apk struct {
	VName   string    `xml:"version"`
	VCode   int       `xml:"versioncode"`
	Size    int64     `xml:"size"`
	MinSdk  int       `xml:"sdkver"`
	MaxSdk  int       `xml:"maxsdkver"`
	ABIs    CommaList `xml:"nativecode"`
	ApkName string    `xml:"apkname"`
	SrcName string    `xml:"srcname"`
	Sig     HexVal    `xml:"sig"`
	Added   DateVal   `xml:"added"`
	Perms   CommaList `xml:"permissions"`
	Feats   CommaList `xml:"features"`
	Hash    HexHash   `xml:"hash"`

	App  *App  `xml:"-"`
	Repo *Repo `xml:"-"`
}

func (a *Apk) URL() string {
	return fmt.Sprintf("%s/%s", a.Repo.URL, a.ApkName)
}

func (a *Apk) SrcURL() string {
	return fmt.Sprintf("%s/%s", a.Repo.URL, a.SrcName)
}

func (a *Apk) IsCompatibleABI(ABIs []string) bool {
	if len(a.ABIs) == 0 {
		return true // APK does not contain native code
	}
	for _, apkABI := range a.ABIs {
		for _, abi := range ABIs {
			if apkABI == abi {
				return true
			}
		}
	}
	return false
}

func (a *Apk) IsCompatibleAPILevel(sdk int) bool {
	return sdk >= a.MinSdk && (a.MaxSdk == 0 || sdk <= a.MaxSdk)
}

func (a *Apk) IsCompatible(device *adb.Device) bool {
	if device == nil {
		return true
	}
	return a.IsCompatibleABI(device.ABIs) &&
		a.IsCompatibleAPILevel(device.APILevel)
}

type AppList []App

func (al AppList) Len() int           { return len(al) }
func (al AppList) Swap(i, j int)      { al[i], al[j] = al[j], al[i] }
func (al AppList) Less(i, j int) bool { return al[i].ID < al[j].ID }

type ApkList []Apk

func (al ApkList) Len() int           { return len(al) }
func (al ApkList) Swap(i, j int)      { al[i], al[j] = al[j], al[i] }
func (al ApkList) Less(i, j int) bool { return al[i].VCode > al[j].VCode }

func LoadIndexXML(r io.Reader) (*Index, error) {
	var index Index
	decoder := xml.NewDecoder(r)
	if err := decoder.Decode(&index); err != nil {
		return nil, err
	}

	sort.Sort(AppList(index.Apps))

	for i := range index.Apps {
		app := &index.Apps[i]
		sort.Sort(ApkList(app.Apks))
		for j := range app.Apks {
			apk := &app.Apks[j]
			apk.App = app
			apk.Repo = &index.Repo
		}
	}
	return &index, nil
}

func (a *App) SuggestedApk(device *adb.Device) *Apk {
	for i := range a.Apks {
		apk := &a.Apks[i]
		if a.CVCode >= apk.VCode && apk.IsCompatible(device) {
			return apk
		}
	}
	// fall back to the first compatible apk
	for i := range a.Apks {
		apk := &a.Apks[i]
		if apk.IsCompatible(device) {
			return apk
		}
	}
	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/gob"
	"log"
	"sync"

	"github.com/khades/servbot/models"
	"github.com/khades/servbot/repos"
	"github.com/khades/servbot/services"
)

func main() {
	var wg sync.WaitGroup
	result, _ := repos.GetUsersID(&repos.Config.Channels)
	for _, value := range *result {
		repos.PushCommandsForChannel(&value)
	}

	repos.CreateChannels()
	wg.Add(1)
	go func() {
		services.CheckTwitchDJTrack()
		services.CheckStreamStatus()
		// 	services.CheckDubTrack()
	}()

	gob.Register(&models.HTTPSession{})
	log.Println("Starting...")
	services.CheckVK()
	// ticker := time.NewTicker(time.Second * 15)

	// go func(wg *sync.WaitGroup) {
	// 	for {
	// 		<-ticker.C
	// 		wg.Add(1)
	// 		bot.IrcClientInstance.SendModsCommand()
	// 		services.SendAutoMessages()
	// 		wg.Done()
	// 	}
	// }(&wg)

	// thirtyTicker := time.NewTicker(time.Second * 30)
	// go func(wg *sync.WaitGroup) {
	// 	for {
	// 		<-thirtyTicker.C
	// 		wg.Add(1)
	// 		services.CheckTwitchDJTrack()
	// 		wg.Done()
	// 	}
	// }(&wg)

	// // go func(wg *sync.WaitGroup) {
	// // 	for {
	// // 		<-thirtyTicker.C
	// // 		wg.Add(1)
	// // 		services.CheckDubTrack()
	// // 		wg.Done()
	// // 	}
	// // }(&wg)
	// twentyticker := time.NewTicker(time.Second * 20)

	// go func() {
	// 	for {
	// 		<-twentyticker.C
	// 		eventbus.EventBus.Trigger("ping")
	// 	}
	// }()

	// vkTimer := time.NewTicker(time.Second * 60)

	// go func() {
	// 	for {
	// 		<-vkTimer.C
	// 		services.CheckVK()
	// 	}
	// }()
	// minuteTicker := time.NewTicker(time.Minute)

	// go func(wg *sync.WaitGroup) {
	// 	for {
	// 		<-minuteTicker.C
	// 		wg.Add(1)
	// 		services.CheckStreamStatus()
	// 		wg.Done()
	// 	}
	// }(&wg)

	// go func(wg *sync.WaitGroup) {
	// 	httpbackend.Start()
	// 	wg.Done()
	// }(&wg)
	// followerTicker := time.NewTicker(time.Second * 30)

	// go func(wg *sync.WaitGroup) {
	// 	for {
	// 		<-followerTicker.C
	// 		wg.Add(1)
	// 		services.CheckChannelsFollowers()
	// 		wg.Done()
	// 	}
	// }(&wg)
	// go func(wg *sync.WaitGroup) {
	// 	bot.Start()
	// 	wg.Done()
	// }(&wg)

	// wg.Wait()
	log.Println("Quitting...")

}
<commit_msg>Fix: i accidently broke whole bot<commit_after>package main

import (
	"encoding/gob"
	"log"
	"sync"
	"time"

	"github.com/khades/servbot/bot"
	"github.com/khades/servbot/eventbus"
	"github.com/khades/servbot/httpbackend"
	"github.com/khades/servbot/models"
	"github.com/khades/servbot/repos"
	"github.com/khades/servbot/services"
)

func main() {
	var wg sync.WaitGroup
	result, _ := repos.GetUsersID(&repos.Config.Channels)
	for _, value := range *result {
		repos.PushCommandsForChannel(&value)
	}

	repos.CreateChannels()
	wg.Add(1)
	go func() {
		services.CheckTwitchDJTrack()
		services.CheckStreamStatus()
		// 	services.CheckDubTrack()
	}()

	gob.Register(&models.HTTPSession{})
	log.Println("Starting...")

	ticker := time.NewTicker(time.Second * 15)

	go func(wg *sync.WaitGroup) {
		for {
			<-ticker.C
			wg.Add(1)
			bot.IrcClientInstance.SendModsCommand()
			services.SendAutoMessages()
			wg.Done()
		}
	}(&wg)

	thirtyTicker := time.NewTicker(time.Second * 30)
	go func(wg *sync.WaitGroup) {
		for {
			<-thirtyTicker.C
			wg.Add(1)
			services.CheckTwitchDJTrack()
			wg.Done()
		}
	}(&wg)

	// go func(wg *sync.WaitGroup) {
	// 	for {
	// 		<-thirtyTicker.C
	// 		wg.Add(1)
	// 		services.CheckDubTrack()
	// 		wg.Done()
	// 	}
	// }(&wg)
	twentyticker := time.NewTicker(time.Second * 20)

	go func() {
		for {
			<-twentyticker.C
			eventbus.EventBus.Trigger("ping")
		}
	}()

	vkTimer := time.NewTicker(time.Second * 60)

	go func() {
		for {
			<-vkTimer.C
			services.CheckVK()
		}
	}()
	minuteTicker := time.NewTicker(time.Minute)

	go func(wg *sync.WaitGroup) {
		for {
			<-minuteTicker.C
			wg.Add(1)
			services.CheckStreamStatus()
			wg.Done()
		}
	}(&wg)

	go func(wg *sync.WaitGroup) {
		httpbackend.Start()
		wg.Done()
	}(&wg)
	followerTicker := time.NewTicker(time.Second * 30)

	go func(wg *sync.WaitGroup) {
		for {
			<-followerTicker.C
			wg.Add(1)
			services.CheckChannelsFollowers()
			wg.Done()
		}
	}(&wg)
	go func(wg *sync.WaitGroup) {
		bot.Start()
		wg.Done()
	}(&wg)

	wg.Wait()
	log.Println("Quitting...")

}
<|endoftext|>


<commit_before>package policy

import (
	"fmt"
	"github.com/Aptomi/aptomi/pkg/lang"
	"github.com/Aptomi/aptomi/pkg/runtime"
	"github.com/Aptomi/aptomi/pkg/runtime/codec/yaml"
	"github.com/mattn/go-zglob"
	"io/ioutil"
	"os"
	"path/filepath"
	"sort"
)

func readFiles(policyPaths []string) ([]runtime.Object, error) {
	policyReg := runtime.NewRegistry().Append(lang.PolicyObjects...)
	codec := yaml.NewCodec(policyReg)

	files, err := findPolicyFiles(policyPaths)
	if err != nil {
		return nil, fmt.Errorf("error while searching for policy files: %s", err)
	}

	allObjects := make([]runtime.Object, 0)
	for _, file := range files {
		data, readErr := ioutil.ReadFile(file)
		if readErr != nil {
			return nil, fmt.Errorf("can't read file %s error: %s", file, readErr)
		}

		objects, decodeErr := codec.DecodeOneOrMany(data)
		if decodeErr != nil {
			return nil, fmt.Errorf("can't unmarshal file %s error: %s", file, decodeErr)
		}

		for _, obj := range objects {
			if !lang.IsPolicyObject(obj) {
				return nil, fmt.Errorf("only policy objects could be applied but got: %s", obj.GetKind())
			}
		}

		allObjects = append(allObjects, objects...)
	}

	if len(allObjects) == 0 {
		return nil, fmt.Errorf("no objects found in %s", policyPaths)
	}

	return allObjects, nil
}

func findPolicyFiles(policyPaths []string) ([]string, error) {
	allFiles := make([]string, 0, len(policyPaths))

	for _, rawPolicyPath := range policyPaths {
		policyPath, errPath := filepath.Abs(rawPolicyPath)
		if errPath != nil {
			return nil, fmt.Errorf("error reading filepath: %s", errPath)
		}

		if stat, err := os.Stat(policyPath); err == nil {
			if stat.IsDir() { // if dir provided, use all yaml files from it
				files, errGlob := zglob.Glob(filepath.Join(policyPath, "**", "*.yaml"))
				if errGlob != nil {
					return nil, fmt.Errorf("error while searching yaml files in directory: %s error: %s", policyPath, err)
				}
				allFiles = append(allFiles, files...)
			} else { // if specific file provided, use it
				allFiles = append(allFiles, policyPath)
			}
		} else if os.IsNotExist(err) {
			return nil, fmt.Errorf("path doesn't exist: %s error: %s", policyPath, err)
		} else {
			return nil, fmt.Errorf("error while processing path: %s", err)
		}
	}

	sort.Strings(allFiles)

	// todo(slukjanov): log list of files from which we're applying policy
	//fmt.Println("Apply policy from following files:")
	//for idx, policyPath := range allFiles {
	//	fmt.Println(idx, "-", policyPath)
	//}

	return allFiles, nil
}
<commit_msg>more explicit error if user forgot to specify "-f" in CLI<commit_after>package policy

import (
	"fmt"
	"github.com/Aptomi/aptomi/pkg/lang"
	"github.com/Aptomi/aptomi/pkg/runtime"
	"github.com/Aptomi/aptomi/pkg/runtime/codec/yaml"
	"github.com/mattn/go-zglob"
	"io/ioutil"
	"os"
	"path/filepath"
	"sort"
)

func readFiles(policyPaths []string) ([]runtime.Object, error) {
	if len(policyPaths) <= 0 {
		return nil, fmt.Errorf("policy file path is not specified")
	}

	policyReg := runtime.NewRegistry().Append(lang.PolicyObjects...)
	codec := yaml.NewCodec(policyReg)

	files, err := findPolicyFiles(policyPaths)
	if err != nil {
		return nil, fmt.Errorf("error while searching for policy files: %s", err)
	}

	allObjects := make([]runtime.Object, 0)
	for _, file := range files {
		data, readErr := ioutil.ReadFile(file)
		if readErr != nil {
			return nil, fmt.Errorf("can't read file %s error: %s", file, readErr)
		}

		objects, decodeErr := codec.DecodeOneOrMany(data)
		if decodeErr != nil {
			return nil, fmt.Errorf("can't unmarshal file %s error: %s", file, decodeErr)
		}

		for _, obj := range objects {
			if !lang.IsPolicyObject(obj) {
				return nil, fmt.Errorf("only policy objects could be applied but got: %s", obj.GetKind())
			}
		}

		allObjects = append(allObjects, objects...)
	}

	if len(allObjects) == 0 {
		return nil, fmt.Errorf("no objects found in %s", policyPaths)
	}

	return allObjects, nil
}

func findPolicyFiles(policyPaths []string) ([]string, error) {
	allFiles := make([]string, 0, len(policyPaths))

	for _, rawPolicyPath := range policyPaths {
		policyPath, errPath := filepath.Abs(rawPolicyPath)
		if errPath != nil {
			return nil, fmt.Errorf("error reading filepath: %s", errPath)
		}

		if stat, err := os.Stat(policyPath); err == nil {
			if stat.IsDir() { // if dir provided, use all yaml files from it
				files, errGlob := zglob.Glob(filepath.Join(policyPath, "**", "*.yaml"))
				if errGlob != nil {
					return nil, fmt.Errorf("error while searching yaml files in directory: %s error: %s", policyPath, err)
				}
				allFiles = append(allFiles, files...)
			} else { // if specific file provided, use it
				allFiles = append(allFiles, policyPath)
			}
		} else if os.IsNotExist(err) {
			return nil, fmt.Errorf("path doesn't exist: %s error: %s", policyPath, err)
		} else {
			return nil, fmt.Errorf("error while processing path: %s", err)
		}
	}

	sort.Strings(allFiles)

	// todo(slukjanov): log list of files from which we're applying policy
	//fmt.Println("Apply policy from following files:")
	//for idx, policyPath := range allFiles {
	//	fmt.Println(idx, "-", policyPath)
	//}

	return allFiles, nil
}
<|endoftext|>


<commit_before>package main

import "testing"

func TestGetFileName(t *testing.T) {
	testCases := []struct {
		filePath string
		expected string
	}{
		{
			filePath: "some/path/here.php",
			expected: "here.go",
		},

		{
			filePath: "some/path/here.java",
			expected: "",
		},
		{
			filePath: "some/error/path/here",
			expected: "",
		},
		{
			filePath: "some/error/path/here/",
			expected: "",
		},
	}

	for index, testCase := range testCases {
		result := convertFileName(testCase.filePath)
		if result != testCase.expected {
			t.Errorf("result = %+v , expected = %+v, at index = %+v\n", result, testCase.expected, index)
		}
	}
}
<commit_msg>fix test function name<commit_after>package main

import "testing"

func TestConvertFileName(t *testing.T) {
	testCases := []struct {
		filePath string
		expected string
	}{
		{
			filePath: "some/path/here.php",
			expected: "here.go",
		},

		{
			filePath: "some/path/here.java",
			expected: "",
		},
		{
			filePath: "some/error/path/here",
			expected: "",
		},
		{
			filePath: "some/error/path/here/",
			expected: "",
		},
	}

	for index, testCase := range testCases {
		result := convertFileName(testCase.filePath)
		if result != testCase.expected {
			t.Errorf("result = %+v , expected = %+v, at index = %+v\n", result, testCase.expected, index)
		}
	}
}
<|endoftext|>


<commit_before>// Copyright 2017 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// The go-contrib-init command helps new Go contributors get their development
// environment set up for the Go contribution process.
//
// It aims to be a complement or alternative to https://golang.org/doc/contribute.html.
package main

import (
	"bytes"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"runtime"
	"strings"
)

var (
	repo = flag.String("repo", "go", "Which go repo you want to contribute to. Use \"go\" for the core, or e.g. \"net\" for golang.org/x/net/*")
	dry  = flag.Bool("dry-run", false, "Fail with problems instead of trying to fix things.")
)

func main() {
	log.SetFlags(0)
	flag.Parse()

	checkCLA()
	checkGoroot()
	checkWorkingDir()
	checkGitOrigin()
	checkGitCodeReview()
}

func checkCLA() {
	slurp, err := ioutil.ReadFile(cookiesFile())
	if err != nil && !os.IsNotExist(err) {
		log.Fatal(err)
	}
	if bytes.Contains(slurp, []byte("go.googlesource.com")) &&
		bytes.Contains(slurp, []byte("go-review.googlesource.com")) {
		// Probably good.
		return
	}
	log.Fatal("Your .gitcookies file isn't configured.\n" +
		"Next steps:\n" +
		"  * Submit a CLA (https://golang.org/doc/contribute.html#cla) if not done\n" +
		"  * Go to https://go.googlesource.com/ and click \"Generate Password\" at the top,\n" +
		"    then follow instructions.\n" +
		"  * Run go-contrib-init again.\n")
}

func cookiesFile() string {
	if runtime.GOOS == "windows" {
		return filepath.Join(os.Getenv("USERPROFILE"), ".gitcookies")
	}
	return filepath.Join(os.Getenv("HOME"), ".gitcookies")
}

func checkGoroot() {
	v := os.Getenv("GOROOT")
	if v == "" {
		return
	}
	if *repo == "go" {
		if strings.HasPrefix(v, "/usr/") {
			log.Fatalf("Your GOROOT environment variable is set to %q\n"+
				"This is almost certainly not what you want. Either unset\n"+
				"your GOROOT or set it to the path of your development version\n"+
				"of Go.", v)
		}
		slurp, err := ioutil.ReadFile(filepath.Join(v, "VERSION"))
		if err == nil {
			slurp = bytes.TrimSpace(slurp)
			log.Fatalf("Your GOROOT environment variable is set to %q\n"+
				"But that path is to a binary release of Go, with VERSION file %q.\n"+
				"You should hack on Go in a fresh checkout of Go. Fix or unset your GOROOT.\n",
				v, slurp)
		}
	}
}

func checkWorkingDir() {
	// TODO
}

// mostly check that they didn't clone from github
func checkGitOrigin() {
	if _, err := exec.LookPath("git"); err != nil {
		log.Fatalf("You don't appear to have git installed. Do that.")
	}
	wantRemote := "https://go.googlesource.com/" + *repo
	remotes, err := exec.Command("git", "remote", "-v").Output()
	if err != nil {
		msg := cmdErr(err)
		if strings.Contains(msg, "Not a git repository") {
			log.Fatalf("Your current directory is not in a git checkout of %s", wantRemote)
		}
		log.Fatalf("Error running git remote -v: %v", msg)
	}
	matches := 0
	for _, line := range strings.Split(string(remotes), "\n") {
		line = strings.TrimSpace(line)
		if !strings.HasPrefix(line, "origin") {
			continue
		}
		if !strings.Contains(line, wantRemote) {
			curRemote := strings.Fields(strings.TrimPrefix(line, "origin"))[0]
			// TODO: if not in dryRun mode, just fix it?
			log.Fatalf("Current directory's git was cloned from %q; origin should be %q", curRemote, wantRemote)
		}
		matches++
	}
	if matches == 0 {
		log.Fatalf("git remote -v output didn't contain expected %q. Got:\n%s", wantRemote, remotes)
	}
}

func cmdErr(err error) string {
	if ee, ok := err.(*exec.ExitError); ok && len(ee.Stderr) > 0 {
		return fmt.Sprintf("%s: %s", err, ee.Stderr)
	}
	return fmt.Sprint(err)
}

func checkGitCodeReview() {
	if _, err := exec.LookPath("git-codereview"); err != nil {
		if *dry {
			log.Fatalf("You don't appear to have git-codereview tool. While this is technically optional,\n" +
				"almost all Go contributors use it. Our documentation and this tool assume it is used.\n" +
				"To install it, run:\n\n\t$ go get golang.org/x/review/git-codereview\n\n(Then run go-contrib-init again)")
		}
		err := exec.Command("go", "get", "golang.org/x/review/git-codereview").Run()
		if err != nil {
			log.Printf("Error running go get golang.org/x/review/git-codereview: %v", cmdErr(err))
		}
	}
	if *dry {
		// TODO: check the aliases. For now, just return.
		return
	}
	for _, cmd := range []string{"change", "gofmt", "mail", "pending", "submit", "sync"} {
		err := exec.Command("git", "config", "alias."+cmd, "codereview "+cmd).Run()
		if err != nil {
			log.Fatalf("Error setting alias.%s: %v", cmd, cmdErr(err))
		}
	}

}
<commit_msg>cmd/go-contrib-init: add git alias dry run mode, add success message<commit_after>// Copyright 2017 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// The go-contrib-init command helps new Go contributors get their development
// environment set up for the Go contribution process.
//
// It aims to be a complement or alternative to https://golang.org/doc/contribute.html.
package main

import (
	"bytes"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"runtime"
	"strings"
)

var (
	repo = flag.String("repo", "go", "Which go repo you want to contribute to. Use \"go\" for the core, or e.g. \"net\" for golang.org/x/net/*")
	dry  = flag.Bool("dry-run", false, "Fail with problems instead of trying to fix things.")
)

func main() {
	log.SetFlags(0)
	flag.Parse()

	checkCLA()
	checkGoroot()
	checkWorkingDir()
	checkGitOrigin()
	checkGitCodeReview()
	fmt.Print("All good. Happy hacking!\n" +
		"Remember to squash your revised commits and preserve the magic Change-Id lines.\n" +
		"Next steps: https://golang.org/doc/contribute.html#commit_changes\n")
}

func checkCLA() {
	slurp, err := ioutil.ReadFile(cookiesFile())
	if err != nil && !os.IsNotExist(err) {
		log.Fatal(err)
	}
	if bytes.Contains(slurp, []byte("go.googlesource.com")) &&
		bytes.Contains(slurp, []byte("go-review.googlesource.com")) {
		// Probably good.
		return
	}
	log.Fatal("Your .gitcookies file isn't configured.\n" +
		"Next steps:\n" +
		"  * Submit a CLA (https://golang.org/doc/contribute.html#cla) if not done\n" +
		"  * Go to https://go.googlesource.com/ and click \"Generate Password\" at the top,\n" +
		"    then follow instructions.\n" +
		"  * Run go-contrib-init again.\n")
}

func cookiesFile() string {
	if runtime.GOOS == "windows" {
		return filepath.Join(os.Getenv("USERPROFILE"), ".gitcookies")
	}
	return filepath.Join(os.Getenv("HOME"), ".gitcookies")
}

func checkGoroot() {
	v := os.Getenv("GOROOT")
	if v == "" {
		return
	}
	if *repo == "go" {
		if strings.HasPrefix(v, "/usr/") {
			log.Fatalf("Your GOROOT environment variable is set to %q\n"+
				"This is almost certainly not what you want. Either unset\n"+
				"your GOROOT or set it to the path of your development version\n"+
				"of Go.", v)
		}
		slurp, err := ioutil.ReadFile(filepath.Join(v, "VERSION"))
		if err == nil {
			slurp = bytes.TrimSpace(slurp)
			log.Fatalf("Your GOROOT environment variable is set to %q\n"+
				"But that path is to a binary release of Go, with VERSION file %q.\n"+
				"You should hack on Go in a fresh checkout of Go. Fix or unset your GOROOT.\n",
				v, slurp)
		}
	}
}

func checkWorkingDir() {
	// TODO
}

// mostly check that they didn't clone from github
func checkGitOrigin() {
	if _, err := exec.LookPath("git"); err != nil {
		log.Fatalf("You don't appear to have git installed. Do that.")
	}
	wantRemote := "https://go.googlesource.com/" + *repo
	remotes, err := exec.Command("git", "remote", "-v").Output()
	if err != nil {
		msg := cmdErr(err)
		if strings.Contains(msg, "Not a git repository") {
			log.Fatalf("Your current directory is not in a git checkout of %s", wantRemote)
		}
		log.Fatalf("Error running git remote -v: %v", msg)
	}
	matches := 0
	for _, line := range strings.Split(string(remotes), "\n") {
		line = strings.TrimSpace(line)
		if !strings.HasPrefix(line, "origin") {
			continue
		}
		if !strings.Contains(line, wantRemote) {
			curRemote := strings.Fields(strings.TrimPrefix(line, "origin"))[0]
			// TODO: if not in dryRun mode, just fix it?
			log.Fatalf("Current directory's git was cloned from %q; origin should be %q", curRemote, wantRemote)
		}
		matches++
	}
	if matches == 0 {
		log.Fatalf("git remote -v output didn't contain expected %q. Got:\n%s", wantRemote, remotes)
	}
}

func cmdErr(err error) string {
	if ee, ok := err.(*exec.ExitError); ok && len(ee.Stderr) > 0 {
		return fmt.Sprintf("%s: %s", err, ee.Stderr)
	}
	return fmt.Sprint(err)
}

func checkGitCodeReview() {
	if _, err := exec.LookPath("git-codereview"); err != nil {
		if *dry {
			log.Fatalf("You don't appear to have git-codereview tool. While this is technically optional,\n" +
				"almost all Go contributors use it. Our documentation and this tool assume it is used.\n" +
				"To install it, run:\n\n\t$ go get golang.org/x/review/git-codereview\n\n(Then run go-contrib-init again)")
		}
		err := exec.Command("go", "get", "golang.org/x/review/git-codereview").Run()
		if err != nil {
			log.Printf("Error running go get golang.org/x/review/git-codereview: %v", cmdErr(err))
		}
		log.Printf("Installed git-codereview (ran `go get golang.org/x/review/git-codereview`)")
	}
	missing := false
	for _, cmd := range []string{"change", "gofmt", "mail", "pending", "submit", "sync"} {
		v, _ := exec.Command("git", "config", "alias."+cmd).Output()
		if strings.Contains(string(v), "codereview") {
			continue
		}
		if *dry {
			log.Printf("Missing alias. Run:\n\t$ git config alias.%s \"codereview %s\"", cmd, cmd)
			missing = true
		} else {
			err := exec.Command("git", "config", "alias."+cmd, "codereview "+cmd).Run()
			if err != nil {
				log.Fatalf("Error setting alias.%s: %v", cmd, cmdErr(err))
			}
		}
	}
	if missing {
		log.Fatalf("Missing aliases. (While optional, this tool assumes you use them.)")
	}
}
<|endoftext|>


<commit_before>package healthcheck

import (
	"errors"
	"fmt"
	"net/http"
	"os"
	"time"

	"github.com/containous/traefik/v2/pkg/cli"
	"github.com/containous/traefik/v2/pkg/config/static"
)

// NewCmd builds a new HealthCheck command.
func NewCmd(traefikConfiguration *static.Configuration, loaders []cli.ResourceLoader) *cli.Command {
	return &cli.Command{
		Name:          "healthcheck",
		Description:   `Calls Traefik /ping endpoint (disabled by default) to check the health of Traefik.`,
		Configuration: traefikConfiguration,
		Run:           runCmd(traefikConfiguration),
		Resources:     loaders,
	}
}

func runCmd(traefikConfiguration *static.Configuration) func(_ []string) error {
	return func(_ []string) error {
		traefikConfiguration.SetEffectiveConfiguration()

		resp, errPing := Do(*traefikConfiguration)
		if resp != nil {
			resp.Body.Close()
		}
		if errPing != nil {
			fmt.Printf("Error calling healthcheck: %s\n", errPing)
			os.Exit(1)
		}

		if resp.StatusCode != http.StatusOK {
			fmt.Printf("Bad healthcheck status: %s\n", resp.Status)
			os.Exit(1)
		}
		fmt.Printf("OK: %s\n", resp.Request.URL)
		os.Exit(0)
		return nil
	}
}

// Do try to do a healthcheck
func Do(staticConfiguration static.Configuration) (*http.Response, error) {
	if staticConfiguration.Ping == nil {
		return nil, errors.New("please enable `ping` to use health check")
	}

	pingEntryPoint, ok := staticConfiguration.EntryPoints["traefik"]
	if !ok {
		return nil, errors.New("missing `ping` entrypoint")
	}

	client := &http.Client{Timeout: 5 * time.Second}
	protocol := "http"

	// FIXME Handle TLS on ping etc...
	// if pingEntryPoint.TLS != nil {
	// 	protocol = "https"
	// 	tr := &http.Transport{
	// 		TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
	// 	}
	// 	client.Transport = tr
	// }

	path := "/"

	return client.Head(protocol + "://" + pingEntryPoint.Address + path + "ping")
}
<commit_msg>Uses, if it exists, the ping entry point provided in the static configuration<commit_after>package healthcheck

import (
	"errors"
	"fmt"
	"net/http"
	"os"
	"time"

	"github.com/containous/traefik/v2/pkg/cli"
	"github.com/containous/traefik/v2/pkg/config/static"
)

// NewCmd builds a new HealthCheck command.
func NewCmd(traefikConfiguration *static.Configuration, loaders []cli.ResourceLoader) *cli.Command {
	return &cli.Command{
		Name:          "healthcheck",
		Description:   `Calls Traefik /ping endpoint (disabled by default) to check the health of Traefik.`,
		Configuration: traefikConfiguration,
		Run:           runCmd(traefikConfiguration),
		Resources:     loaders,
	}
}

func runCmd(traefikConfiguration *static.Configuration) func(_ []string) error {
	return func(_ []string) error {
		traefikConfiguration.SetEffectiveConfiguration()

		resp, errPing := Do(*traefikConfiguration)
		if resp != nil {
			resp.Body.Close()
		}
		if errPing != nil {
			fmt.Printf("Error calling healthcheck: %s\n", errPing)
			os.Exit(1)
		}

		if resp.StatusCode != http.StatusOK {
			fmt.Printf("Bad healthcheck status: %s\n", resp.Status)
			os.Exit(1)
		}
		fmt.Printf("OK: %s\n", resp.Request.URL)
		os.Exit(0)
		return nil
	}
}

// Do try to do a healthcheck
func Do(staticConfiguration static.Configuration) (*http.Response, error) {
	if staticConfiguration.Ping == nil {
		return nil, errors.New("please enable `ping` to use health check")
	}

	ep := staticConfiguration.Ping.EntryPoint
	if ep == "" {
		ep = "traefik"
	}

	pingEntryPoint, ok := staticConfiguration.EntryPoints[ep]
	if !ok {
		return nil, fmt.Errorf("ping: missing %s entry point", ep)
	}

	client := &http.Client{Timeout: 5 * time.Second}
	protocol := "http"

	// FIXME Handle TLS on ping etc...
	// if pingEntryPoint.TLS != nil {
	// 	protocol = "https"
	// 	tr := &http.Transport{
	// 		TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
	// 	}
	// 	client.Transport = tr
	// }

	path := "/"

	return client.Head(protocol + "://" + pingEntryPoint.Address + path + "ping")
}
<|endoftext|>