<commit_before>package algoliasearch

// Client is a representation of an Algolia application. Once initialized it
// allows manipulations over the indexes of the application as well as network
// related parameters.
type Client interface {
	// SetExtraHeader allows to set custom headers while reaching out to
	// Algolia servers.
	SetExtraHeader(key, value string)

	// SetTimeout specifies timeouts to use with the HTTP connection.
	SetTimeout(connectTimeout, readTimeout int)

	// ListIndexes returns the list of all indexes belonging to this Algolia
	// application.
	ListIndexes() (indexes []IndexRes, err error)

	// InitIndex returns an Index object targeting `name`.
	InitIndex(name string) Index

	// ListKeys returns all the API keys available for this Algolia
	// application.
	ListKeys() (keys []Key, err error)

	// MoveIndex renames the index named `source` as `destination`.
	MoveIndex(source, destination string) (UpdateTaskRes, error)

	// CopyIndex duplicates the index named `source` as `destination`.
	CopyIndex(source, destination string) (UpdateTaskRes, error)

	// AddKey creates a new API key from the supplied `ACL` and the specified
	// optional parameters. More details here:
	// https://www.algolia.com/doc/rest#add-a-global-api-key
	AddKey(ACL []string, params Map) (res AddKeyRes, err error)

	// UpdateKey updates the API key identified by its value `key` with the
	// given parameters.
	UpdateKey(key string, params Map) (res UpdateKeyRes, err error)

	// GetKey returns the key identified by its value `key`.
	GetKey(key string) (res Key, err error)

	// DeleteKey deletes the API key identified by its `key`.
	DeleteKey(key string) (res DeleteRes, err error)

	// GetLogs retrieves the logs according to the given `params` map which can
	// contain the following fields:
	//   - `length` (number of entries to retrieve)
	//   - `offset` (offset to the first entry)
	//   - `type` (type of logs to retrieve, can be "all", "query", "build" or
	//     "error")
	// More details here:
	// https://www.algolia.com/doc/rest#logs-api
	GetLogs(params Map) (logs []LogRes, err error)

	// GenerateSecuredAPIKey generates a public API key intended to restrict
	// access to certain records. This new key is built upon the existing key
	// named `apiKey` and the `params` map. The `params` map can contain any
	// query parameters to restrict what needs to be and can also have the
	// following fields:
	//   - `userToken` (string identifier generally used to rate-limit users
	//     per IP)
	//   - `validUntil` (timestamp of the expiration date)
	//   - `restrictIndices` (comma-separated string list of the indices to
	//     restrict)
	// More details here:
	// https://www.algolia.com/doc/rest#request-from-browser-with-secure-restriction
	GenerateSecuredAPIKey(apiKey string, params Map) (key string, err error)

	// MultipleQueries performs all the queries specified in `queries` and
	// aggregates the results. The `strategy` can either be set to `none`
	// (default) which executes all the queries until the last one, or set to
	// `stopIfEnoughMatches` to limit the number of results according to the
	// `hitsPerPage` parameter. More details here:
	// https://www.algolia.com/doc/rest#query-multiple-indexes
	MultipleQueries(queries []IndexedQuery, strategy string) (res []MultipleQueryRes, err error)

	// Batch performs all queries in `queries`.
	Batch(records []BatchOperationIndexed) (res MultipleBatchRes, err error)
}

// Index is the structure used to manipulate an Algolia index.
type Index interface {
	// Delete deletes the Algolia index.
	Delete() (res DeleteTaskRes, err error)

	// Clear removes every record from the Algolia index.
	Clear() (res UpdateTaskRes, err error)

	// GetObject retrieves the object as an interface representing the JSON-encoded
	// object. The `objectID` is used to uniquely identify the object in the index
	// while `attributes` contains the list of attributes to retrieve.
	GetObject(objectID string, attributes []string) (object Object, err error)

	// GetObjects retrieves the objects identified according to their `objectIDs`.
	GetObjects(objectIDs []string) (objects []Object, err error)

	// DeleteObject deletes an object from the index that is uniquely identified by
	// its `objectID`.
	DeleteObject(objectID string) (res DeleteTaskRes, err error)

	// GetSettings retrieves the index' settings.
	GetSettings() (settings Settings, err error)

	// SetSettings changes the index settings.
	SetSettings(settings Map) (res UpdateTaskRes, err error)

	// WaitTask stops the current execution until the task identified by its
	// `taskID` is finished. The waiting time between each check starts at 1s and
	// is increased by a factor of 2 at each retry (but is bounded at around
	// 20min).
	WaitTask(taskID int) error

	// ListKeys lists all the keys that can access the index.
	ListKeys() (keys []Key, err error)

	// AddKey creates a new API key from the supplied `ACL` and the specified
	// optional parameters for the current index.
	AddKey(ACL []string, params Map) (res AddKeyRes, err error)

	// UpdateKey updates the key identified by the value `k.Value` by replacing all
	// the original key's fields by the ones of `k`.
	UpdateKey(value string, k Key) (res UpdateKeyRes, err error)

	// GetKey retrieves the key identified by its `value` string.
	GetKey(value string) (key Key, err error)

	// DeleteKey deletes the key identified by its `value` string.
	DeleteKey(value string) (res DeleteRes, err error)

	// AddObject adds a new record to the index.
	AddObject(object Object) (res CreateObjectRes, err error)

	// UpdateObject replaces the record in the index matching the one given in
	// parameter, according to its `objectID`.
	UpdateObject(object Object) (res UpdateObjectRes, err error)

	// PartialUpdateObject modifies the record in the index matching the one given
	// in parameter, according to its `objectID`. However, the record is only
	// partially updated i.e. only the specified attributes will be
	// updated, the original record won't be replaced.
	PartialUpdateObject(object Object) (res UpdateTaskRes, err error)

	// AddObjects adds several objects to the index.
	AddObjects(objects []Object) (BatchRes, error)

	// UpdateObjects adds or replaces several objects at the same time, according
	// to their respective `objectID` attribute.
	UpdateObjects(objects []Object) (BatchRes, error)

	// PartialUpdateObjects partially updates several objects at the same time,
	// according to their respective `objectID` attribute.
	PartialUpdateObjects(objects []Object) (BatchRes, error)

	// DeleteObjects deletes several objects at the same time, according to their
	// respective `objectID` attribute.
	DeleteObjects(objectIDs []string) (BatchRes, error)

	// Batch processes all the specified `operations` in a batch manner. The
	// operations's actions could be one of the following:
	//   - addObject
	//   - updateObject
	//   - partialUpdateObject
	//   - partialUpdateObjectNoCreate
	//   - deleteObject
	//   - clear
	// For more informations, please refer to the official REST API documentation
	// available here: https://www.algolia.com/doc/rest#batch-write-operations.
	Batch(operations []BatchOperation) (res BatchRes, err error)

	// Copy copies the index into a new one called `name`.
	Copy(name string) (UpdateTaskRes, error)

	// Move renames the index into `name`.
	Move(name string) (UpdateTaskRes, error)

	// GetStatus returns the status of a task given its ID `taskID`.
	GetStatus(taskID int) (res TaskStatusRes, err error)

	// SearchSynonyms returns the synonyms matching `query` whose types match
	// `types`. To retrieve the first page, `page` should be set to 0.
	// `hitsPerPage` specifies how many synonym sets will be returned per page.
	SearchSynonyms(query string, types []string, page, hitsPerPage int) (synonyms []Synonym, err error)

	// GetSynonym retrieves the synonym identified by `objectID`.
	GetSynonym(objectID string) (s Synonym, err error)

	// AddSynonym adds the given `synonym` to be identified `objectID`. This
	// addition can be forwarded to the index slaves using `forwardToSlaves`.
	AddSynonym(objectID string, synonym Synonym, forwardToSlaves bool) (res UpdateTaskRes, err error)

	// DeleteSynonym removes the synonym identified by `objectID`. This deletion
	// can be forwarded to the index slaves of the index with `forwardToSlaves`.
	DeleteSynonym(objectID string, forwardToSlaves bool) (res DeleteTaskRes, err error)

	// ClearSynonyms removes all synonyms from the index. The clear operation can
	// be forwarded to the index slaves of the index using `forwardToSlaves`.
	ClearSynonyms(forwardToSlaves bool) (res UpdateTaskRes, err error)

	// BatchSynonyms adds all `synonyms` to the index. The index can be cleared
	// before by setting `replaceExistingSynonyms` to `true`. The optional clear
	// operation and the additions can be forwarded to the index slaves by setting
	// `forwardToSlaves` to `true'.
	BatchSynonyms(synonyms []Synonym, replaceExistingSynonyms, forwardToSlaves bool) (res UpdateTaskRes, err error)

	// Browse returns the hits found according to the given `params`. The result
	// also contains the cursor needed to paginate the result. This is a low-level
	// function, if you simply want to iterate through all the results, it is
	// preferable to use BrowseAll instead. For more informations about the Browse
	// endpoint, please refer to the REST API documentation:
	// https://www.algolia.com/doc/rest#browse-all-index-content
	Browse(params Map) (res BrowseRes, err error)

	// BrowseAll returns an iterator pointing to the first result that matches the
	// search query given the `params`. Calling `Next()` on the iterator will
	// returns all the hits one by one, without the 1000 elements limit of the
	// Search function.
	BrowseAll(params Map) (it IndexIterator, err error)

	// Search performs a search query according to the `query` search query and the
	// given `params`.
	Search(query string, params Map) (res QueryRes, err error)

	// DeleteByQuery finds all the records that match the `query`, according to the
	// given 'params` and deletes them.
	DeleteByQuery(query string, params Map) (res BatchRes, err error)
}

// IndexIterator is used by the BrowseAll functions to iterate over all the
// records of an index (or a subset according to what the query was).
type IndexIterator interface {
	// Next returns the next record each time is is called. Subsequent pages of
	// results are automatically loaded and an error is returned if a problem
	// arises. When the last element has been reached, an error is returned with
	// the following message: "No more hits".
	Next() (res Map, err error)
}
<commit_msg>Review and fix `Index` interface comments<commit_after>package algoliasearch

// Client is a representation of an Algolia application. Once initialized it
// allows manipulations over the indexes of the application as well as network
// related parameters.
type Client interface {
	// SetExtraHeader allows to set custom headers while reaching out to
	// Algolia servers.
	SetExtraHeader(key, value string)

	// SetTimeout specifies timeouts to use with the HTTP connection.
	SetTimeout(connectTimeout, readTimeout int)

	// ListIndexes returns the list of all indexes belonging to this Algolia
	// application.
	ListIndexes() (indexes []IndexRes, err error)

	// InitIndex returns an Index object targeting `name`.
	InitIndex(name string) Index

	// ListKeys returns all the API keys available for this Algolia
	// application.
	ListKeys() (keys []Key, err error)

	// MoveIndex renames the index named `source` as `destination`.
	MoveIndex(source, destination string) (UpdateTaskRes, error)

	// CopyIndex duplicates the index named `source` as `destination`.
	CopyIndex(source, destination string) (UpdateTaskRes, error)

	// AddKey creates a new API key from the supplied `ACL` and the specified
	// optional parameters. More details here:
	// https://www.algolia.com/doc/rest#add-a-global-api-key
	AddKey(ACL []string, params Map) (res AddKeyRes, err error)

	// UpdateKey updates the API key identified by its value `key` with the
	// given parameters.
	UpdateKey(key string, params Map) (res UpdateKeyRes, err error)

	// GetKey returns the key identified by its value `key`.
	GetKey(key string) (res Key, err error)

	// DeleteKey deletes the API key identified by its `key`.
	DeleteKey(key string) (res DeleteRes, err error)

	// GetLogs retrieves the logs according to the given `params` map which can
	// contain the following fields:
	//   - `length` (number of entries to retrieve)
	//   - `offset` (offset to the first entry)
	//   - `type` (type of logs to retrieve, can be "all", "query", "build" or
	//     "error")
	// More details here:
	// https://www.algolia.com/doc/rest#logs-api
	GetLogs(params Map) (logs []LogRes, err error)

	// GenerateSecuredAPIKey generates a public API key intended to restrict
	// access to certain records. This new key is built upon the existing key
	// named `apiKey` and the `params` map. The `params` map can contain any
	// query parameters to restrict what needs to be and can also have the
	// following fields:
	//   - `userToken` (string identifier generally used to rate-limit users
	//     per IP)
	//   - `validUntil` (timestamp of the expiration date)
	//   - `restrictIndices` (comma-separated string list of the indices to
	//     restrict)
	// More details here:
	// https://www.algolia.com/doc/rest#request-from-browser-with-secure-restriction
	GenerateSecuredAPIKey(apiKey string, params Map) (key string, err error)

	// MultipleQueries performs all the queries specified in `queries` and
	// aggregates the results. The `strategy` can either be set to `none`
	// (default) which executes all the queries until the last one, or set to
	// `stopIfEnoughMatches` to limit the number of results according to the
	// `hitsPerPage` parameter. More details here:
	// https://www.algolia.com/doc/rest#query-multiple-indexes
	MultipleQueries(queries []IndexedQuery, strategy string) (res []MultipleQueryRes, err error)

	// Batch performs all queries in `queries`.
	Batch(records []BatchOperationIndexed) (res MultipleBatchRes, err error)
}

