<commit_before>/*
 * Copyright (c) 2013 Santiago Arias | Remy Jourde | Carlos Bernal
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

package users

import (
	"encoding/json"
	"errors"
	"html/template"
	"io/ioutil"
	"net/http"
	"time"

	"appengine"

	"github.com/santiaago/purple-wing/helpers"
	"github.com/santiaago/purple-wing/helpers/handlers"
	"github.com/santiaago/purple-wing/helpers/log"
	teamrelshlp "github.com/santiaago/purple-wing/helpers/teamrels"
	templateshlp "github.com/santiaago/purple-wing/helpers/templates"
	tournamentrelshlp "github.com/santiaago/purple-wing/helpers/tournamentrels"

	teammdl "github.com/santiaago/purple-wing/models/team"
	teamrequestmdl "github.com/santiaago/purple-wing/models/teamrequest"
	tournamentmdl "github.com/santiaago/purple-wing/models/tournament"
	usermdl "github.com/santiaago/purple-wing/models/user"
)

type Form struct {
	Username      string
	Name          string
	Email         string
	ErrorUsername string
	ErrorName     string
	ErrorEmail    string
}

type UserData struct {
	Username string
	Name     string
	Email    string
}

//used by json api to send only needed info
type userJsonZip struct {
	Id       int64
	Username string
	Name     string
	Email    string
	Created  time.Time
}

type userJson struct {
	Id           int64
	Username     string
	Name         string
	Email        string
	IsAdmin      bool
	Auth         string
	Created      time.Time
	Teams        []teamJsonZip
	Tournaments  []tournamentJsonZip
	TeamRequests []teamRequestJsonZip
}

type teamJsonZip struct {
	Id   int64
	Name string
}

type tournamentJsonZip struct {
	Id   int64
	Name string
}

type teamRequestJsonZip struct {
	Id     int64
	TeamId int64
	UserId int64
}

// Show handler
func Show(w http.ResponseWriter, r *http.Request) {
	c := appengine.NewContext(r)

	userId, err := handlers.PermalinkID(r, c, 3)
	if err != nil {
		http.Redirect(w, r, "/m/users/", http.StatusFound)
		return
	}

	funcs := template.FuncMap{
		"Profile": func() bool { return true },
	}

	t := template.Must(template.New("tmpl_user_show").
		Funcs(funcs).
		ParseFiles("templates/user/show.html",
		"templates/user/info.html",
		"templates/user/teams.html",
		"templates/user/tournaments.html",
		"templates/user/requests.html"))

	var user *usermdl.User
	user, err = usermdl.ById(c, userId)
	if err != nil {
		helpers.Error404(w)
		return
	}

	teams := usermdl.Teams(c, userId)
	tournaments := tournamentrelshlp.Tournaments(c, userId)
	teamRequests := teamrelshlp.TeamsRequests(c, teams)

	userData := struct {
		User         *usermdl.User
		Teams        []*teammdl.Team
		Tournaments  []*tournamentmdl.Tournament
		TeamRequests []*teamrequestmdl.TeamRequest
	}{
		user,
		teams,
		tournaments,
		teamRequests,
	}

	templateshlp.RenderWithData(w, r, c, t, userData, funcs, "renderUserShow")
}

// json index user handler
func IndexJson(w http.ResponseWriter, r *http.Request, u *usermdl.User) error {
	c := appengine.NewContext(r)

	if r.Method == "GET" {
		users := usermdl.FindAll(c)
		usersJson := make([]userJson, len(users))
		counterUsers := 0
		for _, user := range users {
			usersJson[counterUsers].Id = user.Id
			usersJson[counterUsers].Username = user.Username
			usersJson[counterUsers].Name = user.Name
			usersJson[counterUsers].Email = user.Email
			usersJson[counterUsers].Created = user.Created
			counterUsers++
		}
		return templateshlp.RenderJson(w, c, usersJson)

	} else {
		return helpers.BadRequest{errors.New("not supported.")}
	}
}

// Json show user handler
func ShowJson(w http.ResponseWriter, r *http.Request, u *usermdl.User) error {
	c := appengine.NewContext(r)
	log.Infof(c, "User Show Json Handler")

	if r.Method == "GET" {

		userId, err := handlers.PermalinkID(r, c, 4)
		if err != nil {
			return helpers.BadRequest{err}
		}

		// get user
		var user *usermdl.User
		user, err = usermdl.ById(c, userId)
		if err != nil {
			return helpers.BadRequest{err}
		}

		// set teams info in user json
		teams := usermdl.Teams(c, userId)
		teamsJson := make([]teamJsonZip, len(teams))
		counterTeams := 0
		for _, team := range teams {
			teamsJson[counterTeams].Id = team.Id
			teamsJson[counterTeams].Name = team.Name
			counterTeams++
		}

		// set tournament info in user json
		tournaments := tournamentrelshlp.Tournaments(c, userId)
		tournamentsJson := make([]tournamentJsonZip, len(tournaments))
		counterTournaments := 0
		for _, tournament := range tournaments {
			tournamentsJson[counterTournaments].Id = tournament.Id
			tournamentsJson[counterTournaments].Name = tournament.Name
			counterTournaments++
		}

		// set request info in user json
		teamRequests := teamrelshlp.TeamsRequests(c, teams)
		teamRequestsJson := make([]teamRequestJsonZip, len(teamRequests))
		counterRequests := 0
		for _, request := range teamRequests {
			teamRequestsJson[counterRequests].Id = request.Id
			teamRequestsJson[counterRequests].UserId = request.UserId
			teamRequestsJson[counterRequests].TeamId = request.TeamId
			counterRequests++
		}

		// copy to json data
		var userJson userJson
		userJson.Id = user.Id
		userJson.Username = user.Username
		userJson.Name = user.Name
		userJson.Email = user.Email
		userJson.IsAdmin = user.IsAdmin
		userJson.Auth = user.Auth
		userJson.Created = user.Created
		userJson.Teams = teamsJson
		userJson.TeamRequests = teamRequestsJson
		userJson.Tournaments = tournamentsJson

		return templateshlp.RenderJson(w, c, userJson)
	} else {
		return helpers.BadRequest{errors.New("not supported.")}
	}
}

// json update user handler
func UpdateJson(w http.ResponseWriter, r *http.Request, u *usermdl.User) error {
	c := appengine.NewContext(r)

	if r.Method == "POST" {
		userId, err := handlers.PermalinkID(r, c, 4)

		if err != nil {
			return helpers.BadRequest{err}
		}
		if userId != u.Id {
			return helpers.BadRequest{errors.New("User cannot be updated")}
		}

		// only work on name other values should not be editable
		defer r.Body.Close()
		body, err := ioutil.ReadAll(r.Body)
		if err != nil {
			return helpers.InternalServerError{errors.New("Error when reading request body")}
		}

		var updatedData UserData
		err = json.Unmarshal(body, &updatedData)
		if err != nil {
			return helpers.InternalServerError{errors.New("Error when decoding request body")}
		}
		if helpers.IsEmailValid(updatedData.Email) && updatedData.Email != u.Email {
			u.Email = updatedData.Email
			usermdl.Update(c, u)
		}

		// return updated user
		return templateshlp.RenderJson(w, c, u)
	} else {
		return helpers.BadRequest{errors.New("not supported.")}
	}
}
<commit_msg>refactor user controller #231<commit_after>/*
 * Copyright (c) 2013 Santiago Arias | Remy Jourde | Carlos Bernal
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

package users

import (
	"encoding/json"
	"errors"
	"html/template"
	"io/ioutil"
	"net/http"
	"time"

	"appengine"

	"github.com/santiaago/purple-wing/helpers"
	"github.com/santiaago/purple-wing/helpers/handlers"
	"github.com/santiaago/purple-wing/helpers/log"
	teamrelshlp "github.com/santiaago/purple-wing/helpers/teamrels"
	templateshlp "github.com/santiaago/purple-wing/helpers/templates"
	tournamentrelshlp "github.com/santiaago/purple-wing/helpers/tournamentrels"

	teammdl "github.com/santiaago/purple-wing/models/team"
	teamrequestmdl "github.com/santiaago/purple-wing/models/teamrequest"
	tournamentmdl "github.com/santiaago/purple-wing/models/tournament"
	usermdl "github.com/santiaago/purple-wing/models/user"
)

type Form struct {
	Username      string
	Name          string
	Email         string
	ErrorUsername string
	ErrorName     string
	ErrorEmail    string
}

type UserData struct {
	Username string
	Name     string
	Email    string
}

//used by json api to send only needed info
type userJsonZip struct {
	Id       int64
	Username string
	Name     string
	Email    string
	Created  time.Time
}

type userJson struct {
	Id           int64
	Username     string
	Name         string
	Email        string
	IsAdmin      bool
	Auth         string
	Created      time.Time
	Teams        []teamJsonZip
	Tournaments  []tournamentJsonZip
	TeamRequests []teamRequestJsonZip
}

type teamJsonZip struct {
	Id   int64
	Name string
}

type tournamentJsonZip struct {
	Id   int64
	Name string
}

type teamRequestJsonZip struct {
	Id     int64
	TeamId int64
	UserId int64
}

// copy function from model data structure to json zip data structure
func (t *teamJsonZip) Copy(teamToCopy *teammdl.Team) {
	t.Id = teamToCopy.Id
	t.Name = teamToCopy.Name
}

// create an array of team json zip data struture from an array of datastore Team pointers
func createTeamsJsonZip(teamsToCopy []*teammdl.Team) []teamJsonZip {
	teams := make([]teamJsonZip, len(teamsToCopy))
	counterTeams := 0
	for _, team := range teamsToCopy {
		(&teams[counterTeams]).Copy(team)
		counterTeams++
	}
	return teams
}

// copy function from model data structure to json zip data structure
func (t *tournamentJsonZip) Copy(tournamentToCopy *tournamentmdl.Tournament) {
	t.Id = tournamentToCopy.Id
	t.Name = tournamentToCopy.Name
}

// create an array of team json zip data struture from an array of datastore Team pointers
func createTournamentsJsonZip(tournamentsToCopy []*tournamentmdl.Tournament) []tournamentJsonZip {
	tournaments := make([]tournamentJsonZip, len(tournamentsToCopy))
	counterTournament := 0
	for _, tournament := range tournamentsToCopy {
		(&tournaments[counterTournament]).Copy(tournament)
		counterTournament++
	}
	return tournaments
}

func (tr *teamRequestJsonZip) Copy(teamRequestToCopy *teamrequestmdl.TeamRequest) {
	tr.Id = teamRequestToCopy.Id
	tr.UserId = teamRequestToCopy.UserId
	tr.TeamId = teamRequestToCopy.TeamId
}

func createTeamRequestsJsonZip(teamRequestsToCopy []*teamrequestmdl.TeamRequest) []teamRequestJsonZip {
	teamRequests := make([]teamRequestJsonZip, len(teamRequestsToCopy))
	counterTeamRequest := 0
	for _, teamRequest := range teamRequestsToCopy {
		(&teamRequests[counterTeamRequest]).Copy(teamRequest)
		counterTeamRequest++
	}
	return teamRequests
}

func (u *userJson) Copy(userToCopy *usermdl.User, teamsToCopy []teamJsonZip, teamRequestsToCopy []teamRequestJsonZip, tournamentsToCopy []tournamentJsonZip) {
	u.Id = userToCopy.Id
	u.Username = userToCopy.Username
	u.Name = userToCopy.Name
	u.Email = userToCopy.Email
	u.IsAdmin = userToCopy.IsAdmin
	u.Auth = userToCopy.Auth
	u.Created = userToCopy.Created
	u.Teams = teamsToCopy
	u.TeamRequests = teamRequestsToCopy
	u.Tournaments = tournamentsToCopy
}

func (u *userJsonZip) Copy(userToCopy *usermdl.User) {
	u.Id = userToCopy.Id
	u.Username = userToCopy.Username
	u.Name = userToCopy.Name
	u.Email = userToCopy.Email
	u.Created = userToCopy.Created
}

// Show handler
func Show(w http.ResponseWriter, r *http.Request) {
	c := appengine.NewContext(r)

	userId, err := handlers.PermalinkID(r, c, 3)
	if err != nil {
		http.Redirect(w, r, "/m/users/", http.StatusFound)
		return
	}

	funcs := template.FuncMap{
		"Profile": func() bool { return true },
	}

	t := template.Must(template.New("tmpl_user_show").
		Funcs(funcs).
		ParseFiles("templates/user/show.html",
		"templates/user/info.html",
		"templates/user/teams.html",
		"templates/user/tournaments.html",
		"templates/user/requests.html"))

	var user *usermdl.User
	user, err = usermdl.ById(c, userId)
	if err != nil {
		helpers.Error404(w)
		return
	}

	teams := usermdl.Teams(c, userId)
	tournaments := tournamentrelshlp.Tournaments(c, userId)
	teamRequests := teamrelshlp.TeamsRequests(c, teams)

	userData := struct {
		User         *usermdl.User
		Teams        []*teammdl.Team
		Tournaments  []*tournamentmdl.Tournament
		TeamRequests []*teamrequestmdl.TeamRequest
	}{
		user,
		teams,
		tournaments,
		teamRequests,
	}

	templateshlp.RenderWithData(w, r, c, t, userData, funcs, "renderUserShow")
}

// json index user handler
func IndexJson(w http.ResponseWriter, r *http.Request, u *usermdl.User) error {
	c := appengine.NewContext(r)

	if r.Method == "GET" {
		users := usermdl.FindAll(c)
		usersJson := make([]userJson, len(users))
		counterUsers := 0
		for _, user := range users {
			usersJson[counterUsers].Id = user.Id
			usersJson[counterUsers].Username = user.Username
			usersJson[counterUsers].Name = user.Name
			usersJson[counterUsers].Email = user.Email
			usersJson[counterUsers].Created = user.Created
			counterUsers++
		}
		return templateshlp.RenderJson(w, c, usersJson)
	} else {
		return helpers.BadRequest{errors.New("not supported.")}
	}
}

// Json show user handler
func ShowJson(w http.ResponseWriter, r *http.Request, u *usermdl.User) error {
	c := appengine.NewContext(r)
	log.Infof(c, "User Show Json Handler")

	if r.Method == "GET" {

		userId, err := handlers.PermalinkID(r, c, 4)
		if err != nil {
			return helpers.BadRequest{err}
		}

		// get user
		var user *usermdl.User
		user, err = usermdl.ById(c, userId)
		if err != nil {
			return helpers.BadRequest{err}
		}
		teams := usermdl.Teams(c, userId)
		teamsJson := createTeamsJsonZip(teams)
		tournaments := tournamentrelshlp.Tournaments(c, userId)
		tournamentsJson := createTournamentsJsonZip(tournaments)
		teamRequests := teamrelshlp.TeamsRequests(c, teams)
		teamRequestsJson := createTeamRequestsJsonZip(teamRequests)
		// copy to json data
		var userJson userJson
		(&userJson).Copy(user, teamsJson, teamRequestsJson, tournamentsJson)

		return templateshlp.RenderJson(w, c, userJson)
	} else {
		return helpers.BadRequest{errors.New("not supported.")}
	}
}

// json update user handler
func UpdateJson(w http.ResponseWriter, r *http.Request, u *usermdl.User) error {
	c := appengine.NewContext(r)

	if r.Method == "POST" {
		userId, err := handlers.PermalinkID(r, c, 4)

		if err != nil {
			return helpers.BadRequest{err}
		}
		if userId != u.Id {
			return helpers.BadRequest{errors.New("User cannot be updated")}
		}

		// only work on name other values should not be editable
		defer r.Body.Close()
		body, err := ioutil.ReadAll(r.Body)
		if err != nil {
			return helpers.InternalServerError{errors.New("Error when reading request body")}
		}

		var updatedData UserData
		err = json.Unmarshal(body, &updatedData)
		if err != nil {
			return helpers.InternalServerError{errors.New("Error when decoding request body")}
		}
		if helpers.IsEmailValid(updatedData.Email) && updatedData.Email != u.Email {
			u.Email = updatedData.Email
			usermdl.Update(c, u)
		}
		var uJson userJsonZip
		(&uJson).Copy(u)
		return templateshlp.RenderJson(w, c, uJson)
	} else {
		return helpers.BadRequest{errors.New("not supported.")}
	}
}
<|endoftext|>


<commit_before>package bigquery

import (
	"errors"
	"github.com/viant/endly"
	"google.golang.org/api/bigquery/v2"
	"time"
)

type JobWaitRequest struct {
	Job *bigquery.JobReference
}

func (s *service) jobWait(context *endly.Context, request *JobWaitRequest) (response *bigquery.Job, err error) {
	err = s.RunInBackground(context, func() error {
		response, err = s.waitForOperationCompletion(context, request.Job)
		return err
	})
	return response, err
}

func (s *service) waitForOperationCompletion(context *endly.Context, job *bigquery.JobReference) (*bigquery.Job, error) {
	client, err := GetClient(context)
	if err != nil {
		return nil, err
	}
	service := bigquery.NewJobsService(client.service)
	for {
		getCall := service.Get(job.ProjectId, job.JobId)
		getCall.Context(client.Context())
		job, err := getCall.Do()
		if err != nil {
			return nil, err
		}
		if job.Status.State == doneStatus {
			return job, err
		}
		time.Sleep(time.Second)
	}
}

//Validate checks if request is valid
func (r *JobWaitRequest) Validate() error {
	if r.Job == nil {
		return errors.New("job was empty")
	}
	return nil
}
<commit_msg>patched wait<commit_after>package bigquery

import (
	"errors"
	"github.com/viant/endly"
	"google.golang.org/api/bigquery/v2"
	"strings"
	"time"
)

type JobWaitRequest struct {
	Job *bigquery.JobReference
}

func (s *service) jobWait(context *endly.Context, request *JobWaitRequest) (response *bigquery.Job, err error) {
	err = s.RunInBackground(context, func() error {
		response, err = s.waitForOperationCompletion(context, request.Job)
		return err
	})
	return response, err
}

func (s *service) waitForOperationCompletion(context *endly.Context, job *bigquery.JobReference) (*bigquery.Job, error) {
	client, err := GetClient(context)
	if err != nil {
		return nil, err
	}
	service := bigquery.NewJobsService(client.service)
	for {
		getCall := service.Get(job.ProjectId, job.JobId)
		getCall.Context(client.Context())
		job, err := getCall.Do()
		if err != nil {
			if strings.Contains(err.Error(), "backendError") {
				time.Sleep(time.Second)
				continue
			}
			return nil, err
		}

		if job.Status.State == doneStatus {
			return job, err
		}
		time.Sleep(time.Second)
	}
}

//Validate checks if request is valid
func (r *JobWaitRequest) Validate() error {
	if r.Job == nil {
		return errors.New("job was empty")
	}
	return nil
}
<|endoftext|>


<commit_before>package ccv3

import (
	"code.cloudfoundry.org/cli/api/cloudcontroller/ccerror"
	"code.cloudfoundry.org/cli/api/cloudcontroller/ccv3/internal"
	"code.cloudfoundry.org/cli/api/cloudcontroller/jsonry"
)

// ServiceOffering represents a Cloud Controller V3 Service Offering.
type ServiceOffering struct {
	// GUID is a unique service offering identifier.
	GUID string
	// Name is the name of the service offering.
	Name string
	// ServiceBrokerName is the name of the service broker
	ServiceBrokerName string
	// ServiceBrokerGUID is the guid of the service broker
	ServiceBrokerGUID string `jsonry:"relationships.service_broker.data.guid"`
	// Description of the service offering
	Description string

	Metadata *Metadata
}

func (so *ServiceOffering) UnmarshalJSON(data []byte) error {
	return jsonry.Unmarshal(data, so)
}

// GetServiceOffering lists service offering with optional filters.
func (client *Client) GetServiceOfferings(query ...Query) ([]ServiceOffering, Warnings, error) {
	var tempResources []*ServiceOffering
	var resources []ServiceOffering

	query = append(query, Query{Key: FieldsServiceBroker, Values: []string{"name", "guid"}})

	included, warnings, err := client.MakeListRequest(RequestParams{
		RequestName:  internal.GetServiceOfferingsRequest,
		Query:        query,
		ResponseBody: ServiceOffering{},
		AppendToList: func(item interface{}) error {
			myItem := item.(ServiceOffering)
			tempResources = append(tempResources, &myItem)
			return nil
		},
	})

	brokerNameLookup := make(map[string]string)
	for _, b := range included.ServiceBrokers {
		brokerNameLookup[b.GUID] = b.Name
	}

	for _, offering := range tempResources {
		offering.ServiceBrokerName = brokerNameLookup[offering.ServiceBrokerGUID]
		resources = append(resources, *offering)
	}

	return resources, warnings, err
}

func (client *Client) GetServiceOfferingByNameAndBroker(serviceOfferingName, serviceBrokerName string) (ServiceOffering, Warnings, error) {
	query := []Query{{Key: NameFilter, Values: []string{serviceOfferingName}}}
	if serviceBrokerName != "" {
		query = append(query, Query{Key: ServiceBrokerNamesFilter, Values: []string{serviceBrokerName}})
	}

	offerings, warnings, err := client.GetServiceOfferings(query...)
	if err != nil {
		return ServiceOffering{}, warnings, err
	}

	switch len(offerings) {
	case 0:
		return ServiceOffering{}, warnings, ccerror.ServiceOfferingNotFoundError{
			ServiceOfferingName: serviceOfferingName,
			ServiceBrokerName:   serviceBrokerName,
		}
	case 1:
		return offerings[0], warnings, nil
	default:
		return ServiceOffering{}, warnings, ccerror.ServiceOfferingNameAmbiguityError{
			ServiceOfferingName: serviceOfferingName,
			ServiceBrokerNames:  extractServiceBrokerNames(offerings),
		}
	}
}

func (client *Client) PurgeServiceOffering(serviceOfferingGUID string) (Warnings, error) {
	_, warnings, err := client.MakeRequest(RequestParams{
		RequestName: internal.DeleteServiceOfferingRequest,
		URIParams:   internal.Params{"service_offering_guid": serviceOfferingGUID},
		Query:       []Query{{Key: Purge, Values: []string{"true"}}},
	})
	return warnings, err
}

func extractServiceBrokerNames(offerings []ServiceOffering) (result []string) {
	for _, o := range offerings {
		result = append(result, o.ServiceBrokerName)
	}
	return
}
<commit_msg>Change pointer usage to iteration by index to change resources<commit_after>package ccv3

import (
	"code.cloudfoundry.org/cli/api/cloudcontroller/ccerror"
	"code.cloudfoundry.org/cli/api/cloudcontroller/ccv3/internal"
	"code.cloudfoundry.org/cli/api/cloudcontroller/jsonry"
)

// ServiceOffering represents a Cloud Controller V3 Service Offering.
type ServiceOffering struct {
	// GUID is a unique service offering identifier.
	GUID string
	// Name is the name of the service offering.
	Name string
	// ServiceBrokerName is the name of the service broker
	ServiceBrokerName string
	// ServiceBrokerGUID is the guid of the service broker
	ServiceBrokerGUID string `jsonry:"relationships.service_broker.data.guid"`
	// Description of the service offering
	Description string

	Metadata *Metadata
}

func (so *ServiceOffering) UnmarshalJSON(data []byte) error {
	return jsonry.Unmarshal(data, so)
}

// GetServiceOffering lists service offering with optional filters.
func (client *Client) GetServiceOfferings(query ...Query) ([]ServiceOffering, Warnings, error) {
	var resources []ServiceOffering

	query = append(query, Query{Key: FieldsServiceBroker, Values: []string{"name", "guid"}})

	included, warnings, err := client.MakeListRequest(RequestParams{
		RequestName:  internal.GetServiceOfferingsRequest,
		Query:        query,
		ResponseBody: ServiceOffering{},
		AppendToList: func(item interface{}) error {
			resources = append(resources, item.(ServiceOffering))
			return nil
		},
	})

	brokerNameLookup := make(map[string]string)
	for _, b := range included.ServiceBrokers {
		brokerNameLookup[b.GUID] = b.Name
	}

	for i, _ := range resources {
		resources[i].ServiceBrokerName = brokerNameLookup[resources[i].ServiceBrokerGUID]
	}

	return resources, warnings, err
}

func (client *Client) GetServiceOfferingByNameAndBroker(serviceOfferingName, serviceBrokerName string) (ServiceOffering, Warnings, error) {
	query := []Query{{Key: NameFilter, Values: []string{serviceOfferingName}}}
	if serviceBrokerName != "" {
		query = append(query, Query{Key: ServiceBrokerNamesFilter, Values: []string{serviceBrokerName}})
	}

	offerings, warnings, err := client.GetServiceOfferings(query...)
	if err != nil {
		return ServiceOffering{}, warnings, err
	}

	switch len(offerings) {
	case 0:
		return ServiceOffering{}, warnings, ccerror.ServiceOfferingNotFoundError{
			ServiceOfferingName: serviceOfferingName,
			ServiceBrokerName:   serviceBrokerName,
		}
	case 1:
		return offerings[0], warnings, nil
	default:
		return ServiceOffering{}, warnings, ccerror.ServiceOfferingNameAmbiguityError{
			ServiceOfferingName: serviceOfferingName,
			ServiceBrokerNames:  extractServiceBrokerNames(offerings),
		}
	}
}

func (client *Client) PurgeServiceOffering(serviceOfferingGUID string) (Warnings, error) {
	_, warnings, err := client.MakeRequest(RequestParams{
		RequestName: internal.DeleteServiceOfferingRequest,
		URIParams:   internal.Params{"service_offering_guid": serviceOfferingGUID},
		Query:       []Query{{Key: Purge, Values: []string{"true"}}},
	})
	return warnings, err
}

func extractServiceBrokerNames(offerings []ServiceOffering) (result []string) {
	for _, o := range offerings {
		result = append(result, o.ServiceBrokerName)
	}
	return
}
<|endoftext|>


<commit_before><commit_msg>Fixed minor errors blocking compilation<commit_after><|endoftext|>


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

package test

import (
	"context"
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"path"
	"path/filepath"
	"reflect"
	"runtime"
	"testing"

	"google.golang.org/grpc"

	"sync"

	istio_mixer_v1 "istio.io/api/mixer/v1"
	"istio.io/istio/mixer/pkg/adapter"
	"istio.io/istio/mixer/pkg/attribute"
	"istio.io/istio/mixer/pkg/config/storetest"
	"istio.io/istio/mixer/pkg/server"
	"istio.io/istio/mixer/pkg/template"
	template2 "istio.io/istio/mixer/template"
)

// Utility to help write Mixer-adapter integration tests.

type (
	// Scenario fully defines an adapter integration test
	Scenario struct {
		// Configs is a list of CRDs that Mixer will read.
		Configs []string

		// ParallelCalls is a list of test calls to be made to Mixer
		// in parallel.
		ParallelCalls []Call

		// Setup is a callback function that will be called at the beginning of the test. It is
		// meant to be used for things like starting a local backend server. Setup function returns a
		// context (interface{}) which is passed back into the Teardown and the GetState functions.
		// pass nil if no setup needed
		Setup SetupFn

		// Teardown is a callback function that will be called at the end of the test. It is
		// meant to be used for things like stopping a local backend server that might have been started during Setup.
		// pass nil if no teardown is needed
		Teardown TeardownFn

		// GetState lets the test provide any (interface{}) adapter specific data to be part of baseline.
		// Example: for prometheus adapter, the actual metric reported to the local backend can be embedded into the
		// expected json baseline.
		// pass nil if no adapter specific state is part of baseline.
		GetState GetStateFn

		// Templates supported by Mixer.
		// If `tmpls` is not specified, the default templates inside istio.io/istio/mixer/template.SupportedTmplInfo
		// are made available to the Mixer.
		tmpls map[string]template.Info

		// Want is the expected serialized json for the Result struct.
		// Result.AdapterState is what the callback function `getState`, passed to `RunTest`, returns.
		//
		// New test can start of with an empty "{}" string and then
		// get the baseline from the failure logs upon execution.
		Want string
	}
	// Call represents the input to make a call to Mixer
	Call struct {
		// CallKind can be either CHECK or REPORT
		CallKind CallKind
		// Attrs to call the Mixer with.
		Attrs map[string]interface{}
		// Quotas info to call the Mixer with.
		Quotas map[string]istio_mixer_v1.CheckRequest_QuotaParams
	}
	// CallKind represents the call to make; check or report.
	CallKind int32

	// Result represents the test baseline
	Result struct {
		// AdapterState represents adapter specific baseline data. AdapterState is what the callback function
		// `getState`, passed to `RunTest`, returns.
		AdapterState interface{} `json:"AdapterState"`
		// Returns represents the return data from calls to Mixer
		Returns []Return `json:"Returns"`
	}
	// Return represents the return data from a call to Mixer
	Return struct {
		// Check is the response from a check call to Mixer
		Check adapter.CheckResult `json:"Check"`
		// Quota is the response from a check call to Mixer
		Quota map[string]adapter.QuotaResult `json:"Quota"`
		// Error is the error from call to Mixer
		Error error `json:"Error"`
	}
)

const (
	// CHECK for  Mixer Check
	CHECK CallKind = iota
	// REPORT for  Mixer Report
	REPORT
)

type (
	// SetupFn functions will be called at the beginning of the test
	SetupFn func() (ctx interface{}, err error)
	// TeardownFn functions will be called at the end of the test
	TeardownFn func(ctx interface{})
	// GetStateFn returns the adapter specific state upon test execution. The return value becomes part of
	// expected Result.AdapterState.
	GetStateFn func(ctx interface{}) (interface{}, error)
)

// RunTest performs a Mixer adapter integration test using in-memory Mixer and config store.
// NOTE: DO NOT invoke this using `t.Run(string, func)` because that would execute func in a separate go routine.
// Separate go routines would cause the test to fail randomly because fixed ports cannot be assigned and cleaned up
// deterministically on each iteration.
//
// * adapterInfo provides the InfoFn for the adapter under test.
// * Scenario provide the adapter/handler/rule configs along with the call parameters (check or report, and attributes)
//   Optionally, it also takes the test specific SetupFn, TeardownFn, GetStateFn and list of supported templates.
func RunTest(
	t *testing.T,
	adapterInfo adapter.InfoFn,
	scenario Scenario,
) {

	// Let the test do some initial setup.
	var ctx interface{}
	var err error
	if scenario.Setup != nil {
		ctx, err = scenario.Setup()
		// Teardown the initial setup
		if scenario.Teardown != nil {
			defer scenario.Teardown(ctx)
		}
		if err != nil {
			t.Fatalf("initial setup failed: %v", err)
		}
	}

	if len(scenario.tmpls) == 0 {
		scenario.tmpls = template2.SupportedTmplInfo
	}

	// Start Mixer
	var args *server.Args
	var env *server.Server
	if args, err = getServerArgs(scenario.tmpls, []adapter.InfoFn{adapterInfo}, scenario.Configs); err != nil {
		t.Fatalf("fail to create mixer args: %v", err)
	}

	// Setting zero will make Mixer pick any available port.
	args.APIPort = 0
	args.MonitoringPort = 0

	if env, err = server.New(args); err != nil {
		t.Fatalf("fail to new mixer: %v", err)
	}
	env.Run()
	defer closeHelper(env)

	// Connect the client to Mixer
	conn, err := grpc.Dial(env.Addr().String(), grpc.WithInsecure())
	if err != nil {
		t.Fatalf("Unable to connect to gRPC server: %v", err)
	}
	client := istio_mixer_v1.NewMixerClient(conn)
	defer closeHelper(conn)

	// Invoke calls async
	var wg sync.WaitGroup
	wg.Add(len(scenario.ParallelCalls))

	got := Result{Returns: make([]Return, len(scenario.ParallelCalls))}
	for i, call := range scenario.ParallelCalls {
		go execute(call, args.ConfigIdentityAttribute, args.ConfigIdentityAttributeDomain, client, got.Returns, i, &wg)
	}
	// wait for calls to finish
	wg.Wait()

	// get adapter state. NOTE: We are doing marshal and then unmarshal it back into generic interface{}.
	// This is done to make getState output into generic json map or array; which is exactly what we get when un-marshalling
	// the baseline json. Without this, deep equality on un-marshalled baseline AdapterState would defer
	// from the rich object returned by getState function.
	if scenario.GetState != nil {
		adptState, _ := scenario.GetState(ctx)
		var adptStateBytes []byte
		if adptStateBytes, err = json.Marshal(adptState); err != nil {
			t.Fatalf("Unable to convert %v into json: %v", adptState, err)
		}
		if err = json.Unmarshal(adptStateBytes, &got.AdapterState); err != nil {
			t.Fatalf("Unable to unmarshal %s into interface{}: %v", string(adptStateBytes), err)
		}
	}

	var want Result
	if err = json.Unmarshal([]byte(scenario.Want), &want); err != nil {
		t.Fatalf("Unable to unmarshal %s into Result: %v", scenario.Want, err)
	}

	// compare
	if !reflect.DeepEqual(want, got) {
		gotJSON, err := json.MarshalIndent(got, "", " ")
		if err != nil {
			t.Fatalf("Unable to convert %v into json: %v", got, err)
		}
		wantJSON, err := json.MarshalIndent(want, "", " ")
		if err != nil {
			t.Fatalf("Unable to convert %v into json: %v", want, err)
		}
		t.Errorf("\ngot=>\n%s\nwant=>\n%s", gotJSON, wantJSON)
	}
}

func execute(c Call, idAttr string, idAttrDomain string, client istio_mixer_v1.MixerClient, returns []Return, i int, wg *sync.WaitGroup) {
	ret := Return{}
	switch c.CallKind {
	case CHECK:
		req := istio_mixer_v1.CheckRequest{
			Attributes: getAttrBag(c.Attrs,
				idAttr,
				idAttrDomain),
			Quotas: c.Quotas,
		}

		result, resultErr := client.Check(context.Background(), &req)
		result.Precondition.ReferencedAttributes = istio_mixer_v1.ReferencedAttributes{}
		ret.Error = resultErr
		if len(c.Quotas) > 0 {
			ret.Quota = make(map[string]adapter.QuotaResult)
			for k := range c.Quotas {
				ret.Quota[k] = adapter.QuotaResult{
					Amount: result.Quotas[k].GrantedAmount, ValidDuration: result.Quotas[k].ValidDuration,
				}
			}
		} else {
			ret.Check.ValidDuration = result.Precondition.ValidDuration
			ret.Check.ValidUseCount = result.Precondition.ValidUseCount
			ret.Check.Status = result.Precondition.Status
		}

	case REPORT:
		req := istio_mixer_v1.ReportRequest{
			Attributes: []istio_mixer_v1.CompressedAttributes{
				getAttrBag(c.Attrs,
					idAttr,
					idAttrDomain)},
		}
		_, responseErr := client.Report(context.Background(), &req)
		ret.Error = responseErr
	}
	returns[i] = ret
	wg.Done()
}

func closeHelper(c io.Closer) {
	err := c.Close()
	if err != nil {
		log.Fatal(err)
	}
}

func getServerArgs(
	tmpls map[string]template.Info,
	adpts []adapter.InfoFn,
	cfgs []string) (*server.Args, error) {

	args := server.DefaultArgs()
	args.Templates = tmpls
	args.Adapters = adpts

	data := make([]string, 0)
	data = append(data, cfgs...)

	// always include the attribute vocabulary
	_, filename, _, _ := runtime.Caller(0)
	if f, err := filepath.Abs(path.Join(path.Dir(filename), "../../../testdata/config/attributes.yaml")); err != nil {
		return nil, fmt.Errorf("cannot load attributes.yaml: %v", err)
	} else if f, err := ioutil.ReadFile(f); err != nil {
		return nil, fmt.Errorf("cannot load attributes.yaml: %v", err)
	} else {
		data = append(data, string(f))
	}

	var err error
	args.ConfigStore, err = storetest.SetupStoreForTest(data...)
	return args, err
}

func getAttrBag(attrs map[string]interface{}, identityAttr, identityAttrDomain string) istio_mixer_v1.CompressedAttributes {
	requestBag := attribute.GetMutableBag(nil)
	requestBag.Set(identityAttr, identityAttrDomain)
	for k, v := range attrs {
		switch v.(type) {
		case map[string]interface{}:
			mapCast := make(map[string]string, len(v.(map[string]interface{})))

			for k1, v1 := range v.(map[string]interface{}) {
				mapCast[k1] = v1.(string)
			}
			requestBag.Set(k, mapCast)
		default:
			requestBag.Set(k, v)
		}
	}

	var attrProto istio_mixer_v1.CompressedAttributes
	requestBag.ToProto(&attrProto, nil, 0)
	return attrProto
}
<commit_msg>Make the supported templates public. (#4441)<commit_after>// Copyright 2017 Istio Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package test

import (
	"context"
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"path"
	"path/filepath"
	"reflect"
	"runtime"
	"testing"

	"google.golang.org/grpc"

	"sync"

	istio_mixer_v1 "istio.io/api/mixer/v1"
	"istio.io/istio/mixer/pkg/adapter"
	"istio.io/istio/mixer/pkg/attribute"
	"istio.io/istio/mixer/pkg/config/storetest"
	"istio.io/istio/mixer/pkg/server"
	"istio.io/istio/mixer/pkg/template"
	template2 "istio.io/istio/mixer/template"
)

// Utility to help write Mixer-adapter integration tests.

type (
	// Scenario fully defines an adapter integration test
	Scenario struct {
		// Configs is a list of CRDs that Mixer will read.
		Configs []string

		// ParallelCalls is a list of test calls to be made to Mixer
		// in parallel.
		ParallelCalls []Call

		// Setup is a callback function that will be called at the beginning of the test. It is
		// meant to be used for things like starting a local backend server. Setup function returns a
		// context (interface{}) which is passed back into the Teardown and the GetState functions.
		// pass nil if no setup needed
		Setup SetupFn

		// Teardown is a callback function that will be called at the end of the test. It is
		// meant to be used for things like stopping a local backend server that might have been started during Setup.
		// pass nil if no teardown is needed
		Teardown TeardownFn

		// GetState lets the test provide any (interface{}) adapter specific data to be part of baseline.
		// Example: for prometheus adapter, the actual metric reported to the local backend can be embedded into the
		// expected json baseline.
		// pass nil if no adapter specific state is part of baseline.
		GetState GetStateFn

		// Templates supported by Mixer.
		// If `Templates` is not specified, the default templates inside istio.io/istio/mixer/template.SupportedTmplInfo
		// are made available to the Mixer.
		Templates map[string]template.Info

		// Want is the expected serialized json for the Result struct.
		// Result.AdapterState is what the callback function `getState`, passed to `RunTest`, returns.
		//
		// New test can start of with an empty "{}" string and then
		// get the baseline from the failure logs upon execution.
		Want string
	}
	// Call represents the input to make a call to Mixer
	Call struct {
		// CallKind can be either CHECK or REPORT
		CallKind CallKind
		// Attrs to call the Mixer with.
		Attrs map[string]interface{}
		// Quotas info to call the Mixer with.
		Quotas map[string]istio_mixer_v1.CheckRequest_QuotaParams
	}
	// CallKind represents the call to make; check or report.
	CallKind int32

	// Result represents the test baseline
	Result struct {
		// AdapterState represents adapter specific baseline data. AdapterState is what the callback function
		// `getState`, passed to `RunTest`, returns.
		AdapterState interface{} `json:"AdapterState"`
		// Returns represents the return data from calls to Mixer
		Returns []Return `json:"Returns"`
	}
	// Return represents the return data from a call to Mixer
	Return struct {
		// Check is the response from a check call to Mixer
		Check adapter.CheckResult `json:"Check"`
		// Quota is the response from a check call to Mixer
		Quota map[string]adapter.QuotaResult `json:"Quota"`
		// Error is the error from call to Mixer
		Error error `json:"Error"`
	}
)

const (
	// CHECK for  Mixer Check
	CHECK CallKind = iota
	// REPORT for  Mixer Report
	REPORT
)

type (
	// SetupFn functions will be called at the beginning of the test
	SetupFn func() (ctx interface{}, err error)
	// TeardownFn functions will be called at the end of the test
	TeardownFn func(ctx interface{})
	// GetStateFn returns the adapter specific state upon test execution. The return value becomes part of
	// expected Result.AdapterState.
	GetStateFn func(ctx interface{}) (interface{}, error)
)

// RunTest performs a Mixer adapter integration test using in-memory Mixer and config store.
// NOTE: DO NOT invoke this using `t.Run(string, func)` because that would execute func in a separate go routine.
// Separate go routines would cause the test to fail randomly because fixed ports cannot be assigned and cleaned up
// deterministically on each iteration.
//
// * adapterInfo provides the InfoFn for the adapter under test.
// * Scenario provide the adapter/handler/rule configs along with the call parameters (check or report, and attributes)
//   Optionally, it also takes the test specific SetupFn, TeardownFn, GetStateFn and list of supported templates.
func RunTest(
	t *testing.T,
	adapterInfo adapter.InfoFn,
	scenario Scenario,
) {

	// Let the test do some initial setup.
	var ctx interface{}
	var err error
	if scenario.Setup != nil {
		ctx, err = scenario.Setup()
		// Teardown the initial setup
		if scenario.Teardown != nil {
			defer scenario.Teardown(ctx)
		}
		if err != nil {
			t.Fatalf("initial setup failed: %v", err)
		}
	}

	if len(scenario.Templates) == 0 {
		scenario.Templates = template2.SupportedTmplInfo
	}

	// Start Mixer
	var args *server.Args
	var env *server.Server
	if args, err = getServerArgs(scenario.Templates, []adapter.InfoFn{adapterInfo}, scenario.Configs); err != nil {
		t.Fatalf("fail to create mixer args: %v", err)
	}

	// Setting zero will make Mixer pick any available port.
	args.APIPort = 0
	args.MonitoringPort = 0

	if env, err = server.New(args); err != nil {
		t.Fatalf("fail to new mixer: %v", err)
	}
	env.Run()
	defer closeHelper(env)

	// Connect the client to Mixer
	conn, err := grpc.Dial(env.Addr().String(), grpc.WithInsecure())
	if err != nil {
		t.Fatalf("Unable to connect to gRPC server: %v", err)
	}
	client := istio_mixer_v1.NewMixerClient(conn)
	defer closeHelper(conn)

	// Invoke calls async
	var wg sync.WaitGroup
	wg.Add(len(scenario.ParallelCalls))

	got := Result{Returns: make([]Return, len(scenario.ParallelCalls))}
	for i, call := range scenario.ParallelCalls {
		go execute(call, args.ConfigIdentityAttribute, args.ConfigIdentityAttributeDomain, client, got.Returns, i, &wg)
	}
	// wait for calls to finish
	wg.Wait()

	// get adapter state. NOTE: We are doing marshal and then unmarshal it back into generic interface{}.
	// This is done to make getState output into generic json map or array; which is exactly what we get when un-marshalling
	// the baseline json. Without this, deep equality on un-marshalled baseline AdapterState would defer
	// from the rich object returned by getState function.
	if scenario.GetState != nil {
		adptState, _ := scenario.GetState(ctx)
		var adptStateBytes []byte
		if adptStateBytes, err = json.Marshal(adptState); err != nil {
			t.Fatalf("Unable to convert %v into json: %v", adptState, err)
		}
		if err = json.Unmarshal(adptStateBytes, &got.AdapterState); err != nil {
			t.Fatalf("Unable to unmarshal %s into interface{}: %v", string(adptStateBytes), err)
		}
	}

	var want Result
	if err = json.Unmarshal([]byte(scenario.Want), &want); err != nil {
		t.Fatalf("Unable to unmarshal %s into Result: %v", scenario.Want, err)
	}

	// compare
	if !reflect.DeepEqual(want, got) {
		gotJSON, err := json.MarshalIndent(got, "", " ")
		if err != nil {
			t.Fatalf("Unable to convert %v into json: %v", got, err)
		}
		wantJSON, err := json.MarshalIndent(want, "", " ")
		if err != nil {
			t.Fatalf("Unable to convert %v into json: %v", want, err)
		}
		t.Errorf("\ngot=>\n%s\nwant=>\n%s", gotJSON, wantJSON)
	}
}

func execute(c Call, idAttr string, idAttrDomain string, client istio_mixer_v1.MixerClient, returns []Return, i int, wg *sync.WaitGroup) {
	ret := Return{}
	switch c.CallKind {
	case CHECK:
		req := istio_mixer_v1.CheckRequest{
			Attributes: getAttrBag(c.Attrs,
				idAttr,
				idAttrDomain),
			Quotas: c.Quotas,
		}

		result, resultErr := client.Check(context.Background(), &req)
		result.Precondition.ReferencedAttributes = istio_mixer_v1.ReferencedAttributes{}
		ret.Error = resultErr
		if len(c.Quotas) > 0 {
			ret.Quota = make(map[string]adapter.QuotaResult)
			for k := range c.Quotas {
				ret.Quota[k] = adapter.QuotaResult{
					Amount: result.Quotas[k].GrantedAmount, ValidDuration: result.Quotas[k].ValidDuration,
				}
			}
		} else {
			ret.Check.ValidDuration = result.Precondition.ValidDuration
			ret.Check.ValidUseCount = result.Precondition.ValidUseCount
			ret.Check.Status = result.Precondition.Status
		}

	case REPORT:
		req := istio_mixer_v1.ReportRequest{
			Attributes: []istio_mixer_v1.CompressedAttributes{
				getAttrBag(c.Attrs,
					idAttr,
					idAttrDomain)},
		}
		_, responseErr := client.Report(context.Background(), &req)
		ret.Error = responseErr
	}
	returns[i] = ret
	wg.Done()
}

func closeHelper(c io.Closer) {
	err := c.Close()
	if err != nil {
		log.Fatal(err)
	}
}

func getServerArgs(
	tmpls map[string]template.Info,
	adpts []adapter.InfoFn,
	cfgs []string) (*server.Args, error) {

	args := server.DefaultArgs()
	args.Templates = tmpls
	args.Adapters = adpts

	data := make([]string, 0)
	data = append(data, cfgs...)

	// always include the attribute vocabulary
	_, filename, _, _ := runtime.Caller(0)
	if f, err := filepath.Abs(path.Join(path.Dir(filename), "../../../testdata/config/attributes.yaml")); err != nil {
		return nil, fmt.Errorf("cannot load attributes.yaml: %v", err)
	} else if f, err := ioutil.ReadFile(f); err != nil {
		return nil, fmt.Errorf("cannot load attributes.yaml: %v", err)
	} else {
		data = append(data, string(f))
	}

	var err error
	args.ConfigStore, err = storetest.SetupStoreForTest(data...)
	return args, err
}

func getAttrBag(attrs map[string]interface{}, identityAttr, identityAttrDomain string) istio_mixer_v1.CompressedAttributes {
	requestBag := attribute.GetMutableBag(nil)
	requestBag.Set(identityAttr, identityAttrDomain)
	for k, v := range attrs {
		switch v.(type) {
		case map[string]interface{}:
			mapCast := make(map[string]string, len(v.(map[string]interface{})))

			for k1, v1 := range v.(map[string]interface{}) {
				mapCast[k1] = v1.(string)
			}
			requestBag.Set(k, mapCast)
		default:
			requestBag.Set(k, v)
		}
	}

	var attrProto istio_mixer_v1.CompressedAttributes
	requestBag.ToProto(&attrProto, nil, 0)
	return attrProto
}
<|endoftext|>


<commit_before>// Title：模板中用的函数集
//
// Description:模板中用的函数集
//
// Author:black
//
// Createtime:2013-08-07 00:47
//
// Version:1.0
//
// 修改历史:版本号 修改日期 修改人 修改说明
//
// 1.0 2013-08-07 00:47 black 创建文档
package lessgo

import (
	"fmt"
	"html/template"
	"math/rand"
	"strings"
	"time"
)

//获取通用model的指定属性的值
func GetPropValue(model *Model, propName string) string {

	if model != nil {
		for _, prop := range model.Props {
			if prop.Name == propName {
				return prop.Value
			}
		}
		Log.Debug("找不到实体", model.Entity.Id, "的属性", propName, "对应的值")
	}

	return ""
}

//获取随机的组件id
func getComponentId(componentType string) string {

	r := rand.New(rand.NewSource(time.Now().UnixNano()))

	str := ""

	for i := 0; i < 4; i++ {
		str += fmt.Sprint(r.Intn(10))
	}

	return componentType + str
}

//模板中的int类型比较比较
func CompareInt(a, b int, compareType string) (flag bool) {

	switch compareType {

	case "eq":
		if a == b {
			flag = true
		} else {
			flag = false
		}
	case "gt":
		if a > b {
			flag = true
		} else {
			flag = false
		}
	case "ge":
		if a >= b {
			flag = true
		} else {
			flag = false
		}
	case "lt":
		if a < b {
			flag = true
		} else {
			flag = false
		}
	case "le":
		if a <= b {
			flag = true
		} else {
			flag = false
		}
	default:
		if a == b {
			flag = true
		} else {
			flag = false
		}
	}

	return flag
}

//模板中字符串比较
func CompareString(a, b string) bool {
	if a == b {
		return true
	} else {
		return false
	}
}

//替换json字符中的换行等特殊符号
func DealJsonString(str string) string {
	str = strings.Replace(str, "\n", " ", -1)
	str = strings.Replace(str, "\n\r", " ", -1)
	str = strings.Replace(str, "\r\n", " ", -1)
	str = strings.Replace(str, "\r", " ", -1)
	str = strings.Replace(str, "\"", "\\\"", -1)
	//to fixed
	str = strings.Replace(str, "'", "\\\"", -1)

	return str
}

func DealHTMLEscaper(str string) string {
	return template.HTMLEscaper(str)
}
<commit_msg>SetPropValue<commit_after>// Title：模板中用的函数集
//
// Description:模板中用的函数集
//
// Author:black
//
// Createtime:2013-08-07 00:47
//
// Version:1.0
//
// 修改历史:版本号 修改日期 修改人 修改说明
//
// 1.0 2013-08-07 00:47 black 创建文档
package lessgo

import (
	"fmt"
	"html/template"
	"math/rand"
	"strings"
	"time"
)

//获取通用model的指定属性的值
func GetPropValue(model *Model, propName string) string {

	if model != nil {
		for _, prop := range model.Props {
			if prop.Name == propName {
				return prop.Value
			}
		}
		Log.Debug("找不到实体", model.Entity.Id, "的属性", propName, "对应的值")
	}

	return ""
}

func SetPropValue(model *Model, propName,newValue string) {

	if model != nil {
		for _, prop := range model.Props {
			if prop.Name == propName {
				prop.Value = newValue
			}
		}
		Log.Debug("找不到实体", model.Entity.Id, "的属性")
	}
}

//获取随机的组件id
func getComponentId(componentType string) string {

	r := rand.New(rand.NewSource(time.Now().UnixNano()))

	str := ""

	for i := 0; i < 4; i++ {
		str += fmt.Sprint(r.Intn(10))
	}

	return componentType + str
}

//模板中的int类型比较比较
func CompareInt(a, b int, compareType string) (flag bool) {

	switch compareType {

	case "eq":
		if a == b {
			flag = true
		} else {
			flag = false
		}
	case "gt":
		if a > b {
			flag = true
		} else {
			flag = false
		}
	case "ge":
		if a >= b {
			flag = true
		} else {
			flag = false
		}
	case "lt":
		if a < b {
			flag = true
		} else {
			flag = false
		}
	case "le":
		if a <= b {
			flag = true
		} else {
			flag = false
		}
	default:
		if a == b {
			flag = true
		} else {
			flag = false
		}
	}

	return flag
}

//模板中字符串比较
func CompareString(a, b string) bool {
	if a == b {
		return true
	} else {
		return false
	}
}

//替换json字符中的换行等特殊符号
func DealJsonString(str string) string {
	str = strings.Replace(str, "\n", " ", -1)
	str = strings.Replace(str, "\n\r", " ", -1)
	str = strings.Replace(str, "\r\n", " ", -1)
	str = strings.Replace(str, "\r", " ", -1)
	str = strings.Replace(str, "\"", "\\\"", -1)
	//to fixed
	str = strings.Replace(str, "'", "\\\"", -1)

	return str
}

func DealHTMLEscaper(str string) string {
	return template.HTMLEscaper(str)
}
<|endoftext|>


<commit_before>package main

import (
	"github.com/TranscendComputing/mciaas/store"
	"github.com/ant0ine/go-json-rest"
	"path/filepath"
)

type JSONTemplates struct {
	BasePath string
}

func (this *JSONTemplates) ListTemplateTypes(w *rest.ResponseWriter, r *rest.Request) {
	store.SendJSONFile(w, r, filepath.Join(this.BasePath, "list.json"))
}

func (this *JSONTemplates) ListBuilderTemplates(w *rest.ResponseWriter, r *rest.Request) {
	store.SendJSONFile(w, r, filepath.Join(this.BasePath, "builders", "list.json"))
}

func (this *JSONTemplates) GetBuilderTemplate(w *rest.ResponseWriter, r *rest.Request) {
	builder := r.PathParam("type")
	jsonPath := filepath.Join(this.BasePath, "builders", builder+".json")
	store.SendJSONFile(w, r, jsonPath)
}

func (this *JSONTemplates) ListProvisionerTemplates(w *rest.ResponseWriter, r *rest.Request) {
	store.SendJSONFile(w, r, filepath.Join(this.BasePath, "provisioners", "list.json"))
}

func (this *JSONTemplates) GetProvisionerTemplate(w *rest.ResponseWriter, r *rest.Request) {
	provisioner := r.PathParam("type")
	jsonPath := filepath.Join(this.BasePath, "provisioners", provisioner+".json")
	store.SendJSONFile(w, r, jsonPath)
}

func (this *JSONTemplates) ListPostprocessorTemplates(w *rest.ResponseWriter, r *rest.Request) {
	store.SendJSONFile(w, r, filepath.Join(this.BasePath, "postprocessors", "list.json"))
}

func (this *JSONTemplates) ListPostprocessorTemplate(w *rest.ResponseWriter, r *rest.Request) {
	postprocessor := r.PathParam("type")
	jsonPath := filepath.Join(this.BasePath, "postprocessors", postprocessor+".json")
	store.SendJSONFile(w, r, jsonPath)
}
<commit_msg>failed git add cause no checkin<commit_after>package main

import (
	"github.com/TranscendComputing/mciaas/store"
	"github.com/ant0ine/go-json-rest"
	"path/filepath"
)

type JSONTemplates struct {
	BasePath string
}

func (this *JSONTemplates) ListTemplateTypes(w *rest.ResponseWriter, r *rest.Request) {
	store.SendJSONFile(w, r, filepath.Join(this.BasePath, "list.json"))
}

func (this *JSONTemplates) ListBuilderTemplates(w *rest.ResponseWriter, r *rest.Request) {
	store.SendJSONFile(w, r, filepath.Join(this.BasePath, "builders", "list.json"))
}

func (this *JSONTemplates) GetBuilderTemplate(w *rest.ResponseWriter, r *rest.Request) {
	builder := r.PathParam("type")
	jsonPath := filepath.Join(this.BasePath, "builders", builder+".json")
	store.SendJSONFile(w, r, jsonPath)
}

func (this *JSONTemplates) ListProvisionerTemplates(w *rest.ResponseWriter, r *rest.Request) {
	store.SendJSONFile(w, r, filepath.Join(this.BasePath, "provisioners", "list.json"))
}

func (this *JSONTemplates) GetProvisionerTemplate(w *rest.ResponseWriter, r *rest.Request) {
	provisioner := r.PathParam("type")
	jsonPath := filepath.Join(this.BasePath, "provisioners", provisioner+".json")
	store.SendJSONFile(w, r, jsonPath)
}

func (this *JSONTemplates) ListPostprocessorTemplates(w *rest.ResponseWriter, r *rest.Request) {
	store.SendJSONFile(w, r, filepath.Join(this.BasePath, "postprocessors", "list.json"))
}

func (this *JSONTemplates) GetPostprocessorTemplate(w *rest.ResponseWriter, r *rest.Request) {
	postprocessor := r.PathParam("type")
	jsonPath := filepath.Join(this.BasePath, "postprocessors", postprocessor+".json")
	store.SendJSONFile(w, r, jsonPath)
}
<|endoftext|>


<commit_before>package term // import "github.com/amalog/go/term"

import "math/big"

type Term interface {
}

type Variable interface {
}

type Number interface {
	AsBigRat() *big.Rat
}

type Atom interface {
}

type Seq interface {
}

type Database interface {
}

type Struct struct {
	Context Variable
	Name    Atom
	Args    Seq
	Data    Database
}

func NewAtom(s string) Term {
	return nil
}

func IsGround(t Term) bool {
	return false
}

func TermFromBigRat(x *big.Rat) Term {
	return nil
}
<commit_msg>Simplify term types<commit_after>package term // import "github.com/amalog/go/term"

import "math/big"

type Term interface {
}

type Variable interface {
}

type Number *big.Rat

type Atom string

type Seq []Term

type Database []Term

type Struct struct {
	Context Variable
	Name    Atom
	Args    Seq
	Data    Database
}

func NewAtom(s string) Term {
	return nil
}

func IsGround(t Term) bool {
	return false
}

func TermFromBigRat(x *big.Rat) Term {
	return nil
}
<|endoftext|>


<commit_before>package tftest

import (
	"bytes"
	"encoding/json"
	"fmt"
	"os"
	"os/exec"
	"strings"
)

// FindTerraform attempts to find a Terraform CLI executable for plugin testing.
//
// As a first preference it will look for the environment variable
// TFTEST_TERRAFORM and return its value. If that variable is not set, it will
// look in PATH for a program named "terraform" and, if one is found, return
// its absolute path.
//
// If no Terraform executable can be found, the result is the empty string. In
// that case, the test program will usually fail outright.
func FindTerraform() string {
	if p := os.Getenv("TFTEST_TERRAFORM"); p != "" {
		return p
	}
	p, err := exec.LookPath("terraform")
	if err != nil {
		return ""
	}
	return p
}

// RunTerraform runs the configured Terraform CLI executable with the given
// arguments, returning an error if it produces a non-successful exit status.
func (wd *WorkingDir) runTerraform(args ...string) error {
	allArgs := []string{"terraform"}
	allArgs = append(allArgs, args...)

	var env []string
	for _, e := range os.Environ() {
		env = append(env, e)
	}
	env = append(env, "TF_INPUT=0")
	env = append(env, "TF_LOG=") // so logging can't pollute our stderr output

	var errBuf strings.Builder

	// FIXME: Ideally in testing.Verbose mode we'd turn on Terraform DEBUG
	// logging, perhaps redirected to a separate fd other than stderr to avoid
	// polluting it, and then propagate the log lines out into t.Log so that
	// they are visible to the person running the test. Currently though,
	// Terraform CLI is able to send logs only to either an on-disk file or
	// to stderr.

	cmd := &exec.Cmd{
		Path:   wd.h.TerraformExecPath(),
		Args:   allArgs,
		Dir:    wd.baseDir,
		Stderr: &errBuf,
	}
	err := cmd.Run()
	if tErr, ok := err.(*exec.ExitError); ok {
		err = fmt.Errorf("terraform failed: %s\n\nstderr:\n%s", tErr.ProcessState.String(), errBuf.String())
	}
	return err
}

// runTerraformJSON runs the configured Terraform CLI executable with the given
// arguments and tries to decode its stdout into the given target value (which
// must be a non-nil pointer) as JSON.
func (wd *WorkingDir) runTerraformJSON(target interface{}, args ...string) error {
	allArgs := []string{"terraform"}
	allArgs = append(allArgs, args...)

	var env []string
	for _, e := range os.Environ() {
		env = append(env, e)
	}
	env = append(env, "TF_INPUT=0")
	env = append(env, "TF_LOG=") // so logging can't pollute our stderr output

	var outBuf bytes.Buffer
	var errBuf strings.Builder

	cmd := &exec.Cmd{
		Path:   wd.h.TerraformExecPath(),
		Args:   allArgs,
		Dir:    wd.baseDir,
		Stderr: &errBuf,
		Stdout: &outBuf,
	}
	err := cmd.Run()
	if err != nil {
		if tErr, ok := err.(*exec.ExitError); ok {
			err = fmt.Errorf("terraform failed: %s\n\nstderr:\n%s", tErr.ProcessState.String(), errBuf.String())
		}
		return err
	}

	return json.Unmarshal(outBuf.Bytes(), target)
}
<commit_msg>allow setting TFTEST_LOG_PATH in env<commit_after>package tftest

import (
	"bytes"
	"encoding/json"
	"fmt"
	"os"
	"os/exec"
	"strings"
)

// FindTerraform attempts to find a Terraform CLI executable for plugin testing.
//
// As a first preference it will look for the environment variable
// TFTEST_TERRAFORM and return its value. If that variable is not set, it will
// look in PATH for a program named "terraform" and, if one is found, return
// its absolute path.
//
// If no Terraform executable can be found, the result is the empty string. In
// that case, the test program will usually fail outright.
func FindTerraform() string {
	if p := os.Getenv("TFTEST_TERRAFORM"); p != "" {
		return p
	}
	p, err := exec.LookPath("terraform")
	if err != nil {
		return ""
	}
	return p
}

// getTerraformEnv returns the appropriate Env for the Terraform command.
func getTerraformEnv() []string {
	var env []string
	for _, e := range os.Environ() {
		env = append(env, e)
	}

	// FIXME: Ideally in testing.Verbose mode we'd turn on Terraform DEBUG
	// logging, perhaps redirected to a separate fd other than stderr to avoid
	// polluting it, and then propagate the log lines out into t.Log so that
	// they are visible to the person running the test. Currently though,
	// Terraform CLI is able to send logs only to either an on-disk file or
	// to stderr.
	env = append(env, "TF_LOG=") // so logging can't pollute our stderr output
	env = append(env, "TF_INPUT=0")

	if p := os.Getenv("TFTEST_LOG_PATH"); p != "" {
		env = append(env, "TF_LOG=TRACE")
		env = append(env, "TF_LOG_PATH="+p)
	}
	return env
}

// RunTerraform runs the configured Terraform CLI executable with the given
// arguments, returning an error if it produces a non-successful exit status.
func (wd *WorkingDir) runTerraform(args ...string) error {
	allArgs := []string{"terraform"}
	allArgs = append(allArgs, args...)

	env := getTerraformEnv()

	var errBuf strings.Builder

	cmd := &exec.Cmd{
		Path:   wd.h.TerraformExecPath(),
		Args:   allArgs,
		Dir:    wd.baseDir,
		Stderr: &errBuf,
		Env:    env,
	}
	err := cmd.Run()
	if tErr, ok := err.(*exec.ExitError); ok {
		err = fmt.Errorf("terraform failed: %s\n\nstderr:\n%s", tErr.ProcessState.String(), errBuf.String())
	}
	return err
}

// runTerraformJSON runs the configured Terraform CLI executable with the given
// arguments and tries to decode its stdout into the given target value (which
// must be a non-nil pointer) as JSON.
func (wd *WorkingDir) runTerraformJSON(target interface{}, args ...string) error {
	allArgs := []string{"terraform"}
	allArgs = append(allArgs, args...)

	env := getTerraformEnv()

	var outBuf bytes.Buffer
	var errBuf strings.Builder

	cmd := &exec.Cmd{
		Path:   wd.h.TerraformExecPath(),
		Args:   allArgs,
		Dir:    wd.baseDir,
		Stderr: &errBuf,
		Stdout: &outBuf,
		Env:    env,
	}
	err := cmd.Run()
	if err != nil {
		if tErr, ok := err.(*exec.ExitError); ok {
			err = fmt.Errorf("terraform failed: %s\n\nstderr:\n%s", tErr.ProcessState.String(), errBuf.String())
		}
		return err
	}

	return json.Unmarshal(outBuf.Bytes(), target)
}
<|endoftext|>


<commit_before>/*
Terse is an html templating language inspired by slim, but
written for the features of multitemplate. The minimal logic
marks were inspired by mustache, but I'm not going to pretend
they're not template logic. Note that the logic syntax is the
same as the template logic syntax in the Go standard library.
Terse is not an acronym, it is a description of the design of
the language.

Features

- Significant Whitespace

- Auto-closing tags and functions

- Integrates with other multitemplate languages

- Uses same function calling syntax as stdlib templates

Using Terse

Active terse as a multitemplate languages by importing the
terse library like

    import _ "github.com/acsellers/multitemplate/terse"

At that point, Parse will now take a "terse" parser for templates
and ParseFiles/ParseGlob will detect files with a .terse extension
as terse formatted files.

An example terse file:

    #content
      .title
        h1= .Title
        = link_to "Home" (url_for "home")

The resulting HTML would look like:

Welcome

      Home

Security and XSS Protection

Terse uses the built-in protection of html/template via multitemplate.

Simple HTML

Most of HTML documents is static text. Terse makes writing this static
text as simple as possible. There are three ways to write HTML tags, the
automatic way, the manual way, and the verbatim way. The automatic way
will detect tags by name, and will do a case sensitive search on the
elements listed in the ValidElements map. The manual way will detect
elements by a percentage sign before the element name, which is the same
behavior as Haml and Bham. Finally, you can just add verbatim HTML code,
and it wil be passed through to the final output. This is why the character
'<' has no special meaning in terse.

  // Source
  article

My Title

  // Output

My Title

Collapsing Tags

If you have lines that are simply declaring elements that are nesting,
you can collapse the lines using the '>' character. Note that you cannot
add attributes or content to the tags. At the moment, you can't use the
id/class shorthand here.

  // Source
  table > tr > td > %custom_element
    Gopher Freeman

  // Output

<custom_element>
    Gopher Freeman
  </custom_element>

Template Calls

Templates can be called easily using the >> operator. You may add the name
of the template without quotes, unless the name would have spaces, in which
case you should add quotes to the template name. Then the template call may
have a space and a value declaraction (could be ., a $ variable, a function,
a number, string, number, etc) where the value would be passed to the
template. If you do not provide a value to the template, the dot operator will
be assumed to be the value.

  // Source
  >>layouts/navigation.html

  // Output
  {{ template "layouts/navigation.html" . }}

  // Source
  >>"beta layouts/javascript defer.html" $modules

  // Output
  {{ template "beta layouts/javascript defer.html" $modules }}

Define Statements

Define statements start with two :'s, then the name for the template. Remember
that variables from below the define will not be accessible in the define area.
Also remember that a define statement will be pulled out and compiled during
the compilation of the parent, and that we will use the name given for the
template.

  // Source
  ::snippets/title.html
    h1.title= .

  // Output
  {{ define "snippets.html" }}

{{ . }}

  {{ end }}

Class and Id Shorthand

Id's and Class attributes may be specified in shorthand. If you do
not specify an html element, terse will assume that you want to use
the div element. Multiple class attributes will be combined into the
class attribute, while multiple id attributes will take the final id
attribute. Classes are similar to css declarations, where '.'s precede
class attributes and '#'s precede id attributes. You can still provide
id and class attributes using the standard HTML attributes.

  // Source
  #sidebar
    ul#sidebar_list.vertical_list
      li.sidebar_element.active Thing

  // Output

Thing

HTML Attributes

There are two ways to specify attributes, one which allows for multiple
lines with attributes and another that requires all attributes to be
specied on the same line. By specifying the attribute name, then an
equals sign, then either a string, a $variable, a RenderArg which is
a . followed by words. Finally, if you just specify a helper function.
Note that if the helper function needs arguments, you should wrap the
function and arguments in parentheses. Boolean HTML attributes, that is
attributes that have no value, either require parentheses or can have
the value 'true' or 'false'.

  // Single Line
  div id="special_thing" class=$DivIds special thing content
  // Output

    special thing content

  // Multi Line
  input(
    name="is_active"
    type="checkbox"
    value="yes"
    checked=.User.Active
  )
  // Output
  <input type="is_active" type="checkbox" value="yes" checkbox="{{.User.Active}}" />

  // All the ways to specify attributes
  input(
    name=$inputName
    type="checkbox"
    value=.User.Name
    checked=(if_print "checked" .User.ShowName)
    class=.Check.User.Class
  )

  // Boolean Attribute Option 1
  .content ng-view=true
  // Boolean Attribute Option 2
  .content(ng-view)
  // Output

Doctype

Doctype lines are prefixed with two exclamation points (!!). There is
the default doctype, which is a line with just !!, terse will assume
you want to use the HTML5 Doctype (<!DOCTYPE html>). You can modify
the terse.Doctypes variable to change to another default by changing
the empty string key. Terse includes 8 different Doctypes by default,
which are Transitional (XHTML 1.0 Transitional), Strict (XHTML 1.0
Strict), Frameset (XHTML 1.0 Frameset), 5 (HTML5), 1.1 (XHTML 1.1),
Basic (XHTML 1.1 Basic), Mobile (XHTML Mobile 1.2), and RDFa
(XHTML+RDFa 1.0). These are the same as haml's Doctypes, except
that we don't worry about a Format option.

  // Source
  !!
  // Output
  <!DOCTYPE html>

Comments

By prefixing lines with a double slash (//), that line and any nested
lines will be marked as a comment. Comment lines do not show up in the
rendered template in any way.

Executing Code

There are preferred methods for if, range, with, and block functions,
but for template functions, there is a generic way to use code in
your templates. By adding an = at the start of the line, you can
mark that line as executable, for multiple lines there is a continuation
marker (/=) which will collapse multiple lines into a single line of code,
so long as the continuation lines are nested in the first code line. Note
that the syntax is the same as text/template in the standard library,
and the behavior about inserting code results into the output is same as
the text/template code as well.

  // Source
  = print .User
  // Output
  {{ print .User }}

  // Source
  = form_tag (url_for "user.new") (attrs
    /= "enctype" "multipart/form-data"
    /= "method" "PUT")
  // Output
  <form action="{{ url_for "user.new" }}" enctype="multipart/form-data" method="PUT">

Auto Closing Functions

When lines are nested, terse will look a function another function
that has the same name as the function that has the nested name, but
with the prefix 'end_'.

  // Source
  = fieldset_tag "Visibility"
    = checkbox_tag "admins"
    = checkbox_tag "users"
    = checkbox_tag "visitors"

  // Output
  {{ fieldset_tag "Visibility" }} {{ checkbox_tag "admins" }}
    {{ checkbox_tag "users" }}
    {{ checkbox_tag "visitors" }}
  {{ end_fieldset_tag }}

If and Else Statements

If lines begin with a question mark (?), then a statement to be evaluated. The
method of evaluation is the same as text/template, where if the statement
evaluates to false, 0, nil, or anything with a length of 0, the statement
is not executed. Else is an exclamation mark followed by a question mark,
or "not the question".

  // Source
  ?.User
    Welcome
    = .User.Name
  !?
    Please Login

  // Output
  {{ if .User }}
    Welcome
  {{ else }}
    Please Login
  {{ end }}

Range Statements

Range statements begin with an ampersand (&). Else statements for ranges
are an exclamation mark followed by an ampersand (!&). Variables for the
range statement are specified using colons after the statement you will
be ranging over.

  // Source
  &.Users:$user:$index
    {{ $index }}. {{ $user.Name }}
  !&
    No matching users.

  // Output
  {{ range $user, $index := .Users }}
    {{ $index }}. {{ $user.Name }}
  {{ else }}
    No matching users.
  {{ end }}

Block Statements

Blocks are central to multitemplate and terse features
them in a first-class manner. The simple block call is [name] where
name is the name you are using for that block. If you a special
form of the block statement, just replace the opening '['. For an
exec block you use a $, while define block uses a ^. The mnemonic
for those is that exec is the end of a block, so it is a regex endline
symbol ($), while define-block is more a beginning statement, and the
regex character for the beginning of line is ^. Blocks are automatically
closed in terse.

  // Source
  [content]
    h1
      Welcome
      = .User.Name

  // Output
  {{ block "content" }}

Welcome {{.User.Name }}

  {{ end_block }}

  // Source
  ^content]
    I'm defining this block and not outputting here.
  // Output
  {{ define_block "content" }}
    I'm defining this block and not outputting here.
  {{ end_block }}

  // Source
  $content]
    We will definitely put some block content here.
  // Output
  {{ exec_block "content" }}
    We will definitely put some block content here.
  {{ end_block }}

Yield Statements

Yield statements (for blocks or templates) are written as @name,
where name is the name you are using for that block or template.

  // Source
  #content
    @content

  // Output

    {{ yield "content" }}

Extend Statements

Extend statements (for inheriting from other templates) are written
using @@ followed by the template name (without quotation marks).

  // Source
  @@layouts/app.html

  // Output
  {{ extend "layouts/app.html" }}

With Statements

A with statement takes a pipeline and either sets the dot or a variable
to the value. With statments will only execute if the value is not a
falsey value (0, false, nil, empty string, array, slice or map). With
statements can have else statements, which are signified by a !>.

  // Source
  >.Current.User
    Welcome
    = .Name
    ?time_gt .LastLogin "3w"
      It's been a while
  !>
    Please login

  // Output
  {{ with .Current.User }}
    Welcome
    {{ .Name }}
    {{ if time_gt .LastLogin "3w" }}
      It's been a while
    {{ end }}
  {{ end }}

  // Source
  >.Current.Location:$loc
    = $loc.Name

  // Output
  {{ with $loc := .Current.Location }}
    {{ $loc.Name }}
  {{ end }}
Interpolation

In addition to the function lines, you can also embed functions into
regular lines, using the Delimeters set on terse (same as the standard
library delimeters by default).

  // Source
  Welcome {{ .User.Name }}.

  // Output (same)
  Welcome {{ .User.Name}}.

Filters

Filters are started with a :, then the name of a registered filter.
Filters can have interpolated code within them, if the filter may
have interpolated code, it needs to return true, else if it returns
false, the filtered text will not be checked for code. Note that the
processed text will be inserted into the template and any interpolated
code will be processed by html/template and escaped in a manner
consistent with the surrounding text.

  // Source
  :js
    $(document).ready(function{ setup_ajax(); });

  // Output

Currently there are 3 built-in filters, a plain filter, a javascript filter
(also aliased as js), and a css filter. The Plain filter will take any nested
lines and push the straight out to the the text/template parser. The javascript
filter will wrap the text in a script tag, then send it to be processed by the
text/template parser. Similarly, the css filter will wrap the text in a style
tag, then send it to the parser.

Notes

The format of the documentation and some examples were inspired by
Haml's REFERENCE file.

*/
package terse
<commit_msg>Add note about arguments possibly changing.<commit_after>/*
Terse is an html templating language inspired by slim, but
written for the features of multitemplate. The minimal logic
marks were inspired by mustache, but I'm not going to pretend
they're not template logic. Note that the logic syntax is the
same as the template logic syntax in the Go standard library.
Terse is not an acronym, it is a description of the design of
the language.

Features

- Significant Whitespace

- Auto-closing tags and functions

- Integrates with other multitemplate languages

- Uses same function calling syntax as stdlib templates

Using Terse

Active terse as a multitemplate languages by importing the
terse library like

    import _ "github.com/acsellers/multitemplate/terse"

At that point, Parse will now take a "terse" parser for templates
and ParseFiles/ParseGlob will detect files with a .terse extension
as terse formatted files.

An example terse file:

    #content
      .title
        h1= .Title
        = link_to "Home" (url_for "home")

The resulting HTML would look like:

Welcome

      Home

Security and XSS Protection

Terse uses the built-in protection of html/template via multitemplate.

Simple HTML

Most of HTML documents is static text. Terse makes writing this static
text as simple as possible. There are three ways to write HTML tags, the
automatic way, the manual way, and the verbatim way. The automatic way
will detect tags by name, and will do a case sensitive search on the
elements listed in the ValidElements map. The manual way will detect
elements by a percentage sign before the element name, which is the same
behavior as Haml and Bham. Finally, you can just add verbatim HTML code,
and it wil be passed through to the final output. This is why the character
'<' has no special meaning in terse.

  // Source
  article

My Title

  // Output

My Title

Collapsing Tags

If you have lines that are simply declaring elements that are nesting,
you can collapse the lines using the '>' character. Note that you cannot
add attributes or content to the tags. At the moment, you can't use the
id/class shorthand here.

  // Source
  table > tr > td > %custom_element
    Gopher Freeman

  // Output

<custom_element>
    Gopher Freeman
  </custom_element>

Template Calls

Templates can be called easily using the >> operator. You may add the name
of the template without quotes, unless the name would have spaces, in which
case you should add quotes to the template name. Then the template call may
have a space and a value declaraction (could be ., a $ variable, a function,
a number, string, number, etc) where the value would be passed to the
template. If you do not provide a value to the template, the dot operator will
be assumed to be the value.

  // Source
  >>layouts/navigation.html

  // Output
  {{ template "layouts/navigation.html" . }}

  // Source
  >>"beta layouts/javascript defer.html" $modules

  // Output
  {{ template "beta layouts/javascript defer.html" $modules }}

Define Statements

Define statements start with two :'s, then the name for the template. Remember
that variables from below the define will not be accessible in the define area.
Also remember that a define statement will be pulled out and compiled during
the compilation of the parent, and that we will use the name given for the
template.

  // Source
  ::snippets/title.html
    h1.title= .

  // Output
  {{ define "snippets.html" }}

{{ . }}

  {{ end }}

Class and Id Shorthand

Id's and Class attributes may be specified in shorthand. If you do
not specify an html element, terse will assume that you want to use
the div element. Multiple class attributes will be combined into the
class attribute, while multiple id attributes will take the final id
attribute. Classes are similar to css declarations, where '.'s precede
class attributes and '#'s precede id attributes. You can still provide
id and class attributes using the standard HTML attributes.

  // Source
  #sidebar
    ul#sidebar_list.vertical_list
      li.sidebar_element.active Thing

  // Output

Thing

HTML Attributes

There are two ways to specify attributes, one which allows for multiple
lines with attributes and another that requires all attributes to be
specied on the same line. By specifying the attribute name, then an
equals sign, then either a string, a $variable, a RenderArg which is
a . followed by words. Finally, if you just specify a helper function.
Note that if the helper function needs arguments, you should wrap the
function and arguments in parentheses. Boolean HTML attributes, that is
attributes that have no value, either require parentheses or can have
the value 'true' or 'false'.

  // Single Line
  div id="special_thing" class=$DivIds special thing content
  // Output

    special thing content

  // Multi Line
  input(
    name="is_active"
    type="checkbox"
    value="yes"
    checked=.User.Active
  )
  // Output
  <input type="is_active" type="checkbox" value="yes" checkbox="{{.User.Active}}" />

  // All the ways to specify attributes
  input(
    name=$inputName
    type="checkbox"
    value=.User.Name
    checked=(if_print "checked" .User.ShowName)
    class=.Check.User.Class
  )

  // Boolean Attribute Option 1
  .content ng-view=true
  // Boolean Attribute Option 2
  .content(ng-view)
  // Output

Doctype

Doctype lines are prefixed with two exclamation points (!!). There is
the default doctype, which is a line with just !!, terse will assume
you want to use the HTML5 Doctype (<!DOCTYPE html>). You can modify
the terse.Doctypes variable to change to another default by changing
the empty string key. Terse includes 8 different Doctypes by default,
which are Transitional (XHTML 1.0 Transitional), Strict (XHTML 1.0
Strict), Frameset (XHTML 1.0 Frameset), 5 (HTML5), 1.1 (XHTML 1.1),
Basic (XHTML 1.1 Basic), Mobile (XHTML Mobile 1.2), and RDFa
(XHTML+RDFa 1.0). These are the same as haml's Doctypes, except
that we don't worry about a Format option.

  // Source
  !!
  // Output
  <!DOCTYPE html>

Comments

By prefixing lines with a double slash (//), that line and any nested
lines will be marked as a comment. Comment lines do not show up in the
rendered template in any way.

Executing Code

There are preferred methods for if, range, with, and block functions,
but for template functions, there is a generic way to use code in
your templates. By adding an = at the start of the line, you can
mark that line as executable, for multiple lines there is a continuation
marker (/=) which will collapse multiple lines into a single line of code,
so long as the continuation lines are nested in the first code line. Note
that the syntax is the same as text/template in the standard library,
and the behavior about inserting code results into the output is same as
the text/template code as well.

  // Source
  = print .User
  // Output
  {{ print .User }}

  // Source
  = form_tag (url_for "user.new") (attrs
    /= "enctype" "multipart/form-data"
    /= "method" "PUT")
  // Output
  <form action="{{ url_for "user.new" }}" enctype="multipart/form-data" method="PUT">

Auto Closing Functions

When lines are nested, terse will look a function another function
that has the same name as the function that has the nested name, but
with the prefix 'end_'.

  // Source
  = fieldset_tag "Visibility"
    = checkbox_tag "admins"
    = checkbox_tag "users"
    = checkbox_tag "visitors"

  // Output
  {{ fieldset_tag "Visibility" }} {{ checkbox_tag "admins" }}
    {{ checkbox_tag "users" }}
    {{ checkbox_tag "visitors" }}
  {{ end_fieldset_tag }}

If and Else Statements

If lines begin with a question mark (?), then a statement to be evaluated. The
method of evaluation is the same as text/template, where if the statement
evaluates to false, 0, nil, or anything with a length of 0, the statement
is not executed. Else is an exclamation mark followed by a question mark,
or "not the question".

  // Source
  ?.User
    Welcome
    = .User.Name
  !?
    Please Login

  // Output
  {{ if .User }}
    Welcome
  {{ else }}
    Please Login
  {{ end }}

Range Statements

Range statements begin with an ampersand (&). Else statements for ranges
are an exclamation mark followed by an ampersand (!&). Variables for the
range statement are specified using colons after the statement you will
be ranging over.

  // Source
  &.Users:$user:$index
    {{ $index }}. {{ $user.Name }}
  !&
    No matching users.

  // Output
  {{ range $user, $index := .Users }}
    {{ $index }}. {{ $user.Name }}
  {{ else }}
    No matching users.
  {{ end }}

Block Statements

Blocks are central to multitemplate and terse features
them in a first-class manner. The simple block call is [name] where
name is the name you are using for that block. If you a special
form of the block statement, just replace the opening '['. For an
exec block you use a $, while define block uses a ^. The mnemonic
for those is that exec is the end of a block, so it is a regex endline
symbol ($), while define-block is more a beginning statement, and the
regex character for the beginning of line is ^. Blocks are automatically
closed in terse.

  // Source
  [content]
    h1
      Welcome
      = .User.Name

  // Output
  {{ block "content" }}

Welcome {{.User.Name }}

  {{ end_block }}

  // Source
  ^content]
    I'm defining this block and not outputting here.
  // Output
  {{ define_block "content" }}
    I'm defining this block and not outputting here.
  {{ end_block }}

  // Source
  $content]
    We will definitely put some block content here.
  // Output
  {{ exec_block "content" }}
    We will definitely put some block content here.
  {{ end_block }}

Yield Statements

Yield statements (for blocks or templates) are written as @name,
where name is the name you are using for that block or template.

  // Source
  #content
    @content

  // Output

    {{ yield "content" }}

Extend Statements

Extend statements (for inheriting from other templates) are written
using @@ followed by the template name (without quotation marks).

  // Source
  @@layouts/app.html

  // Output
  {{ extend "layouts/app.html" }}

With Statements

A with statement takes a pipeline and either sets the dot or a variable
to the value. With statments will only execute if the value is not a
falsey value (0, false, nil, empty string, array, slice or map). With
statements can have else statements, which are signified by a !>.

  // Source
  >.Current.User
    Welcome
    = .Name
    ?time_gt .LastLogin "3w"
      It's been a while
  !>
    Please login

  // Output
  {{ with .Current.User }}
    Welcome
    {{ .Name }}
    {{ if time_gt .LastLogin "3w" }}
      It's been a while
    {{ end }}
  {{ end }}

  // Source
  >.Current.Location:$loc
    = $loc.Name

  // Output
  {{ with $loc := .Current.Location }}
    {{ $loc.Name }}
  {{ end }}
Interpolation

In addition to the function lines, you can also embed functions into
regular lines, using the Delimeters set on terse (same as the standard
library delimeters by default).

  // Source
  Welcome {{ .User.Name }}.

  // Output (same)
  Welcome {{ .User.Name}}.

Filters

Filters are started with a :, then the name of a registered filter.
Filters can have interpolated code within them, if the filter may
have interpolated code, it needs to return true, else if it returns
false, the filtered text will not be checked for code. Note that the
processed text will be inserted into the template and any interpolated
code will be processed by html/template and escaped in a manner
consistent with the surrounding text.

  // Source
  :js
    $(document).ready(function{ setup_ajax(); });

  // Output

Currently there are 3 built-in filters, a plain filter, a javascript filter
(also aliased as js), and a css filter. The Plain filter will take any nested
lines and push the straight out to the the text/template parser. The javascript
filter will wrap the text in a script tag, then send it to be processed by the
text/template parser. Similarly, the css filter will wrap the text in a style
tag, then send it to the parser.

Notes

Range and With statements use :'s to delineate arguments while template
statements use spaces. I'm still thinking about this, and template's will likely
move to :'s.

The format of the documentation and some examples were inspired by
Haml's REFERENCE file.

*/
package terse
<|endoftext|>