// Index is a representation used to manipulate an Algolia index.
type Index interface {
	// Delete removes the Algolia index.
	Delete() (res DeleteTaskRes, err error)

	// Clear removes every record from the index.
	Clear() (res UpdateTaskRes, err error)

	// GetObject retrieves the object as an interface representing the
	// JSON-encoded object. The `objectID` is used to uniquely identify the
	// object in the index while `attributes` contains the list of attributes
	// to retrieve.
	GetObject(objectID string, attributes []string) (object Object, err error)

	// GetObjects retrieves the objects identified according to their
	// `objectIDs`.
	GetObjects(objectIDs []string) (objects []Object, err error)

	// DeleteObject deletes an object from the index that is uniquely
	// identified by its `objectID`.
	DeleteObject(objectID string) (res DeleteTaskRes, err error)

	// GetSettings retrieves the index's settings.
	GetSettings() (settings Settings, err error)

	// SetSettings changes the index settings.
	SetSettings(settings Map) (res UpdateTaskRes, err error)

	// WaitTask stops the current execution until the task identified by its
	// `taskID` is finished. The waiting time between each check is usually
	// implemented by starting at 1s and increases by a factor of 2 at each
	// retry (but is bounded at around 20min).
	WaitTask(taskID int) error

	// ListKeys lists all the keys that can access the index.
	ListKeys() (keys []Key, err error)

	// AddKey creates a new API key from the supplied `ACL` and the specified
	// optional `params` parameters for the current index. More details here:
	// https://www.algolia.com/doc/rest#add-an-index-specific-api-key
	AddKey(ACL []string, params Map) (res AddKeyRes, err error)

	// UpdateKey updates the key identified by its `value` with all the fields
	// present in the `k` key. More details here:
	// https://www.algolia.com/doc/rest#update-an-index-specific-api-key
	UpdateKey(value string, k Key) (res UpdateKeyRes, err error)

	// GetKey retrieves the key identified by its `value`.
	GetKey(value string) (key Key, err error)

	// DeleteKey deletes the key identified by its `value`.
	DeleteKey(value string) (res DeleteRes, err error)

	// AddObject adds a new record to the index.
	AddObject(object Object) (res CreateObjectRes, err error)

	// UpdateObject replaces the record in the index matching the one given in
	// parameter, according to its `objectID` attribute.
	UpdateObject(object Object) (res UpdateObjectRes, err error)

	// PartialUpdateObject modifies the record in the index matching the one
	// given in parameter, according to its `objectID` attribute. However, the
	// record is only partially updated i.e. only the specified attributes will
	// be updated, the original record won't be replaced.
	PartialUpdateObject(object Object) (res UpdateTaskRes, err error)

	// AddObjects adds several objects to the index.
	AddObjects(objects []Object) (BatchRes, error)

	// UpdateObjects adds or replaces several objects at the same time,
	// according to their respective `objectID` attribute.
	UpdateObjects(objects []Object) (BatchRes, error)

	// PartialUpdateObjects partially updates several objects at the same time,
	// according to their respective `objectID` attribute.
	PartialUpdateObjects(objects []Object) (BatchRes, error)

	// DeleteObjects removes several objects at the same time, according to
	// their respective `objectID` attribute.
	DeleteObjects(objectIDs []string) (BatchRes, error)

	// Batch processes all the specified `operations` in a batch manner. The
	// operations's actions could be one of the following:
	//   - `addObject`
	//   - `updateObject`
	//   - `partialUpdateObject`
	//   - `partialUpdateObjectNoCreate`
	//   - `deleteObject`
	//   - `clear`
	// More details here:
	// https://www.algolia.com/doc/rest#batch-write-operations.
	Batch(operations []BatchOperation) (res BatchRes, err error)

	// Copy copies the index into a new one called `name`.
	Copy(name string) (UpdateTaskRes, error)

	// Move renames the index into `name`.
	Move(name string) (UpdateTaskRes, error)

	// GetStatus returns the status of a task given its ID `taskID`.
	GetStatus(taskID int) (res TaskStatusRes, err error)

	// SearchSynonyms returns the synonyms matching `query` whose types match
	// `types`. To retrieve the first page, `page` should be set to 0.
	// `hitsPerPage` specifies how many synonym sets will be returned per page.
	SearchSynonyms(query string, types []string, page, hitsPerPage int) (synonyms []Synonym, err error)

	// GetSynonym retrieves the synonym identified by its `objectID`.
	GetSynonym(objectID string) (s Synonym, err error)

	// AddSynonym adds the given `synonym` identified by its `objectID`. This
	// addition can be forwarded to the index slaves by setting
	// `forwardToSlaves` to `true`.
	AddSynonym(objectID string, synonym Synonym, forwardToSlaves bool) (res UpdateTaskRes, err error)

	// DeleteSynonym removes the synonym identified by its `objectID`. This
	// deletion can be forwarded to the index slaves by setting
	// `forwardToSlaves` to `true`.
	DeleteSynonym(objectID string, forwardToSlaves bool) (res DeleteTaskRes, err error)

	// ClearSynonyms removes all synonyms from the index. The clear operation
	// can be forwarded to the index slaves by setting `forwardToSlaves` to
	// `true`.
	ClearSynonyms(forwardToSlaves bool) (res UpdateTaskRes, err error)

	// BatchSynonyms adds all `synonyms` to the index. The index can be cleared
	// before by setting `replaceExistingSynonyms` to `true`. The optional
	// clear operation and the additions can be forwarded to the index slaves
	// by setting `forwardToSlaves` to `true'.
	BatchSynonyms(synonyms []Synonym, replaceExistingSynonyms, forwardToSlaves bool) (res UpdateTaskRes, err error)

	// Browse returns the hits found according to the given `params`. The
	// result also contains the cursor needed to paginate the results. This is
	// a low-level function, if you simply want to iterate through all the
	// results, it is preferable to use `BrowseAll` instead. More details here:
	// https://www.algolia.com/doc/rest#browse-all-index-content
	Browse(params Map) (res BrowseRes, err error)

	// BrowseAll returns an iterator pointing to the first result that matches
	// the search query given the `params`. Calling `Next()` on the iterator
	// will returns all the hits one by one, without the 1000 elements limit of
	// the Search function.
	BrowseAll(params Map) (it IndexIterator, err error)

	// Search performs a search query according to the `query` search query and
	// the given `params`. More details here:
	// https://www.algolia.com/doc/rest#query-an-index
	Search(query string, params Map) (res QueryRes, err error)

	// DeleteByQuery finds all the records that match the `query`, according to
	// the given 'params` and deletes them.
	DeleteByQuery(query string, params Map) (res BatchRes, err error)
}

// IndexIterator is used by the BrowseAll functions to iterate over all the
// records of an index (or a subset according to what the query was).
type IndexIterator interface {
	// Next returns the next record each time is is called. Subsequent pages of
	// results are automatically loaded and an error is returned if a problem
	// arises. When the last element has been reached, an error is returned with
	// the following message: "No more hits".
	Next() (res Map, err error)
}
<|endoftext|>


<commit_before>// +build examples

package main

import (
	"encoding/hex"
	"fmt"
	"log"
	"net/http"
	"os"

	//"github.com/pkg/profile"
	"gopkg.in/jcmturner/gokrb5.v6/credentials"
	"gopkg.in/jcmturner/gokrb5.v6/keytab"
	"gopkg.in/jcmturner/gokrb5.v6/service"
	"gopkg.in/jcmturner/gokrb5.v6/testdata"
)

const (
	port = ":9080"
)

func main() {
	//defer profile.Start(profile.TraceProfile).Stop()
	// Create logger
	l := log.New(os.Stderr, "GOKRB5 Service: ", log.Ldate|log.Ltime|log.Lshortfile)

	// Load the service's keytab
	b, _ := hex.DecodeString(testdata.HTTP_KEYTAB)
	kt, _ := keytab.Parse(b)

	// Create the application's specific handler
	th := http.HandlerFunc(testAppHandler)

	// Set up handler mappings wrapping in the SPNEGOKRB5Authenticate handler wrapper
	mux := http.NewServeMux()
	c := service.NewConfig(kt)
	mux.Handle("/", service.SPNEGOKRB5Authenticate(th, c, l))

	// Start up the web server
	log.Fatal(http.ListenAndServe(port, mux))
}

// Simple application specific handler
func testAppHandler(w http.ResponseWriter, r *http.Request) {
	w.WriteHeader(http.StatusOK)
	ctx := r.Context()
	creds := ctx.Value(service.CTXKeyCredentials).(*credentials.Credentials)
	fmt.Fprintf(w,
		`

GOKRB5 Handler

Authenticed user: %s

User's realm: %s

Authn time: %v

Session ID: %s

`,
		creds.UserName(),
		creds.Domain(),
		creds.AuthTime(),
		creds.SessionID(),
	)
	return
}
<commit_msg>Update httpServer.go<commit_after>// +build examples

package main

import (
	"encoding/hex"
	"fmt"
	"log"
	"net/http"
	"os"

	//"github.com/pkg/profile"
	"gopkg.in/jcmturner/gokrb5.v6/credentials"
	"gopkg.in/jcmturner/gokrb5.v6/keytab"
	"gopkg.in/jcmturner/gokrb5.v6/service"
	"gopkg.in/jcmturner/gokrb5.v6/testdata"
)

const (
	port = ":9080"
)

func main() {
	//defer profile.Start(profile.TraceProfile).Stop()
	// Create logger
	l := log.New(os.Stderr, "GOKRB5 Service: ", log.Ldate|log.Ltime|log.Lshortfile)

	// Load the service's keytab
	b, _ := hex.DecodeString(testdata.HTTP_KEYTAB)
	kt, _ := keytab.Parse(b)

	// Create the application's specific handler
	th := http.HandlerFunc(testAppHandler)

	// Set up handler mappings wrapping in the SPNEGOKRB5Authenticate handler wrapper
	mux := http.NewServeMux()
	c := service.NewConfig(kt)
	mux.Handle("/", service.SPNEGOKRB5Authenticate(th, c, l))

	// Start up the web server
	log.Fatal(http.ListenAndServe(port, mux))
}

// Simple application specific handler
func testAppHandler(w http.ResponseWriter, r *http.Request) {
	w.WriteHeader(http.StatusOK)
	ctx := r.Context()
	creds := ctx.Value(service.CTXKeyCredentials).(goidentity.Identity)
	fmt.Fprintf(w,
		`

GOKRB5 Handler

Authenticed user: %s

User's realm: %s

Authn time: %v

Session ID: %s

`,
		creds.UserName(),
		creds.Domain(),
		creds.AuthTime(),
		creds.SessionID(),
	)
	return
}
<|endoftext|>


<commit_before>// BaruwaAPI Golang bindings for Baruwa REST API
// Copyright (C) 2019 Andrew Colin Kissa <andrew@topdog.za.net>

// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
// You can obtain one at http://mozilla.org/MPL/2.0/.

// Package api Golang bindings for Baruwa REST API
package api
<commit_msg>FET: Domain delivery server skeleton<commit_after>// BaruwaAPI Golang bindings for Baruwa REST API
// Copyright (C) 2019 Andrew Colin Kissa <andrew@topdog.za.net>

// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
// You can obtain one at http://mozilla.org/MPL/2.0/.

// Package api Golang bindings for Baruwa REST API
package api

// DomainDeliveryServer holds domain delivery servers
type DomainDeliveryServer struct {
	ID               int    `json:"id,omitempty"`
	Address          string `json:"address"`
	Protocol         int    `json:"protocol"`
	Port             int    `json:"port"`
	RequireTLS       bool   `json:"require_tls"`
	VerificationOnly bool   `json:"verification_only"`
	Enabled          bool   `json:"enabled"`
}

// GetDomainDeliveryServer returns a domain delivery server
// https://www.baruwa.com/docs/api/#retrieve-a-delivery-server
func (c *Client) GetDomainDeliveryServer(id int) (domain *DomainDeliveryServer, err error) {
	return
}

// CreateDomainDeliveryServer creates a domain delivery server
// https://www.baruwa.com/docs/api/#create-a-delivery-server
func (c *Client) CreateDomainDeliveryServer(domain *DomainDeliveryServer) (err error) {
	return
}

// UpdateDomainDeliveryServer updates a domain delivery server
// https://www.baruwa.com/docs/api/#update-a-delivery-server
func (c *Client) UpdateDomainDeliveryServer(domain *DomainDeliveryServer) (err error) {
	return
}