<commit_before>package sched

import (
	"fmt"
	"io"
	"log"
	"net/url"
	"os"
	"strings"
	"time"

	"github.com/StackExchange/bosun/_third_party/github.com/StackExchange/scollector/opentsdb"
	"github.com/StackExchange/bosun/conf"
	"github.com/StackExchange/bosun/expr"
)

type Context struct {
	*State
	Alert *conf.Alert

	schedule *Schedule
}

func (s *Schedule) Data(st *State, a *conf.Alert) *Context {
	return &Context{
		State:    st,
		Alert:    a,
		schedule: s,
	}
}

type unknownContext struct {
	Time  time.Time
	Name  string
	Group expr.AlertKeys

	schedule *Schedule
}

func (s *Schedule) unknownData(t time.Time, name string, group expr.AlertKeys) *unknownContext {
	return &unknownContext{
		Time:     t,
		Group:    group,
		Name:     name,
		schedule: s,
	}
}

// URL returns a prepopulated URL for external access, with path and query empty.
func (s *Schedule) URL() *url.URL {
	u := url.URL{
		Scheme: "http",
		Host:   s.Conf.HttpListen,
	}
	if strings.HasPrefix(s.Conf.HttpListen, ":") {
		h, err := os.Hostname()
		if err != nil {
			u.Host = "localhost" + u.Host
		} else {
			u.Host = h + u.Host
		}
	}
	return &u
}

// Ack returns the URL to acknowledge an alert.
func (c *Context) Ack() string {
	u := c.schedule.URL()
	u.Path = fmt.Sprintf("/api/acknowledge/%s/%s", c.Alert.Name, c.State.Group.String())
	return u.String()
}

// HostView returns the URL to the host view page.
func (c *Context) HostView(host string) string {
	u := c.schedule.URL()
	u.Path = "/host"
	u.RawQuery = fmt.Sprintf("time=1d-ago&host=%s", host)
	return u.String()
}

func (c *Context) Expr(v string) string {
	q := url.QueryEscape("q=" + opentsdb.ReplaceTags(v, c.Group))
	u := url.URL{
		Scheme:   "http",
		Host:     c.schedule.Conf.HttpListen,
		Path:     "/expr",
		RawQuery: q,
	}
	if strings.HasPrefix(c.schedule.Conf.HttpListen, ":") {
		h, err := os.Hostname()
		if err != nil {
			return ""
		}
		u.Host = h + u.Host
	}
	return u.String()
}

func (s *Schedule) ExecuteBody(w io.Writer, a *conf.Alert, st *State) error {
	t := a.Template
	if t == nil || t.Body == nil {
		return nil
	}
	return t.Body.Execute(w, s.Data(st, a))
}