// DeleteDomainDeliveryServer deletes a domain delivery server
// https://www.baruwa.com/docs/api/#delete-a-delivery-server
func (c *Client) DeleteDomainDeliveryServer(id int) (err error) {
	return
}
<|endoftext|>


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

// +build example jsgo

// This example is just to check if Ebiten can draw fine checker pattern evenly.
// If there is something wrong in the implementation, the result might include
// uneven patterns (#459).
package main

import (
	"log"

	"github.com/hajimehoshi/ebiten"
	"github.com/hajimehoshi/ebiten/inpututil"
)

const (
	screenWidth     = 640
	screenHeight    = 480
	initScreenScale = 1
)

var (
	dots       []uint8
	dotsWidth  int
	dotsHeight int
)

func getDots(width, height int) []uint8 {
	if dotsWidth == width && dotsHeight == height {
		return dots
	}
	dotsWidth = width
	dotsHeight = height
	dots = make([]uint8, width*height*4)
	for j := 0; j < height; j++ {
		for i := 0; i < width; i++ {
			if (i+j)%2 == 0 {
				dots[(i+j*width)*4+0] = 0xff
				dots[(i+j*width)*4+1] = 0xff
				dots[(i+j*width)*4+2] = 0xff
				dots[(i+j*width)*4+3] = 0xff
			}
		}
	}
	return dots
}

func update(screen *ebiten.Image) error {
	screenScale := ebiten.ScreenScale()
	fullscreen := ebiten.IsFullscreen()

	if inpututil.IsKeyJustPressed(ebiten.KeyS) {
		switch screenScale {
		case 1:
			screenScale = 1.5
		case 1.5:
			screenScale = 2
		case 2:
			screenScale = 1
		default:
			panic("not reached")
		}
	}
	if inpututil.IsKeyJustPressed(ebiten.KeyF) {
		fullscreen = !fullscreen
	}
	ebiten.SetScreenScale(screenScale)
	ebiten.SetFullscreen(fullscreen)

	if ebiten.IsDrawingSkipped() {
		return nil
	}

	screen.ReplacePixels(getDots(screen.Size()))
	return nil
}

func main() {
	if err := ebiten.Run(update, screenWidth, screenHeight, initScreenScale, "Moire (Ebiten Demo)"); err != nil {
		log.Fatal(err)
	}
}
<commit_msg>examples/moire: Bug fix: Crash on browsers<commit_after>// Copyright 2017 The Ebiten Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// +build example jsgo

// This example is just to check if Ebiten can draw fine checker pattern evenly.
// If there is something wrong in the implementation, the result might include
// uneven patterns (#459).
package main

import (
	"log"

	"github.com/hajimehoshi/ebiten"
	"github.com/hajimehoshi/ebiten/inpututil"
)

const (
	screenWidth     = 640
	screenHeight    = 480
	initScreenScale = 1
)

var (
	dots       []uint8
	dotsWidth  int
	dotsHeight int
)

func getDots(width, height int) []uint8 {
	if dotsWidth == width && dotsHeight == height {
		return dots
	}
	dotsWidth = width
	dotsHeight = height
	dots = make([]uint8, width*height*4)
	for j := 0; j < height; j++ {
		for i := 0; i < width; i++ {
			if (i+j)%2 == 0 {
				dots[(i+j*width)*4+0] = 0xff
				dots[(i+j*width)*4+1] = 0xff
				dots[(i+j*width)*4+2] = 0xff
				dots[(i+j*width)*4+3] = 0xff
			}
		}
	}
	return dots
}

func update(screen *ebiten.Image) error {
	screenScale := ebiten.ScreenScale()
	fullscreen := ebiten.IsFullscreen()

	if inpututil.IsKeyJustPressed(ebiten.KeyS) {
		switch screenScale {
		case 1:
			screenScale = 1.5
		case 1.5:
			screenScale = 2
		case 2:
			screenScale = 1
		case 0:
			// screenScale can be 0 on browsers or mobiles. Ignore this.
		default:
			panic("not reached")
		}
	}
	if inpututil.IsKeyJustPressed(ebiten.KeyF) {
		fullscreen = !fullscreen
	}
	if screenScale > 0 {
		ebiten.SetScreenScale(screenScale)
	}
	ebiten.SetFullscreen(fullscreen)

	if ebiten.IsDrawingSkipped() {
		return nil
	}

	screen.ReplacePixels(getDots(screen.Size()))
	return nil
}

func main() {
	if err := ebiten.Run(update, screenWidth, screenHeight, initScreenScale, "Moire (Ebiten Demo)"); err != nil {
		log.Fatal(err)
	}
}
<|endoftext|>


<commit_before>package xxhash

import (
	"bytes"
	"encoding/binary"
	"fmt"
	"hash"
	"hash/crc32"
	"strings"
	"testing"

	OneOfOne "github.com/OneOfOne/xxhash"
	"github.com/spaolacci/murmur3"
)

var result uint64

func BenchmarkStringHash(b *testing.B) {
	const s = "abcdefghijklmnop"
	var r uint64
	b.ReportAllocs()
	for n := 0; n < b.N; n++ {
		r = Sum64([]byte(s))
	}
	result = r
}

func TestSum(t *testing.T) {
	for i, tt := range []struct {
		input string
		want  uint64
	}{
		{"", 0xef46db3751d8e999},
		{"a", 0xd24ec4f1a98c6e5b},
		{"as", 0x1c330fb2d66be179},
		{"asd", 0x631c37ce72a97393},
		{"asdf", 0x415872f599cea71e},
		{
			// Exactly 63 characters, which exercises all code paths.
			"Call me Ishmael. Some years ago--never mind how long precisely-",
			0x02a2e85470d6fd96,
		},
	} {
		for chunkSize := 1; chunkSize <= len(tt.input); chunkSize++ {
			x := New()
			for j := 0; j < len(tt.input); j += chunkSize {
				end := j + chunkSize
				if end > len(tt.input) {
					end = len(tt.input)
				}
				chunk := []byte(tt.input[j:end])
				n, err := x.Write(chunk)
				if err != nil || n != len(chunk) {
					t.Fatalf("[i=%d,chunkSize=%d] Write: got (%d, %v); want (%d, nil)",
						i, chunkSize, n, err, len(chunk))
				}
			}
			if got := x.Sum64(); got != tt.want {
				t.Fatalf("[i=%d,chunkSize=%d] got 0x%x; want 0x%x",
					i, chunkSize, got, tt.want)
			}
			var b [8]byte
			binary.BigEndian.PutUint64(b[:], tt.want)
			if got := x.Sum(nil); !bytes.Equal(got, b[:]) {
				t.Fatalf("[i=%d,chunkSize=%d] Sum: got %v; want %v",
					i, chunkSize, got, b[:])
			}
		}
		if got := Sum64([]byte(tt.input)); got != tt.want {
			t.Fatalf("[i=%d] Sum64: got 0x%x; want 0x%x", i, got, tt.want)
		}
		if got := Sum64String(tt.input); got != tt.want {
			t.Fatalf("[i=%d] Sum64String: got 0x%x; want 0x%x", i, got, tt.want)
		}
	}
}

func TestReset(t *testing.T) {
	parts := []string{"The quic", "k br", "o", "wn fox jumps", " ov", "er the lazy ", "dog."}
	x := New()
	for _, part := range parts {
		x.Write([]byte(part))
	}
	h0 := x.Sum64()

	x.Reset()
	x.Write([]byte(strings.Join(parts, "")))
	h1 := x.Sum64()

	if h0 != h1 {
		t.Errorf("0x%x != 0x%x", h0, h1)
	}
}

var (
	sink  uint64
	sinkb []byte
)

func sumFunc(h hash.Hash) func(b []byte) uint64 {
	return func(b []byte) uint64 {
		h.Reset()
		h.Write(b)
		sinkb = h.Sum(nil)
		return 0 // value doesn't matter
	}
}

func BenchmarkHashes(b *testing.B) {
	for _, ht := range []struct {
		name string
		f    interface{}
	}{
		{"xxhash", Sum64},
		{"xxhash-string", Sum64String},
		{"OneOfOne", OneOfOne.Checksum64},
		{"murmur3", murmur3.Sum64},
		{"CRC-32", sumFunc(crc32.NewIEEE())},
	} {
		for _, nt := range []struct {
			name string
			n    int
		}{
			{"5 B", 5},
			{"100 B", 100},
			{"4 KB", 4e3},
			{"10 MB", 10e6},
		} {
			input := make([]byte, nt.n)
			for i := range input {
				input[i] = byte(i)
			}
			benchName := fmt.Sprintf("%s,n=%s", ht.name, nt.name)
			if ht.name == "xxhash-string" {
				f := ht.f.(func(string) uint64)
				s := string(input)
				b.Run(benchName, func(b *testing.B) {
					b.SetBytes(int64(len(input)))
					for i := 0; i < b.N; i++ {
						sink = f(s)
					}
				})
			} else {
				f := ht.f.(func([]byte) uint64)
				b.Run(benchName, func(b *testing.B) {
					b.SetBytes(int64(len(input)))
					for i := 0; i < b.N; i++ {
						sink = f(input)
					}
				})
			}
		}
	}
}
<commit_msg>Add more benchmarks using New(), etc<commit_after>package xxhash

import (
	"bytes"
	"encoding/binary"
	"fmt"
	"hash/crc32"
	"hash/fnv"
	"strings"
	"testing"

	OneOfOne "github.com/OneOfOne/xxhash"
	"github.com/spaolacci/murmur3"
)

var result uint64

func BenchmarkStringHash(b *testing.B) {
	const s = "abcdefghijklmnop"
	var r uint64
	b.ReportAllocs()
	for n := 0; n < b.N; n++ {
		r = Sum64([]byte(s))
	}
	result = r
}

func TestSum(t *testing.T) {
	for i, tt := range []struct {
		input string
		want  uint64
	}{
		{"", 0xef46db3751d8e999},
		{"a", 0xd24ec4f1a98c6e5b},
		{"as", 0x1c330fb2d66be179},
		{"asd", 0x631c37ce72a97393},
		{"asdf", 0x415872f599cea71e},
		{
			// Exactly 63 characters, which exercises all code paths.
			"Call me Ishmael. Some years ago--never mind how long precisely-",
			0x02a2e85470d6fd96,
		},
	} {
		for chunkSize := 1; chunkSize <= len(tt.input); chunkSize++ {
			x := New()
			for j := 0; j < len(tt.input); j += chunkSize {
				end := j + chunkSize
				if end > len(tt.input) {
					end = len(tt.input)
				}
				chunk := []byte(tt.input[j:end])
				n, err := x.Write(chunk)
				if err != nil || n != len(chunk) {
					t.Fatalf("[i=%d,chunkSize=%d] Write: got (%d, %v); want (%d, nil)",
						i, chunkSize, n, err, len(chunk))
				}
			}
			if got := x.Sum64(); got != tt.want {
				t.Fatalf("[i=%d,chunkSize=%d] got 0x%x; want 0x%x",
					i, chunkSize, got, tt.want)
			}
			var b [8]byte
			binary.BigEndian.PutUint64(b[:], tt.want)
			if got := x.Sum(nil); !bytes.Equal(got, b[:]) {
				t.Fatalf("[i=%d,chunkSize=%d] Sum: got %v; want %v",
					i, chunkSize, got, b[:])
			}
		}
		if got := Sum64([]byte(tt.input)); got != tt.want {
			t.Fatalf("[i=%d] Sum64: got 0x%x; want 0x%x", i, got, tt.want)
		}
		if got := Sum64String(tt.input); got != tt.want {
			t.Fatalf("[i=%d] Sum64String: got 0x%x; want 0x%x", i, got, tt.want)
		}
	}
}

func TestReset(t *testing.T) {
	parts := []string{"The quic", "k br", "o", "wn fox jumps", " ov", "er the lazy ", "dog."}
	x := New()
	for _, part := range parts {
		x.Write([]byte(part))
	}
	h0 := x.Sum64()

	x.Reset()
	x.Write([]byte(strings.Join(parts, "")))
	h1 := x.Sum64()

	if h0 != h1 {
		t.Errorf("0x%x != 0x%x", h0, h1)
	}
}

var (
	sink  uint64
	sinkb []byte
)