func (s *Schedule) ExecuteSubject(w io.Writer, a *conf.Alert, st *State) error {
	t := a.Template
	if t == nil || t.Subject == nil {
		return nil
	}
	return t.Subject.Execute(w, s.Data(st, a))
}

// E executes the given expression and returns a value with corresponding tags
// to the context's tags. If no such result is found, the first result with nil
// tags is returned. If no such result is found, "" is returned. The precision
// of numbers is truncated for convienent display. Series expressions are not
// supported.
func (c *Context) E(v string) string {
	e, err := expr.New(v)
	if err != nil {
		log.Printf("%s: %v", v, err)
		return ""
	}
	res, _, err := e.Execute(c.schedule.cache, nil, c.schedule.CheckStart, 0, c.Alert.UnjoinedOK, c.schedule.Search, c.schedule.Lookups)
	if err != nil {
		log.Printf("%s: %v", v, err)
		return ""
	}
	for _, r := range res {
		if r.Group.Equal(c.State.Group) {
			return truncate(r.Value)
		}
	}
	for _, r := range res {
		if c.State.Group.Subset(r.Group) {
			return truncate(r.Value)
		}
	}
	for _, r := range res {
		if r.Group == nil {
			return truncate(r.Value)
		}
	}
	return ""
}

// truncate displays needed decimals for a Number.
func truncate(v expr.Value) string {
	switch t := v.(type) {
	case expr.Number:
		if t < 1 {
			return fmt.Sprintf("%.4f", t)
		} else if t < 100 {
			return fmt.Sprintf("%.1f", t)
		} else {
			return fmt.Sprintf("%.0f", t)
		}
	default:
		return ""
	}
}
<commit_msg>Fix Ack URL link<commit_after>package sched

import (
	"fmt"
	"io"
	"log"
	"net/url"
	"os"
	"strings"
	"time"

	"github.com/StackExchange/bosun/_third_party/github.com/StackExchange/scollector/opentsdb"
	"github.com/StackExchange/bosun/conf"
	"github.com/StackExchange/bosun/expr"
)

type Context struct {
	*State
	Alert *conf.Alert

	schedule *Schedule
}

func (s *Schedule) Data(st *State, a *conf.Alert) *Context {
	return &Context{
		State:    st,
		Alert:    a,
		schedule: s,
	}
}

type unknownContext struct {
	Time  time.Time
	Name  string
	Group expr.AlertKeys

	schedule *Schedule
}

func (s *Schedule) unknownData(t time.Time, name string, group expr.AlertKeys) *unknownContext {
	return &unknownContext{
		Time:     t,
		Group:    group,
		Name:     name,
		schedule: s,
	}
}

// URL returns a prepopulated URL for external access, with path and query empty.
func (s *Schedule) URL() *url.URL {
	u := url.URL{
		Scheme: "http",
		Host:   s.Conf.HttpListen,
	}
	if strings.HasPrefix(s.Conf.HttpListen, ":") {
		h, err := os.Hostname()
		if err != nil {
			u.Host = "localhost" + u.Host
		} else {
			u.Host = h + u.Host
		}
	}
	return &u
}