var benchmarks = []struct {
	name         string
	directBytes  func([]byte) uint64
	directString func(string) uint64
	digestBytes  func([]byte) uint64
	digestString func(string) uint64
}{
	{
		name:         "xxhash",
		directBytes:  Sum64,
		directString: Sum64String,
		digestBytes: func(b []byte) uint64 {
			h := New()
			h.Write(b)
			return h.Sum64()
		},
		digestString: func(s string) uint64 {
			h := New()
			h.Write([]byte(s))
			return h.Sum64()
		},
	},
	{
		name:         "OneOfOne",
		directBytes:  OneOfOne.Checksum64,
		directString: OneOfOne.ChecksumString64,
		digestBytes: func(b []byte) uint64 {
			h := OneOfOne.New64()
			h.Write(b)
			return h.Sum64()
		},
		digestString: func(s string) uint64 {
			h := OneOfOne.New64()
			h.WriteString(s)
			return h.Sum64()
		},
	},
	{
		name:        "murmur3",
		directBytes: murmur3.Sum64,
		directString: func(s string) uint64 {
			return murmur3.Sum64([]byte(s))
		},
		digestBytes: func(b []byte) uint64 {
			h := murmur3.New64()
			h.Write(b)
			return h.Sum64()
		},
		digestString: func(s string) uint64 {
			h := murmur3.New64()
			h.Write([]byte(s))
			return h.Sum64()
		},
	},
	{
		name: "CRC-32",
		directBytes: func(b []byte) uint64 {
			return uint64(crc32.ChecksumIEEE(b))
		},
		directString: func(s string) uint64 {
			return uint64(crc32.ChecksumIEEE([]byte(s)))
		},
		digestBytes: func(b []byte) uint64 {
			h := crc32.NewIEEE()
			h.Write(b)
			return uint64(h.Sum32())
		},
		digestString: func(s string) uint64 {
			h := crc32.NewIEEE()
			h.Write([]byte(s))
			return uint64(h.Sum32())
		},
	},
	{
		name: "fnv1a",
		digestBytes: func(b []byte) uint64 {
			h := fnv.New64()
			h.Write(b)
			return uint64(h.Sum64())
		},
		digestString: func(s string) uint64 {
			h := fnv.New64a()
			h.Write([]byte(s))
			return uint64(h.Sum64())
		},
	},
}

func BenchmarkHashes(b *testing.B) {
	for _, ht := range benchmarks {
		for _, nt := range []struct {
			name string
			n    int
		}{
			{"5 B", 5},
			{"100 B", 100},
			{"4 KB", 4e3},
			{"10 MB", 10e6},
		} {
			input := make([]byte, nt.n)
			for i := range input {
				input[i] = byte(i)
			}
			inputString := string(input)
			if ht.directBytes != nil {
				b.Run(fmt.Sprintf("%s,direct,bytes,n=%s", ht.name, nt.name), func(b *testing.B) {
					b.SetBytes(int64(len(input)))
					for i := 0; i < b.N; i++ {
						sink = ht.directBytes(input)
					}
				})
			}
			if ht.directString != nil {
				b.Run(fmt.Sprintf("%s,direct,string,n=%s", ht.name, nt.name), func(b *testing.B) {
					b.SetBytes(int64(len(input)))
					for i := 0; i < b.N; i++ {
						sink = ht.directString(inputString)
					}
				})
			}
			if ht.digestBytes != nil {
				b.Run(fmt.Sprintf("%s,digest,bytes,n=%s", ht.name, nt.name), func(b *testing.B) {
					b.SetBytes(int64(len(input)))
					for i := 0; i < b.N; i++ {
						sink = ht.digestBytes(input)
					}
				})
			}
			if ht.digestString != nil {
				b.Run(fmt.Sprintf("%s,digest,string,n=%s", ht.name, nt.name), func(b *testing.B) {
					b.SetBytes(int64(len(input)))
					for i := 0; i < b.N; i++ {
						sink = ht.digestString(inputString)
					}
				})
			}
		}
	}
}
<|endoftext|>


<commit_before>package aws

import (
	"fmt"
	"testing"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/service/apigatewayv2"
	"github.com/hashicorp/terraform/helper/acctest"
	"github.com/hashicorp/terraform/helper/resource"
	"github.com/hashicorp/terraform/terraform"
)

func TestAccAWSAPIGateway2Api_basic(t *testing.T) {
	resourceName := "aws_api_gateway_v2_api.test"
	rName := fmt.Sprintf("terraform-testacc-apigwv2-%d", acctest.RandInt())

	resource.ParallelTest(t, resource.TestCase{
		PreCheck:     func() { testAccPreCheck(t) },
		Providers:    testAccProviders,
		CheckDestroy: testAccCheckAWSAPIGateway2ApiDestroy,
		Steps: []resource.TestStep{
			{
				Config: testAccAWSAPIGateway2ApiConfig_basic(rName),
				Check: resource.ComposeTestCheckFunc(
					testAccCheckAWSAPIGateway2ApiExists(resourceName),
					resource.TestCheckResourceAttrSet(resourceName, "api_endpoint"),
					resource.TestCheckResourceAttr(resourceName, "api_key_selection_expression", "$request.header.x-api-key"),
					resource.TestCheckResourceAttr(resourceName, "description", ""),
					resource.TestCheckResourceAttr(resourceName, "name", rName),
					resource.TestCheckResourceAttr(resourceName, "protocol_type", apigatewayv2.ProtocolTypeWebsocket),
					resource.TestCheckResourceAttr(resourceName, "route_selection_expression", "$request.body.action"),
					resource.TestCheckResourceAttr(resourceName, "version", ""),
				),
			},
			{
				ResourceName:      resourceName,
				ImportState:       true,
				ImportStateVerify: true,
			},
		},
	})
}

func TestAccAWSAPIGateway2Api_update(t *testing.T) {
	resourceName := "aws_api_gateway_v2_api.test"
	rName1 := fmt.Sprintf("terraform-testacc-apigwv2-%d", acctest.RandInt())
	rName2 := fmt.Sprintf("terraform-testacc-apigwv2-%d", acctest.RandInt())

	resource.ParallelTest(t, resource.TestCase{
		PreCheck:     func() { testAccPreCheck(t) },
		Providers:    testAccProviders,
		CheckDestroy: testAccCheckAWSAPIGateway2ApiDestroy,
		Steps: []resource.TestStep{
			{
				Config: testAccAWSAPIGateway2ApiConfig_basic(rName1),
				Check: resource.ComposeTestCheckFunc(
					testAccCheckAWSAPIGateway2ApiExists(resourceName),
					resource.TestCheckResourceAttrSet(resourceName, "api_endpoint"),
					resource.TestCheckResourceAttr(resourceName, "api_key_selection_expression", "$request.header.x-api-key"),
					resource.TestCheckResourceAttr(resourceName, "description", ""),
					resource.TestCheckResourceAttr(resourceName, "name", rName1),
					resource.TestCheckResourceAttr(resourceName, "protocol_type", apigatewayv2.ProtocolTypeWebsocket),
					resource.TestCheckResourceAttr(resourceName, "route_selection_expression", "$request.body.action"),
					resource.TestCheckResourceAttr(resourceName, "version", ""),
				),
			},
			{
				Config: testAccAWSAPIGateway2ApiConfig_update(rName2),
				Check: resource.ComposeTestCheckFunc(
					testAccCheckAWSAPIGateway2ApiExists(resourceName),
					resource.TestCheckResourceAttr(resourceName, "api_key_selection_expression", "$context.authorizer.usageIdentifierKey"),
					resource.TestCheckResourceAttr(resourceName, "description", "test description"),
					resource.TestCheckResourceAttr(resourceName, "name", rName2),
					resource.TestCheckResourceAttr(resourceName, "route_selection_expression", "$request.body.service"),
					resource.TestCheckResourceAttr(resourceName, "version", "v1"),
				),
			},
			{
				Config: testAccAWSAPIGateway2ApiConfig_update(rName1),
				Check: resource.ComposeTestCheckFunc(
					testAccCheckAWSAPIGateway2ApiExists(resourceName),
					resource.TestCheckResourceAttr(resourceName, "api_key_selection_expression", "$context.authorizer.usageIdentifierKey"),
					resource.TestCheckResourceAttr(resourceName, "description", "test description"),
					resource.TestCheckResourceAttr(resourceName, "name", rName1),
					resource.TestCheckResourceAttr(resourceName, "route_selection_expression", "$request.body.service"),
					resource.TestCheckResourceAttr(resourceName, "version", "v1"),
				),
			},
			{
				ResourceName:      resourceName,
				ImportState:       true,
				ImportStateVerify: true,
			},
		},
	})
}

func testAccCheckAWSAPIGateway2ApiDestroy(s *terraform.State) error {
	conn := testAccProvider.Meta().(*AWSClient).apigatewayv2conn

	for _, rs := range s.RootModule().Resources {
		if rs.Type != "aws_api_gateway_v2_api" {
			continue
		}

		_, err := conn.GetApi(&apigatewayv2.GetApiInput{
			ApiId: aws.String(rs.Primary.ID),
		})
		if isAWSErr(err, apigatewayv2.ErrCodeNotFoundException, "") {
			continue
		}
		if err != nil {
			return err
		}

		return fmt.Errorf("API Gateway v2 API %s still exists", rs.Primary.ID)
	}

	return nil
}

func testAccCheckAWSAPIGateway2ApiExists(n string) resource.TestCheckFunc {
	return func(s *terraform.State) error {
		rs, ok := s.RootModule().Resources[n]
		if !ok {
			return fmt.Errorf("Not found: %s", n)
		}

		if rs.Primary.ID == "" {
			return fmt.Errorf("No API Gateway v2 API ID is set")
		}

		conn := testAccProvider.Meta().(*AWSClient).apigatewayv2conn

		_, err := conn.GetApi(&apigatewayv2.GetApiInput{
			ApiId: aws.String(rs.Primary.ID),
		})
		if err != nil {
			return err
		}

		return nil
	}
}

func testAccAWSAPIGateway2ApiConfig_basic(rName string) string {
	return fmt.Sprintf(`
resource "aws_api_gateway_v2_api" "test" {
  name                       = %[1]q
  protocol_type              = "WEBSOCKET"
  route_selection_expression = "$request.body.action"
}
`, rName)
}

func testAccAWSAPIGateway2ApiConfig_update(rName string) string {
	return fmt.Sprintf(`
resource "aws_api_gateway_v2_api" "test" {
  api_key_selection_expression = "$context.authorizer.usageIdentifierKey"
  description                  = "test description"
  name                         = %[1]q
  protocol_type                = "WEBSOCKET"
  route_selection_expression   = "$request.body.service"
  version                      = "v1"
}
`, rName)
}
<commit_msg>Better acceptance tests when all attributes are set.<commit_after>package aws

import (
	"fmt"
	"testing"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/service/apigatewayv2"
	"github.com/hashicorp/terraform/helper/acctest"
	"github.com/hashicorp/terraform/helper/resource"
	"github.com/hashicorp/terraform/terraform"
)

func TestAccAWSAPIGateway2Api_basic(t *testing.T) {
	resourceName := "aws_api_gateway_v2_api.test"
	rName := fmt.Sprintf("terraform-testacc-apigwv2-%d", acctest.RandInt())

	resource.ParallelTest(t, resource.TestCase{
		PreCheck:     func() { testAccPreCheck(t) },
		Providers:    testAccProviders,
		CheckDestroy: testAccCheckAWSAPIGateway2ApiDestroy,
		Steps: []resource.TestStep{
			{
				Config: testAccAWSAPIGateway2ApiConfig_basic(rName),
				Check: resource.ComposeTestCheckFunc(
					testAccCheckAWSAPIGateway2ApiExists(resourceName),
					resource.TestCheckResourceAttrSet(resourceName, "api_endpoint"),
					resource.TestCheckResourceAttr(resourceName, "api_key_selection_expression", "$request.header.x-api-key"),
					resource.TestCheckResourceAttr(resourceName, "description", ""),
					resource.TestCheckResourceAttr(resourceName, "name", rName),
					resource.TestCheckResourceAttr(resourceName, "protocol_type", apigatewayv2.ProtocolTypeWebsocket),
					resource.TestCheckResourceAttr(resourceName, "route_selection_expression", "$request.body.action"),
					resource.TestCheckResourceAttr(resourceName, "version", ""),
				),
			},
			{
				ResourceName:      resourceName,
				ImportState:       true,
				ImportStateVerify: true,
			},
		},
	})
}