// Ack returns the URL to acknowledge an alert.
func (c *Context) Ack() string {
	u := c.schedule.URL()
	u.Path = "/action"
	u.RawQuery = url.Values{
		"type": []string{"type"},
		"key":  []string{c.Alert.Name + c.State.Group.String()},
	}.Encode()
	return u.String()
}

// HostView returns the URL to the host view page.
func (c *Context) HostView(host string) string {
	u := c.schedule.URL()
	u.Path = "/host"
	u.RawQuery = fmt.Sprintf("time=1d-ago&host=%s", host)
	return u.String()
}

func (c *Context) Expr(v string) string {
	q := url.QueryEscape("q=" + opentsdb.ReplaceTags(v, c.Group))
	u := url.URL{
		Scheme:   "http",
		Host:     c.schedule.Conf.HttpListen,
		Path:     "/expr",
		RawQuery: q,
	}
	if strings.HasPrefix(c.schedule.Conf.HttpListen, ":") {
		h, err := os.Hostname()
		if err != nil {
			return ""
		}
		u.Host = h + u.Host
	}
	return u.String()
}

func (s *Schedule) ExecuteBody(w io.Writer, a *conf.Alert, st *State) error {
	t := a.Template
	if t == nil || t.Body == nil {
		return nil
	}
	return t.Body.Execute(w, s.Data(st, a))
}

func (s *Schedule) ExecuteSubject(w io.Writer, a *conf.Alert, st *State) error {
	t := a.Template
	if t == nil || t.Subject == nil {
		return nil
	}
	return t.Subject.Execute(w, s.Data(st, a))
}

// E executes the given expression and returns a value with corresponding tags
// to the context's tags. If no such result is found, the first result with nil
// tags is returned. If no such result is found, "" is returned. The precision
// of numbers is truncated for convienent display. Series expressions are not
// supported.
func (c *Context) E(v string) string {
	e, err := expr.New(v)
	if err != nil {
		log.Printf("%s: %v", v, err)
		return ""
	}
	res, _, err := e.Execute(c.schedule.cache, nil, c.schedule.CheckStart, 0, c.Alert.UnjoinedOK, c.schedule.Search, c.schedule.Lookups)
	if err != nil {
		log.Printf("%s: %v", v, err)
		return ""
	}
	for _, r := range res {
		if r.Group.Equal(c.State.Group) {
			return truncate(r.Value)
		}
	}
	for _, r := range res {
		if c.State.Group.Subset(r.Group) {
			return truncate(r.Value)
		}
	}
	for _, r := range res {
		if r.Group == nil {
			return truncate(r.Value)
		}
	}
	return ""
}

// truncate displays needed decimals for a Number.
func truncate(v expr.Value) string {
	switch t := v.(type) {
	case expr.Number:
		if t < 1 {
			return fmt.Sprintf("%.4f", t)
		} else if t < 100 {
			return fmt.Sprintf("%.1f", t)
		} else {
			return fmt.Sprintf("%.0f", t)
		}
	default:
		return ""
	}
}
<|endoftext|>