func TestAccAWSAPIGateway2Api_update(t *testing.T) {
	resourceName := "aws_api_gateway_v2_api.test"
	rName1 := fmt.Sprintf("terraform-testacc-apigwv2-%d", acctest.RandInt())
	rName2 := fmt.Sprintf("terraform-testacc-apigwv2-%d", acctest.RandInt())

	resource.ParallelTest(t, resource.TestCase{
		PreCheck:     func() { testAccPreCheck(t) },
		Providers:    testAccProviders,
		CheckDestroy: testAccCheckAWSAPIGateway2ApiDestroy,
		Steps: []resource.TestStep{
			{
				Config: testAccAWSAPIGateway2ApiConfig_allAttributes(rName1),
				Check: resource.ComposeTestCheckFunc(
					testAccCheckAWSAPIGateway2ApiExists(resourceName),
					resource.TestCheckResourceAttrSet(resourceName, "api_endpoint"),
					resource.TestCheckResourceAttr(resourceName, "api_key_selection_expression", "$context.authorizer.usageIdentifierKey"),
					resource.TestCheckResourceAttr(resourceName, "description", "test description"),
					resource.TestCheckResourceAttr(resourceName, "name", rName1),
					resource.TestCheckResourceAttr(resourceName, "protocol_type", apigatewayv2.ProtocolTypeWebsocket),
					resource.TestCheckResourceAttr(resourceName, "route_selection_expression", "$request.body.service"),
					resource.TestCheckResourceAttr(resourceName, "version", "v1"),
				),
			},
			{
				Config: testAccAWSAPIGateway2ApiConfig_basic(rName1),
				Check: resource.ComposeTestCheckFunc(
					testAccCheckAWSAPIGateway2ApiExists(resourceName),
					resource.TestCheckResourceAttr(resourceName, "api_key_selection_expression", "$request.header.x-api-key"),
					resource.TestCheckResourceAttr(resourceName, "description", ""),
					resource.TestCheckResourceAttr(resourceName, "name", rName1),
					resource.TestCheckResourceAttr(resourceName, "protocol_type", apigatewayv2.ProtocolTypeWebsocket),
					resource.TestCheckResourceAttr(resourceName, "route_selection_expression", "$request.body.action"),
					resource.TestCheckResourceAttr(resourceName, "version", ""),
				),
			},
			{
				Config: testAccAWSAPIGateway2ApiConfig_allAttributes(rName2),
				Check: resource.ComposeTestCheckFunc(
					testAccCheckAWSAPIGateway2ApiExists(resourceName),
					resource.TestCheckResourceAttr(resourceName, "api_key_selection_expression", "$context.authorizer.usageIdentifierKey"),
					resource.TestCheckResourceAttr(resourceName, "description", "test description"),
					resource.TestCheckResourceAttr(resourceName, "name", rName2),
					resource.TestCheckResourceAttr(resourceName, "route_selection_expression", "$request.body.service"),
					resource.TestCheckResourceAttr(resourceName, "version", "v1"),
				),
			},
			{
				Config: testAccAWSAPIGateway2ApiConfig_allAttributes(rName1),
				Check: resource.ComposeTestCheckFunc(
					testAccCheckAWSAPIGateway2ApiExists(resourceName),
					resource.TestCheckResourceAttr(resourceName, "api_key_selection_expression", "$context.authorizer.usageIdentifierKey"),
					resource.TestCheckResourceAttr(resourceName, "description", "test description"),
					resource.TestCheckResourceAttr(resourceName, "name", rName1),
					resource.TestCheckResourceAttr(resourceName, "route_selection_expression", "$request.body.service"),
					resource.TestCheckResourceAttr(resourceName, "version", "v1"),
				),
			},
			{
				ResourceName:      resourceName,
				ImportState:       true,
				ImportStateVerify: true,
			},
		},
	})
}

func testAccCheckAWSAPIGateway2ApiDestroy(s *terraform.State) error {
	conn := testAccProvider.Meta().(*AWSClient).apigatewayv2conn

	for _, rs := range s.RootModule().Resources {
		if rs.Type != "aws_api_gateway_v2_api" {
			continue
		}

		_, err := conn.GetApi(&apigatewayv2.GetApiInput{
			ApiId: aws.String(rs.Primary.ID),
		})
		if isAWSErr(err, apigatewayv2.ErrCodeNotFoundException, "") {
			continue
		}
		if err != nil {
			return err
		}

		return fmt.Errorf("API Gateway v2 API %s still exists", rs.Primary.ID)
	}

	return nil
}

func testAccCheckAWSAPIGateway2ApiExists(n string) resource.TestCheckFunc {
	return func(s *terraform.State) error {
		rs, ok := s.RootModule().Resources[n]
		if !ok {
			return fmt.Errorf("Not found: %s", n)
		}

		if rs.Primary.ID == "" {
			return fmt.Errorf("No API Gateway v2 API ID is set")
		}

		conn := testAccProvider.Meta().(*AWSClient).apigatewayv2conn

		_, err := conn.GetApi(&apigatewayv2.GetApiInput{
			ApiId: aws.String(rs.Primary.ID),
		})
		if err != nil {
			return err
		}

		return nil
	}
}

func testAccAWSAPIGateway2ApiConfig_basic(rName string) string {
	return fmt.Sprintf(`
resource "aws_api_gateway_v2_api" "test" {
  name                       = %[1]q
  protocol_type              = "WEBSOCKET"
  route_selection_expression = "$request.body.action"
}
`, rName)
}

func testAccAWSAPIGateway2ApiConfig_allAttributes(rName string) string {
	return fmt.Sprintf(`
resource "aws_api_gateway_v2_api" "test" {
  api_key_selection_expression = "$context.authorizer.usageIdentifierKey"
  description                  = "test description"
  name                         = %[1]q
  protocol_type                = "WEBSOCKET"
  route_selection_expression   = "$request.body.service"
  version                      = "v1"
}
`, rName)
}
<|endoftext|>


<commit_before>package aws

import (
	"fmt"
	"log"
	"regexp"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/service/cloudwatchlogs"
	"github.com/hashicorp/terraform/helper/schema"
)

func resourceAwsCloudWatchLogStream() *schema.Resource {
	return &schema.Resource{
		Create: resourceAwsCloudWatchLogStreamCreate,
		Read:   resourceAwsCloudWatchLogStreamRead,
		Delete: resourceAwsCloudWatchLogStreamDelete,

		Schema: map[string]*schema.Schema{
			"arn": {
				Type:     schema.TypeString,
				Computed: true,
			},

			"name": {
				Type:         schema.TypeString,
				Required:     true,
				ForceNew:     true,
				ValidateFunc: validateCloudWatchLogStreamName,
			},

			"log_group_name": {
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
			},
		},
	}
}

func resourceAwsCloudWatchLogStreamCreate(d *schema.ResourceData, meta interface{}) error {
	conn := meta.(*AWSClient).cloudwatchlogsconn

	log.Printf("[DEBUG] Creating CloudWatch Log Stream: %s", d.Get("name").(string))
	_, err := conn.CreateLogStream(&cloudwatchlogs.CreateLogStreamInput{
		LogGroupName:  aws.String(d.Get("log_group_name").(string)),
		LogStreamName: aws.String(d.Get("name").(string)),
	})
	if err != nil {
		return fmt.Errorf("Creating CloudWatch Log Stream failed: %s", err)
	}

	d.SetId(d.Get("name").(string))

	return resourceAwsCloudWatchLogStreamRead(d, meta)
}

func resourceAwsCloudWatchLogStreamRead(d *schema.ResourceData, meta interface{}) error {
	conn := meta.(*AWSClient).cloudwatchlogsconn

	ls, exists, err := lookupCloudWatchLogStream(conn, d.Id(), d.Get("log_group_name").(string), nil)
	if err != nil {
		return err
	}

	if !exists {
		log.Printf("[DEBUG] CloudWatch Stream %q Not Found. Removing from state", d.Id())
		d.SetId("")
		return nil
	}

	d.Set("arn", ls.Arn)
	d.Set("name", ls.LogStreamName)

	return nil
}

func resourceAwsCloudWatchLogStreamDelete(d *schema.ResourceData, meta interface{}) error {
	conn := meta.(*AWSClient).cloudwatchlogsconn

	log.Printf("[INFO] Deleting CloudWatch Log Stream: %s", d.Id())
	params := &cloudwatchlogs.DeleteLogStreamInput{
		LogGroupName:  aws.String(d.Get("log_group_name").(string)),
		LogStreamName: aws.String(d.Id()),
	}
	_, err := conn.DeleteLogStream(params)
	if err != nil {
		return fmt.Errorf("Error deleting CloudWatch Log Stream: %s", err)
	}

	return nil
}

func lookupCloudWatchLogStream(conn *cloudwatchlogs.CloudWatchLogs,
	name string, logStreamName string, nextToken *string) (*cloudwatchlogs.LogStream, bool, error) {
	input := &cloudwatchlogs.DescribeLogStreamsInput{
		LogStreamNamePrefix: aws.String(name),
		LogGroupName:        aws.String(logStreamName),
		NextToken:           nextToken,
	}
	resp, err := conn.DescribeLogStreams(input)
	if err != nil {
		return nil, true, err
	}

	for _, ls := range resp.LogStreams {
		if *ls.LogStreamName == name {
			return ls, true, nil
		}
	}

	if resp.NextToken != nil {
		return lookupCloudWatchLogStream(conn, name, logStreamName, resp.NextToken)
	}

	return nil, false, nil
}

func validateCloudWatchLogStreamName(v interface{}, k string) (ws []string, errors []error) {
	value := v.(string)
	if regexp.MustCompile(`:`).MatchString(value) {
		errors = append(errors, fmt.Errorf(
			"colons not allowed in %q:", k))
	}
	if len(value) < 1 || len(value) > 512 {
		errors = append(errors, fmt.Errorf(
			"%q must be between 1 and 512 characters: %q", k, value))
	}

	return

}
<commit_msg>can't destroy aws_cloudwatch_log_stream if group has been destroyed<commit_after>package aws

import (
	"fmt"
	"log"
	"regexp"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/service/cloudwatchlogs"
	"github.com/hashicorp/terraform/helper/schema"
)

func resourceAwsCloudWatchLogStream() *schema.Resource {
	return &schema.Resource{
		Create: resourceAwsCloudWatchLogStreamCreate,
		Read:   resourceAwsCloudWatchLogStreamRead,
		Delete: resourceAwsCloudWatchLogStreamDelete,

		Schema: map[string]*schema.Schema{
			"arn": {
				Type:     schema.TypeString,
				Computed: true,
			},

			"name": {
				Type:         schema.TypeString,
				Required:     true,
				ForceNew:     true,
				ValidateFunc: validateCloudWatchLogStreamName,
			},

			"log_group_name": {
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
			},
		},
	}
}

func resourceAwsCloudWatchLogStreamCreate(d *schema.ResourceData, meta interface{}) error {
	conn := meta.(*AWSClient).cloudwatchlogsconn

	log.Printf("[DEBUG] Creating CloudWatch Log Stream: %s", d.Get("name").(string))
	_, err := conn.CreateLogStream(&cloudwatchlogs.CreateLogStreamInput{
		LogGroupName:  aws.String(d.Get("log_group_name").(string)),
		LogStreamName: aws.String(d.Get("name").(string)),
	})
	if err != nil {
		return fmt.Errorf("Creating CloudWatch Log Stream failed: %s", err)
	}

	d.SetId(d.Get("name").(string))

	return resourceAwsCloudWatchLogStreamRead(d, meta)
}

func resourceAwsCloudWatchLogStreamRead(d *schema.ResourceData, meta interface{}) error {
	conn := meta.(*AWSClient).cloudwatchlogsconn

	group := d.Get("log_group_name").(string)

	ls, exists, err := lookupCloudWatchLogStream(conn, d.Id(), group, nil)
	if err != nil {
		_, err2 := lookupCloudWatchLogGroup(conn, group)
		if err2 != nil {
			return err
		}

		log.Printf("[DEBUG] container CloudWatch group %q Not Found.", group)
		exists = false
	}

	if !exists {
		log.Printf("[DEBUG] CloudWatch Stream %q Not Found. Removing from state", d.Id())
		d.SetId("")
		return nil
	}

	d.Set("arn", ls.Arn)
	d.Set("name", ls.LogStreamName)

	return nil
}

func resourceAwsCloudWatchLogStreamDelete(d *schema.ResourceData, meta interface{}) error {
	conn := meta.(*AWSClient).cloudwatchlogsconn

	log.Printf("[INFO] Deleting CloudWatch Log Stream: %s", d.Id())
	params := &cloudwatchlogs.DeleteLogStreamInput{
		LogGroupName:  aws.String(d.Get("log_group_name").(string)),
		LogStreamName: aws.String(d.Id()),
	}
	_, err := conn.DeleteLogStream(params)
	if err != nil {
		return fmt.Errorf("Error deleting CloudWatch Log Stream: %s", err)
	}

	return nil
}

func lookupCloudWatchLogStream(conn *cloudwatchlogs.CloudWatchLogs,
	name string, logStreamName string, nextToken *string) (*cloudwatchlogs.LogStream, bool, error) {
	input := &cloudwatchlogs.DescribeLogStreamsInput{
		LogStreamNamePrefix: aws.String(name),
		LogGroupName:        aws.String(logStreamName),
		NextToken:           nextToken,
	}
	resp, err := conn.DescribeLogStreams(input)
	if err != nil {
		return nil, true, err
	}

	for _, ls := range resp.LogStreams {
		if *ls.LogStreamName == name {
			return ls, true, nil
		}
	}

	if resp.NextToken != nil {
		return lookupCloudWatchLogStream(conn, name, logStreamName, resp.NextToken)
	}

	return nil, false, nil
}