<commit_before>package threadpool

import (
	"sync"
	"math"
	"nokia.com/nas/services/telemetry_service_go/ds"
)

type ScheduledThreadPool struct {
	workers chan chan Runnable
	jobQueue chan Runnable
	tasks *sync.Map
	noOfWorkers int
	counter uint64
	queueSize int64
	counterLock sync.Mutex
}

func NewScheduledThreadPool(noOfWorkers int) *ScheduledThreadPool {
	pool := &ScheduledThreadPool{}
	pool.noOfWorkers=noOfWorkers
	pool.queueSize = math.MaxInt32
	pool.workers = make(chan chan Runnable,noOfWorkers)
	pool.jobQueue = make(chan Runnable,pool.queueSize)
	pool.tasks = new(sync.Map)
	pool.createPool()
	return pool
}

func (stf *ScheduledThreadPool) createPool(){
	for i:=0;i<stf.noOfWorkers; i++ {
		worker:= NewWorker(stf.workers)
		worker.Start()
	}

	go stf.dispatch()
}

func (stf *ScheduledThreadPool) dispatch(){
	go stf.intervalRunner()
}

func (stf *ScheduledThreadPool) intervalRunner(){
	stf.updateCounter()
	currentTasksToRun,ok:=stf.tasks.Load(stf.counter)

	if ok {
		currentTasksSet := currentTasksToRun.(*ds.Set)

		for _,val:= range currentTasksSet.GetAll() {
			task:=val.(Runnable)
			worker:=<-stf.workers
			worker <- task
		}
	}
}

func (stf *ScheduledThreadPool) updateCounter(){
	stf.counterLock.Lock()
	stf.counter++
	stf.counterLock.Unlock()
}

<commit_msg>refactored and added documents<commit_after>package threadpool

import (
	"sync"
	"math"
	"nokia.com/nas/services/telemetry_service_go/ds"
	"time"
)

// ScheduledThreadPool
// Schedules the task with the given delay
type ScheduledThreadPool struct {
	workers     chan chan Runnable
	tasks       *sync.Map
	noOfWorkers int
	counter     uint64
	queueSize   int64
	counterLock sync.Mutex
}

// NewScheduledThreadPool creates new scheduler thread pool with given number of workers
func NewScheduledThreadPool(noOfWorkers int) *ScheduledThreadPool {
	pool := &ScheduledThreadPool{}
	pool.noOfWorkers = noOfWorkers
	pool.queueSize = math.MaxInt32
	pool.workers = make(chan chan Runnable, noOfWorkers)
	pool.tasks = new(sync.Map)
	pool.createPool()
	return pool
}

// createPool creates the workers pool
func (stf *ScheduledThreadPool) createPool() {
	for i := 0; i < stf.noOfWorkers; i++ {
		worker := NewWorker(stf.workers)
		worker.Start()
	}

	go stf.dispatch()
}

// dispatch will check for the task to run for current time and invoke the task
func (stf *ScheduledThreadPool) dispatch() {
	for {
		go stf.intervalRunner()     // Runner to check the task to run for current time
		time.Sleep(time.Second * 1) // Check again after 1 sec
	}
}

// intervalRunner checks the tasks map and runs the tasks that are applicable at this point of time
func (stf *ScheduledThreadPool) intervalRunner() {
	// update the time count
	stf.updateCounter()

	// Get the task for the counter value
	currentTasksToRun, ok := stf.tasks.Load(stf.counter)

	// Found tasks
	if ok {
		// Convert to tasks set
		currentTasksSet := currentTasksToRun.(*ds.Set)

		// For each tasks , get a worker from the pool and run the task
		for _, val := range currentTasksSet.GetAll() {
			job := val.(Runnable)

			go func(job Runnable) {
				// get the worker from pool who is free
				worker := <-stf.workers
				// Submit the job to the worker
				worker <- job
			}(job)
		}
	}
}

// updateCounter thread safe update of counter
func (stf *ScheduledThreadPool) updateCounter() {
	stf.counterLock.Lock()
	stf.counter++
	stf.counterLock.Unlock()
}
<|endoftext|>


<commit_before><commit_msg>Custom error for when there is no worker available<commit_after><|endoftext|>