func validateCloudWatchLogStreamName(v interface{}, k string) (ws []string, errors []error) {
	value := v.(string)
	if regexp.MustCompile(`:`).MatchString(value) {
		errors = append(errors, fmt.Errorf(
			"colons not allowed in %q:", k))
	}
	if len(value) < 1 || len(value) > 512 {
		errors = append(errors, fmt.Errorf(
			"%q must be between 1 and 512 characters: %q", k, value))
	}

	return

}
<|endoftext|>


<commit_before>package stun

import (
	"errors"
	"fmt"
	"net"
)

const (
	familyIPv4 byte = 0x01
	familyIPv6 byte = 0x02
)

// XORMappedAddress implements XOR-MAPPED-ADDRESS attribute.
type XORMappedAddress struct {
	IP   net.IP
	Port int
}

func (a XORMappedAddress) String() string {
	return fmt.Sprintf("%s:%d", a.IP, a.Port)
}

// Is p all zeros?
func isZeros(p net.IP) bool {
	for i := 0; i < len(p); i++ {
		if p[i] != 0 {
			return false
		}
	}
	return true
}

// ErrBadIPLength means that len(IP) is not net.{IPv6len,IPv4len}.
var ErrBadIPLength = errors.New("invalid length if IP value")

// AddTo adds XOR-MAPPED-ADDRESS to m. Can return ErrBadIPLength
// if len(a.IP) is invalid.
func (a *XORMappedAddress) AddTo(m *Message) error {
	var (
		family = familyIPv4
		ip     = a.IP
	)
	if len(a.IP) == net.IPv6len {
		// Optimized for performance. See net.IP.To4 method.
		if isZeros(ip[0:10]) && ip[10] == 0xff && ip[11] == 0xff {
			ip = ip[12:16] // like in ip.To4()
		} else {
			family = familyIPv6
		}
	} else if len(ip) != net.IPv4len {
		return ErrBadIPLength
	}
	value := make([]byte, 32+128)
	value[0] = 0 // first 8 bits are zeroes
	xorValue := make([]byte, net.IPv6len)
	copy(xorValue[4:], m.TransactionID[:])
	bin.PutUint32(xorValue[0:4], magicCookie)
	bin.PutUint16(value[0:2], uint16(family))
	bin.PutUint16(value[2:4], uint16(a.Port^magicCookie>>16))
	xorBytes(value[4:4+len(ip)], ip, xorValue)
	m.Add(AttrXORMappedAddress, value[:4+len(ip)])
	return nil
}

// GetFrom decodes XOR-MAPPED-ADDRESS attribute in message and returns
// error if any. While decoding, a.IP is reused if possible and can be
// rendered to invalid state (e.g. if a.IP was set to IPv6 and then
// IPv4 value were decoded into it), be careful.
//
// Example:
//
// expectedIP := net.ParseIP("213.141.156.236")
// expectedIP.String() // 213.141.156.236, 16 bytes, first 12 of them are zeroes
// expectedPort := 21254
// addr := &XORMappedAddress{
//     IP:   expectedIP,
//     Port: expectedPort,
// }
// // addr were added to message that is decoded as newMessage
// // ...
//
// addr.GetFrom(newMessage)
// addr.IP.String()    // 213.141.156.236, net.IPv4Len
// expectedIP.String() // d58d:9cec::ffff:d58d:9cec, 16 bytes, first 4 are IPv4
// // now we have len(expectedIP) = 16 and len(addr.IP) = 4.
func (a *XORMappedAddress) GetFrom(m *Message) error {
	v, err := m.Get(AttrXORMappedAddress)
	if err != nil {
		return err
	}
	family := byte(bin.Uint16(v[0:2]))
	if family != familyIPv6 && family != familyIPv4 {
		return newDecodeErr("xor-mapped address", "family",
			fmt.Sprintf("bad value %d", family),
		)
	}
	ipLen := net.IPv4len
	if family == familyIPv6 {
		ipLen = net.IPv6len
	}
	// Ensuring len(a.IP) == ipLen and reusing a.IP.
	if len(a.IP) < ipLen {
		a.IP = a.IP[:cap(a.IP)]
		for len(a.IP) < ipLen {
			a.IP = append(a.IP, 0)
		}
	}
	a.IP = a.IP[:ipLen]
	for i := range a.IP {
		a.IP[i] = 0
	}
	a.Port = int(bin.Uint16(v[2:4])) ^ (magicCookie >> 16)
	xorValue := make([]byte, 4+transactionIDSize)
	bin.PutUint32(xorValue[0:4], magicCookie)
	copy(xorValue[4:], m.TransactionID[:])
	xorBytes(a.IP, v[4:], xorValue)
	return nil
}
<commit_msg>a:xoraddr: fix typo in ErrBadIPLength<commit_after>package stun

import (
	"errors"
	"fmt"
	"net"
)

const (
	familyIPv4 byte = 0x01
	familyIPv6 byte = 0x02
)

// XORMappedAddress implements XOR-MAPPED-ADDRESS attribute.
type XORMappedAddress struct {
	IP   net.IP
	Port int
}

func (a XORMappedAddress) String() string {
	return fmt.Sprintf("%s:%d", a.IP, a.Port)
}

// Is p all zeros?
func isZeros(p net.IP) bool {
	for i := 0; i < len(p); i++ {
		if p[i] != 0 {
			return false
		}
	}
	return true
}

// ErrBadIPLength means that len(IP) is not net.{IPv6len,IPv4len}.
var ErrBadIPLength = errors.New("invalid length of IP value")

// AddTo adds XOR-MAPPED-ADDRESS to m. Can return ErrBadIPLength
// if len(a.IP) is invalid.
func (a *XORMappedAddress) AddTo(m *Message) error {
	var (
		family = familyIPv4
		ip     = a.IP
	)
	if len(a.IP) == net.IPv6len {
		// Optimized for performance. See net.IP.To4 method.
		if isZeros(ip[0:10]) && ip[10] == 0xff && ip[11] == 0xff {
			ip = ip[12:16] // like in ip.To4()
		} else {
			family = familyIPv6
		}
	} else if len(ip) != net.IPv4len {
		return ErrBadIPLength
	}
	value := make([]byte, 32+128)
	value[0] = 0 // first 8 bits are zeroes
	xorValue := make([]byte, net.IPv6len)
	copy(xorValue[4:], m.TransactionID[:])
	bin.PutUint32(xorValue[0:4], magicCookie)
	bin.PutUint16(value[0:2], uint16(family))
	bin.PutUint16(value[2:4], uint16(a.Port^magicCookie>>16))
	xorBytes(value[4:4+len(ip)], ip, xorValue)
	m.Add(AttrXORMappedAddress, value[:4+len(ip)])
	return nil
}

// GetFrom decodes XOR-MAPPED-ADDRESS attribute in message and returns
// error if any. While decoding, a.IP is reused if possible and can be
// rendered to invalid state (e.g. if a.IP was set to IPv6 and then
// IPv4 value were decoded into it), be careful.
//
// Example:
//
// expectedIP := net.ParseIP("213.141.156.236")
// expectedIP.String() // 213.141.156.236, 16 bytes, first 12 of them are zeroes
// expectedPort := 21254
// addr := &XORMappedAddress{
//     IP:   expectedIP,
//     Port: expectedPort,
// }
// // addr were added to message that is decoded as newMessage
// // ...
//
// addr.GetFrom(newMessage)
// addr.IP.String()    // 213.141.156.236, net.IPv4Len
// expectedIP.String() // d58d:9cec::ffff:d58d:9cec, 16 bytes, first 4 are IPv4
// // now we have len(expectedIP) = 16 and len(addr.IP) = 4.
func (a *XORMappedAddress) GetFrom(m *Message) error {
	v, err := m.Get(AttrXORMappedAddress)
	if err != nil {
		return err
	}
	family := byte(bin.Uint16(v[0:2]))
	if family != familyIPv6 && family != familyIPv4 {
		return newDecodeErr("xor-mapped address", "family",
			fmt.Sprintf("bad value %d", family),
		)
	}
	ipLen := net.IPv4len
	if family == familyIPv6 {
		ipLen = net.IPv6len
	}
	// Ensuring len(a.IP) == ipLen and reusing a.IP.
	if len(a.IP) < ipLen {
		a.IP = a.IP[:cap(a.IP)]
		for len(a.IP) < ipLen {
			a.IP = append(a.IP, 0)
		}
	}
	a.IP = a.IP[:ipLen]
	for i := range a.IP {
		a.IP[i] = 0
	}
	a.Port = int(bin.Uint16(v[2:4])) ^ (magicCookie >> 16)
	xorValue := make([]byte, 4+transactionIDSize)
	bin.PutUint32(xorValue[0:4], magicCookie)
	copy(xorValue[4:], m.TransactionID[:])
	xorBytes(a.IP, v[4:], xorValue)
	return nil
}
<|endoftext|>


<commit_before>package client

import (
	"fmt"
	"io/ioutil"
	"net/http/httputil"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/client/metadata"
	"github.com/aws/aws-sdk-go/aws/request"
)

// A Config provides configuration to a service client instance.
type Config struct {
	Config                  *aws.Config
	Handlers                request.Handlers
	Endpoint, SigningRegion string
}

// ConfigProvider provides a generic way for a service client to receive
// the ClientConfig without circular dependencies.
type ConfigProvider interface {
	ClientConfig(serviceName string, cfgs ...*aws.Config) Config
}

// A Client implements the base client request and response handling
// used by all service clients.
type Client struct {
	request.Retryer
	metadata.ClientInfo

	Config   aws.Config
	Handlers request.Handlers
}

// New will return a pointer to a new initialized service client.
func New(cfg aws.Config, info metadata.ClientInfo, handlers request.Handlers, options ...func(*Client)) *Client {
	svc := &Client{
		Config:     cfg,
		ClientInfo: info,
		Handlers:   handlers,
	}

	switch retryer, ok := cfg.Retryer.(request.Retryer); {
	case ok:
		svc.Retryer = retryer
	case cfg.Retryer != nil && cfg.Logger != nil:
		s := fmt.Sprintf("WARNING: %T does not implement request.Retryer; using DefaultRetryer instead", cfg.Retryer)
		cfg.Logger.Log(s)
		fallthrough
	default:
		maxRetries := aws.IntValue(cfg.MaxRetries)
		if cfg.MaxRetries == nil || maxRetries == aws.UseServiceDefaultRetries {
			maxRetries = 3
		}
		svc.Retryer = DefaultRetryer{NumMaxRetries: maxRetries}
	}

	svc.AddDebugHandlers()

	for _, option := range options {
		option(svc)
	}

	return svc
}

// NewRequest returns a new Request pointer for the service API
// operation and parameters.
func (c *Client) NewRequest(operation *request.Operation, params interface{}, data interface{}) *request.Request {
	return request.New(c.Config, c.ClientInfo, c.Handlers, c.Retryer, operation, params, data)
}

// AddDebugHandlers injects debug logging handlers into the service to log request
// debug information.
func (c *Client) AddDebugHandlers() {
	if !c.Config.LogLevel.AtLeast(aws.LogDebug) {
		return
	}

	c.Handlers.Send.PushFront(logRequest)
	c.Handlers.Send.PushBack(logResponse)
}

const logReqMsg = `DEBUG: Request %s/%s Details:
---[ REQUEST POST-SIGN ]-----------------------------
%s
-----------------------------------------------------`

func logRequest(r *request.Request) {
	logBody := r.Config.LogLevel.Matches(aws.LogDebugWithHTTPBody)
	dumpedBody, _ := httputil.DumpRequestOut(r.HTTPRequest, logBody)

	if logBody {
		// Reset the request body because dumpRequest will re-wrap the r.HTTPRequest's
		// Body as a NoOpCloser and will not be reset after read by the HTTP
		// client reader.
		r.Body.Seek(r.BodyStart, 0)
		r.HTTPRequest.Body = ioutil.NopCloser(r.Body)
	}

	r.Config.Logger.Log(fmt.Sprintf(logReqMsg, r.ClientInfo.ServiceName, r.Operation.Name, string(dumpedBody)))
}

const logRespMsg = `DEBUG: Response %s/%s Details:
---[ RESPONSE ]--------------------------------------
%s
-----------------------------------------------------`

func logResponse(r *request.Request) {
	var msg = "no reponse data"
	if r.HTTPResponse != nil {
		logBody := r.Config.LogLevel.Matches(aws.LogDebugWithHTTPBody)
		dumpedBody, _ := httputil.DumpResponse(r.HTTPResponse, logBody)
		msg = string(dumpedBody)
	} else if r.Error != nil {
		msg = r.Error.Error()
	}
	r.Config.Logger.Log(fmt.Sprintf(logRespMsg, r.ClientInfo.ServiceName, r.Operation.Name, msg))
}
<commit_msg>fix typo<commit_after>package client

import (
	"fmt"
	"io/ioutil"
	"net/http/httputil"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/client/metadata"
	"github.com/aws/aws-sdk-go/aws/request"
)

// A Config provides configuration to a service client instance.
type Config struct {
	Config                  *aws.Config
	Handlers                request.Handlers
	Endpoint, SigningRegion string
}

// ConfigProvider provides a generic way for a service client to receive
// the ClientConfig without circular dependencies.
type ConfigProvider interface {
	ClientConfig(serviceName string, cfgs ...*aws.Config) Config
}

// A Client implements the base client request and response handling
// used by all service clients.
type Client struct {
	request.Retryer
	metadata.ClientInfo

	Config   aws.Config
	Handlers request.Handlers
}

// New will return a pointer to a new initialized service client.
func New(cfg aws.Config, info metadata.ClientInfo, handlers request.Handlers, options ...func(*Client)) *Client {
	svc := &Client{
		Config:     cfg,
		ClientInfo: info,
		Handlers:   handlers,
	}

	switch retryer, ok := cfg.Retryer.(request.Retryer); {
	case ok:
		svc.Retryer = retryer
	case cfg.Retryer != nil && cfg.Logger != nil:
		s := fmt.Sprintf("WARNING: %T does not implement request.Retryer; using DefaultRetryer instead", cfg.Retryer)
		cfg.Logger.Log(s)
		fallthrough
	default:
		maxRetries := aws.IntValue(cfg.MaxRetries)
		if cfg.MaxRetries == nil || maxRetries == aws.UseServiceDefaultRetries {
			maxRetries = 3
		}
		svc.Retryer = DefaultRetryer{NumMaxRetries: maxRetries}
	}

	svc.AddDebugHandlers()

	for _, option := range options {
		option(svc)
	}

	return svc
}

// NewRequest returns a new Request pointer for the service API
// operation and parameters.
func (c *Client) NewRequest(operation *request.Operation, params interface{}, data interface{}) *request.Request {
	return request.New(c.Config, c.ClientInfo, c.Handlers, c.Retryer, operation, params, data)
}

// AddDebugHandlers injects debug logging handlers into the service to log request
// debug information.
func (c *Client) AddDebugHandlers() {
	if !c.Config.LogLevel.AtLeast(aws.LogDebug) {
		return
	}

	c.Handlers.Send.PushFront(logRequest)
	c.Handlers.Send.PushBack(logResponse)
}

const logReqMsg = `DEBUG: Request %s/%s Details:
---[ REQUEST POST-SIGN ]-----------------------------
%s
-----------------------------------------------------`

func logRequest(r *request.Request) {
	logBody := r.Config.LogLevel.Matches(aws.LogDebugWithHTTPBody)
	dumpedBody, _ := httputil.DumpRequestOut(r.HTTPRequest, logBody)

	if logBody {
		// Reset the request body because dumpRequest will re-wrap the r.HTTPRequest's
		// Body as a NoOpCloser and will not be reset after read by the HTTP
		// client reader.
		r.Body.Seek(r.BodyStart, 0)
		r.HTTPRequest.Body = ioutil.NopCloser(r.Body)
	}

	r.Config.Logger.Log(fmt.Sprintf(logReqMsg, r.ClientInfo.ServiceName, r.Operation.Name, string(dumpedBody)))
}

const logRespMsg = `DEBUG: Response %s/%s Details:
---[ RESPONSE ]--------------------------------------
%s
-----------------------------------------------------`

func logResponse(r *request.Request) {
	var msg = "no response data"
	if r.HTTPResponse != nil {
		logBody := r.Config.LogLevel.Matches(aws.LogDebugWithHTTPBody)
		dumpedBody, _ := httputil.DumpResponse(r.HTTPResponse, logBody)
		msg = string(dumpedBody)
	} else if r.Error != nil {
		msg = r.Error.Error()
	}
	r.Config.Logger.Log(fmt.Sprintf(logRespMsg, r.ClientInfo.ServiceName, r.Operation.Name, msg))
}
<|endoftext|>


<commit_before>package awstesting

import (
	"encoding/json"
	"encoding/xml"
	"fmt"
	"net/url"
	"regexp"
	"sort"
	"testing"

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

// Match is a testing helper to test for testing error by comparing expected
// with a regular expression.
func Match(t *testing.T, regex, expected string) {
	if !regexp.MustCompile(regex).Match([]byte(expected)) {
		t.Errorf("%q\n\tdoes not match /%s/", expected, regex)
	}
}

// AssertURL verifies the expected URL is matches the actual.
func AssertURL(t *testing.T, expect, actual string, msgAndArgs ...interface{}) bool {
	expectURL, err := url.Parse(expect)
	if err != nil {
		t.Errorf(errMsg("unable to parse expected URL", err, msgAndArgs))
		return false
	}
	actualURL, err := url.Parse(actual)
	if err != nil {
		t.Errorf(errMsg("unable to parse actual URL", err, msgAndArgs))
		return false
	}

	assert.Equal(t, expectURL.Host, actualURL.Host, msgAndArgs...)
	assert.Equal(t, expectURL.Scheme, actualURL.Scheme, msgAndArgs...)
	assert.Equal(t, expectURL.Path, actualURL.Path, msgAndArgs...)

	return AssertQuery(t, expectURL.Query().Encode(), actualURL.Query().Encode(), msgAndArgs...)
}

// AssertQuery verifies the expect HTTP query string matches the actual.
func AssertQuery(t *testing.T, expect, actual string, msgAndArgs ...interface{}) bool {
	expectQ, err := url.ParseQuery(expect)
	if err != nil {
		t.Errorf(errMsg("unable to parse expected Query", err, msgAndArgs))
		return false
	}
	actualQ, err := url.ParseQuery(expect)
	if err != nil {
		t.Errorf(errMsg("unable to parse actual Query", err, msgAndArgs))
		return false
	}

	// Make sure the keys are the same
	if !assert.Equal(t, queryValueKeys(expectQ), queryValueKeys(actualQ), msgAndArgs...) {
		return false
	}

	for k, expectQVals := range expectQ {
		sort.Strings(expectQVals)
		actualQVals := actualQ[k]
		sort.Strings(actualQVals)
		assert.Equal(t, expectQVals, actualQVals, msgAndArgs...)
	}

	return true
}

// AssertJSON verifies that the expect json string matches the actual.
func AssertJSON(t *testing.T, expect, actual string, msgAndArgs ...interface{}) bool {
	expectVal := map[string]interface{}{}
	if err := json.Unmarshal([]byte(expect), &expectVal); err != nil {
		t.Errorf(errMsg("unable to parse expected JSON", err, msgAndArgs...))
		return false
	}

	actualVal := map[string]interface{}{}
	if err := json.Unmarshal([]byte(actual), &actualVal); err != nil {
		t.Errorf(errMsg("unable to parse actual JSON", err, msgAndArgs...))
		return false
	}

	return assert.Equal(t, expectVal, actualVal, msgAndArgs...)
}

// AssertXML verifies that the expect xml string matches the actual.
func AssertXML(t *testing.T, expect, actual string, container interface{}, msgAndArgs ...interface{}) bool {
	expectVal := container
	if err := xml.Unmarshal([]byte(expect), &expectVal); err != nil {
		t.Errorf(errMsg("unable to parse expected XML", err, msgAndArgs...))
	}

	actualVal := container
	if err := xml.Unmarshal([]byte(actual), &actualVal); err != nil {
		t.Errorf(errMsg("unable to parse actual XML", err, msgAndArgs...))
	}
	return assert.Equal(t, expectVal, actualVal, msgAndArgs...)
}

func errMsg(baseMsg string, err error, msgAndArgs ...interface{}) string {
	message := messageFromMsgAndArgs(msgAndArgs)
	if message != "" {
		message += ", "
	}
	return fmt.Sprintf("%s%s, %v", message, baseMsg, err)
}

func messageFromMsgAndArgs(msgAndArgs []interface{}) string {
	if len(msgAndArgs) == 0 || msgAndArgs == nil {
		return ""
	}
	if len(msgAndArgs) == 1 {
		return msgAndArgs[0].(string)
	}
	if len(msgAndArgs) > 1 {
		return fmt.Sprintf(msgAndArgs[0].(string), msgAndArgs[1:]...)
	}
	return ""
}

func queryValueKeys(v url.Values) []string {
	keys := make([]string, 0, len(v))
	for k := range v {
		keys = append(keys, k)
	}
	sort.Strings(keys)
	return keys
}
<commit_msg>awstesting: Remove non-testing dependancy on testify assert<commit_after>package awstesting

import (
	"encoding/json"
	"encoding/xml"
	"fmt"
	"net/url"
	"reflect"
	"regexp"
	"sort"
	"testing"
)

// Match is a testing helper to test for testing error by comparing expected
// with a regular expression.
func Match(t *testing.T, regex, expected string) {
	if !regexp.MustCompile(regex).Match([]byte(expected)) {
		t.Errorf("%q\n\tdoes not match /%s/", expected, regex)
	}
}

// AssertURL verifies the expected URL is matches the actual.
func AssertURL(t *testing.T, expect, actual string, msgAndArgs ...interface{}) bool {
	expectURL, err := url.Parse(expect)
	if err != nil {
		t.Errorf(errMsg("unable to parse expected URL", err, msgAndArgs))
		return false
	}
	actualURL, err := url.Parse(actual)
	if err != nil {
		t.Errorf(errMsg("unable to parse actual URL", err, msgAndArgs))
		return false
	}

	equal(t, expectURL.Host, actualURL.Host, msgAndArgs...)
	equal(t, expectURL.Scheme, actualURL.Scheme, msgAndArgs...)
	equal(t, expectURL.Path, actualURL.Path, msgAndArgs...)

	return AssertQuery(t, expectURL.Query().Encode(), actualURL.Query().Encode(), msgAndArgs...)
}

// AssertQuery verifies the expect HTTP query string matches the actual.
func AssertQuery(t *testing.T, expect, actual string, msgAndArgs ...interface{}) bool {
	expectQ, err := url.ParseQuery(expect)
	if err != nil {
		t.Errorf(errMsg("unable to parse expected Query", err, msgAndArgs))
		return false
	}
	actualQ, err := url.ParseQuery(expect)
	if err != nil {
		t.Errorf(errMsg("unable to parse actual Query", err, msgAndArgs))
		return false
	}

	// Make sure the keys are the same
	if !equal(t, queryValueKeys(expectQ), queryValueKeys(actualQ), msgAndArgs...) {
		return false
	}

	for k, expectQVals := range expectQ {
		sort.Strings(expectQVals)
		actualQVals := actualQ[k]
		sort.Strings(actualQVals)
		equal(t, expectQVals, actualQVals, msgAndArgs...)
	}

	return true
}

// AssertJSON verifies that the expect json string matches the actual.
func AssertJSON(t *testing.T, expect, actual string, msgAndArgs ...interface{}) bool {
	expectVal := map[string]interface{}{}
	if err := json.Unmarshal([]byte(expect), &expectVal); err != nil {
		t.Errorf(errMsg("unable to parse expected JSON", err, msgAndArgs...))
		return false
	}

	actualVal := map[string]interface{}{}
	if err := json.Unmarshal([]byte(actual), &actualVal); err != nil {
		t.Errorf(errMsg("unable to parse actual JSON", err, msgAndArgs...))
		return false
	}

	return equal(t, expectVal, actualVal, msgAndArgs...)
}

// AssertXML verifies that the expect xml string matches the actual.
func AssertXML(t *testing.T, expect, actual string, container interface{}, msgAndArgs ...interface{}) bool {
	expectVal := container
	if err := xml.Unmarshal([]byte(expect), &expectVal); err != nil {
		t.Errorf(errMsg("unable to parse expected XML", err, msgAndArgs...))
	}

	actualVal := container
	if err := xml.Unmarshal([]byte(actual), &actualVal); err != nil {
		t.Errorf(errMsg("unable to parse actual XML", err, msgAndArgs...))
	}
	return equal(t, expectVal, actualVal, msgAndArgs...)
}

// objectsAreEqual determines if two objects are considered equal.
//
// This function does no assertion of any kind.
//
// Based on github.com/stretchr/testify/assert.ObjectsAreEqual
// Copied locally to prevent non-test build dependencies on testify
func objectsAreEqual(expected, actual interface{}) bool {
	if expected == nil || actual == nil {
		return expected == actual
	}

	return reflect.DeepEqual(expected, actual)
}

// Equal asserts that two objects are equal.
//
//    assert.Equal(t, 123, 123, "123 and 123 should be equal")
//
// Returns whether the assertion was successful (true) or not (false).
//
// Based on github.com/stretchr/testify/assert.Equal
// Copied locally to prevent non-test build dependencies on testify
func equal(t *testing.T, expected, actual interface{}, msgAndArgs ...interface{}) bool {
	if !objectsAreEqual(expected, actual) {
		t.Errorf("Not Equal:\n\t%#v (expected)\n\t%#v (actual), %s",
			expected, actual, messageFromMsgAndArgs(msgAndArgs))
		return false
	}

	return true
}

func errMsg(baseMsg string, err error, msgAndArgs ...interface{}) string {
	message := messageFromMsgAndArgs(msgAndArgs)
	if message != "" {
		message += ", "
	}
	return fmt.Sprintf("%s%s, %v", message, baseMsg, err)
}

// Based on github.com/stretchr/testify/assert.messageFromMsgAndArgs
// Copied locally to prevent non-test build dependencies on testify
func messageFromMsgAndArgs(msgAndArgs []interface{}) string {
	if len(msgAndArgs) == 0 || msgAndArgs == nil {
		return ""
	}
	if len(msgAndArgs) == 1 {
		return msgAndArgs[0].(string)
	}
	if len(msgAndArgs) > 1 {
		return fmt.Sprintf(msgAndArgs[0].(string), msgAndArgs[1:]...)
	}
	return ""
}

func queryValueKeys(v url.Values) []string {
	keys := make([]string, 0, len(v))
	for k := range v {
		keys = append(keys, k)
	}
	sort.Strings(keys)
	return keys
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"github.com/bmizerany/pat"
	"github.com/moovweb/gokogiri"
	"github.com/moovweb/gokogiri/xml"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"syscall"
)

const Host = "linuxfr.org"

// Create an epub for a news
func News(w http.ResponseWriter, r *http.Request) {
	slug := r.URL.Query().Get(":slug")
	uri := fmt.Sprintf("http://%s/news/%s", Host, slug)
	fmt.Println(uri)
	resp, err := http.Get(uri)
	if err != nil {
		http.NotFound(w, r)
		return
	}
	defer resp.Body.Close()

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		log.Printf("Error on ioutil.ReadAll for %s: %s\n", uri, err)
		http.NotFound(w, r)
		return
	}

	doc, err := gokogiri.ParseHtml(body)
	if err != nil {
		log.Printf("Gokogiri error: %s\n", err)
		http.Error(w, err.Error(), 500)
		return
	}

	buffer := make([]byte, 4096)
	buffer, _ = doc.Root().ToHtml([]byte(xml.DefaultEncoding), buffer)
	w.Write(buffer)
}

// Returns 200 OK if the server is running (for monitoring)
func Status(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintf(w, "OK")
}

func main() {
	// Parse the command-line
	var addr string
	var logs string
	flag.StringVar(&addr, "a", "127.0.0.1:8000", "Bind to this address:port")
	flag.StringVar(&logs, "l", "-", "Use this file for logs")
	flag.Parse()

	// Logging
	if logs != "-" {
		f, err := os.OpenFile(logs, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0644)
		if err != nil {
			log.Fatal("OpenFile: ", err)
		}
		syscall.Dup2(int(f.Fd()), int(os.Stdout.Fd()))
		syscall.Dup2(int(f.Fd()), int(os.Stderr.Fd()))
	}

	// Routing
	m := pat.New()
	m.Get("/status", http.HandlerFunc(Status))
	m.Get("/news/:slug.epub", http.HandlerFunc(News))
	http.Handle("/", m)

	// Start the HTTP server
	log.Printf("Listening on http://%s/\n", addr)
	err := http.ListenAndServe(addr, nil)
	if err != nil {
		log.Fatal("ListenAndServe: ", err)
	}
}
<commit_msg>Working on generating an epub<commit_after>package main

import (
	"archive/zip"
	"flag"
	"fmt"
	"github.com/bmizerany/pat"
	"github.com/moovweb/gokogiri"
	"github.com/moovweb/gokogiri/html"
	"github.com/moovweb/gokogiri/xml"
	"io"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"syscall"
)

type Item struct {
	Id string
	Href string
	Type string
}

type Epub struct {
	Zip *zip.Writer
	// TODO identifier / language / publisher / rights
	Title        string
	Subject      string
	Date         string
	Creator      string
	Contributors []string
	Items        []Item
}

const (
	Host        = "linuxfr.org"
	ContentType = "application/epub+zip"
	Container   = `<?xml version="1.0" encoding="utf-8"?>
<container xmlns="urn:oasis:names:tc:opendocument:xmlns:container" version="1.0">
  <rootfiles>
    <rootfile full-path="EPUB/package.opf" media-type="application/oebps-package+xml"/>
  </rootfiles>
</container>`
)

func NewEpub(w io.Writer) (epub *Epub) {
	z := zip.NewWriter(w)
	epub = &Epub{Zip: z}
	epub.AddFile("mimetype", ContentType)
	epub.AddFile("META-INF/container.xml", Container)
	return
}

func (epub *Epub) AddFile(filename, content string) (err error) {
	f, err := epub.Zip.Create(filename)
	if err != nil {
		log.Println(err)
		return
	}

	_, err = f.Write([]byte(content))
	if err != nil {
		log.Println(err)
		return
	}

	return
}

func (epub *Epub) Close() {
	epub.AddFile("EPUB/package.opf", "XXX") // FIXME
	err := epub.Zip.Close()
	if err != nil {
		log.Println(err)
	}
}

func fetchContent(uri string) (doc *html.HtmlDocument, err error) {
	resp, err := http.Get(uri)
	if err != nil {
		return
	}
	defer resp.Body.Close()

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		log.Printf("Error on ioutil.ReadAll for %s: %s\n", uri, err)
		return
	}

	doc, err = gokogiri.ParseHtml(body)
	if err != nil {
		log.Printf("Gokogiri error: %s\n", err)
		return
	}

	return
}

// Create an epub for a news
func News(w http.ResponseWriter, r *http.Request) {
	w.Header().Add("Content-Type", ContentType)

	slug := r.URL.Query().Get(":slug")
	uri := fmt.Sprintf("http://%s/news/%s", Host, slug)
	doc, err := fetchContent(uri)
	if err != nil {
		http.NotFound(w, r)
		return
	}

	buffer := make([]byte, 4096)
	buffer, _ = doc.Root().ToHtml([]byte(xml.DefaultEncoding), buffer)

	epub := NewEpub(w)
	epub.Close()
}

// Returns 200 OK if the server is running (for monitoring)
func Status(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintf(w, "OK")
}

func main() {
	// Parse the command-line
	var addr string
	var logs string
	flag.StringVar(&addr, "a", "127.0.0.1:8000", "Bind to this address:port")
	flag.StringVar(&logs, "l", "-", "Use this file for logs")
	flag.Parse()

	// Logging
	if logs != "-" {
		f, err := os.OpenFile(logs, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0644)
		if err != nil {
			log.Fatal("OpenFile: ", err)
		}
		syscall.Dup2(int(f.Fd()), int(os.Stdout.Fd()))
		syscall.Dup2(int(f.Fd()), int(os.Stderr.Fd()))
	}

	// Routing
	m := pat.New()
	m.Get("/status", http.HandlerFunc(Status))
	m.Get("/news/:slug.epub", http.HandlerFunc(News))
	http.Handle("/", m)

	// Start the HTTP server
	log.Printf("Listening on http://%s/\n", addr)
	err := http.ListenAndServe(addr, nil)
	if err != nil {
		log.Fatal("ListenAndServe: ", err)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"io"
	"io/ioutil"
	"os"

	io_util "github.com/bborbe/io/util"
	"github.com/bborbe/log"
	"gopkg.in/yaml.v2"
)

var logger = log.DefaultLogger

const (
	PARAMETER_LOGLEVEL = "loglevel"
	PARAMETER_PATH     = "path"
	PARAMETER_WRITE    = "write"
)

func main() {
	defer logger.Close()
	logLevelPtr := flag.String(PARAMETER_LOGLEVEL, log.LogLevelToString(log.ERROR), log.FLAG_USAGE)
	pathPtr := flag.String(PARAMETER_PATH, "", "path")
	writePtr := flag.Bool(PARAMETER_WRITE, false, "write")
	flag.Parse()
	logger.SetLevelThreshold(log.LogStringToLevel(*logLevelPtr))
	logger.Debugf("set log level to %s", *logLevelPtr)

	writer := os.Stdout

	err := do(writer, *pathPtr, *writePtr)
	if err != nil {
		logger.Fatal(err)
		logger.Close()
		os.Exit(1)
	}
	logger.Debug("done")
}

func do(writer io.Writer, path string, write bool) error {
	var err error
	logger.Debugf("format %s and write %v", path, write)
	if len(path) == 0 {
		fmt.Fprintf(writer, "parameter %s missing\n", PARAMETER_PATH)
		return nil
	}
	if path, err = io_util.NormalizePath(path); err != nil {
		logger.Warnf("normalize path: %s failed: %v", path, err)
		return err
	}
	source, err := ioutil.ReadFile(path)
	if err != nil {
		logger.Warnf("read file %s failed: %v", path, err)
		return err
	}
	var data interface{}
	err = yaml.Unmarshal(source, &data)
	if err != nil {
		logger.Warnf("unmarshal %s failed: %v", path, err)
		return err
	}
	content, err := yaml.Marshal(data)
	if err != nil {
		logger.Warnf("marshal failed: %v", err)
		return err
	}
	if write {
		logger.Debug("write file")
		fileInfo, err := readMode(path)
		if err != nil {
			logger.Warnf("get fileinfo failed: %v", err)
			return err
		}
		logger.Debugf("write yaml %s", path)
		return ioutil.WriteFile(path, content, fileInfo.Mode())
	} else {
		logger.Debugf("print content")
		fmt.Fprintf(writer, "%s\n", string(content))
		return nil
	}
}

func readMode(path string) (os.FileInfo, error) {
	f, err := os.Open(path)
	defer f.Close()
	if err != nil {
		return nil, err
	}
	return f.Stat()
}
<commit_msg>set max procs<commit_after>package main

import (
	"flag"
	"fmt"
	"io"
	"io/ioutil"
	"os"

	io_util "github.com/bborbe/io/util"
	"github.com/bborbe/log"
	"gopkg.in/yaml.v2"
	"runtime"
)

const (
	PARAMETER_LOGLEVEL = "loglevel"
	PARAMETER_PATH     = "path"
	PARAMETER_WRITE    = "write"
)

var (
	logger      = log.DefaultLogger
	logLevelPtr = flag.String(PARAMETER_LOGLEVEL, log.LogLevelToString(log.ERROR), log.FLAG_USAGE)
	pathPtr     = flag.String(PARAMETER_PATH, "", "path")
	writePtr    = flag.Bool(PARAMETER_WRITE, false, "write")
)

func main() {
	defer logger.Close()
	flag.Parse()

	logger.SetLevelThreshold(log.LogStringToLevel(*logLevelPtr))
	logger.Debugf("set log level to %s", *logLevelPtr)

	runtime.GOMAXPROCS(runtime.NumCPU())

	writer := os.Stdout

	err := do(writer, *pathPtr, *writePtr)
	if err != nil {
		logger.Fatal(err)
		logger.Close()
		os.Exit(1)
	}
	logger.Debug("done")
}

func do(writer io.Writer, path string, write bool) error {
	var err error
	logger.Debugf("format %s and write %v", path, write)
	if len(path) == 0 {
		fmt.Fprintf(writer, "parameter %s missing\n", PARAMETER_PATH)
		return nil
	}
	if path, err = io_util.NormalizePath(path); err != nil {
		logger.Warnf("normalize path: %s failed: %v", path, err)
		return err
	}
	source, err := ioutil.ReadFile(path)
	if err != nil {
		logger.Warnf("read file %s failed: %v", path, err)
		return err
	}
	var data interface{}
	err = yaml.Unmarshal(source, &data)
	if err != nil {
		logger.Warnf("unmarshal %s failed: %v", path, err)
		return err
	}
	content, err := yaml.Marshal(data)
	if err != nil {
		logger.Warnf("marshal failed: %v", err)
		return err
	}
	if write {
		logger.Debug("write file")
		fileInfo, err := readMode(path)
		if err != nil {
			logger.Warnf("get fileinfo failed: %v", err)
			return err
		}
		logger.Debugf("write yaml %s", path)
		return ioutil.WriteFile(path, content, fileInfo.Mode())
	} else {
		logger.Debugf("print content")
		fmt.Fprintf(writer, "%s\n", string(content))
		return nil
	}
}

func readMode(path string) (os.FileInfo, error) {
	f, err := os.Open(path)
	defer f.Close()
	if err != nil {
		return nil, err
	}
	return f.Stat()
}
<|endoftext|>