<commit_before>package aws

import (
	"fmt"
	"log"
	"regexp"
	"strings"
	"time"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/service/sagemaker"
	"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
	"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
	"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
	"github.com/terraform-providers/terraform-provider-aws/aws/internal/keyvaluetags"
	"github.com/terraform-providers/terraform-provider-aws/aws/internal/service/sagemaker/finder"
	"github.com/terraform-providers/terraform-provider-aws/aws/internal/service/sagemaker/waiter"
)

func resourceAwsSagemakerImage() *schema.Resource {
	return &schema.Resource{
		Create: resourceAwsSagemakerImageCreate,
		Read:   resourceAwsSagemakerImageRead,
		Update: resourceAwsSagemakerImageUpdate,
		Delete: resourceAwsSagemakerImageDelete,
		Importer: &schema.ResourceImporter{
			State: schema.ImportStatePassthrough,
		},

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

			"image_name": {
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
				ValidateFunc: validation.All(
					validation.StringLenBetween(1, 63),
					validation.StringMatch(regexp.MustCompile(`^[a-zA-Z0-9](-*[a-zA-Z0-9])*$`), "Valid characters are a-z, A-Z, 0-9, and - (hyphen)."),
				),
			},
			"role_arn": {
				Type:         schema.TypeString,
				Required:     true,
				ForceNew:     true,
				ValidateFunc: validateArn,
			},
			"display_name": {
				Type:         schema.TypeString,
				Optional:     true,
				ValidateFunc: validation.StringLenBetween(1, 128),
			},
			"description": {
				Type:         schema.TypeString,
				Optional:     true,
				ValidateFunc: validation.StringLenBetween(1, 512),
			},
			"tags": tagsSchema(),
		},
	}
}

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

	name := d.Get("image_name").(string)
	input := &sagemaker.CreateImageInput{
		ImageName: aws.String(name),
		RoleArn:   aws.String(d.Get("role_arn").(string)),
	}

	if v, ok := d.GetOk("display_name"); ok {
		input.DisplayName = aws.String(v.(string))
	}

	if v, ok := d.GetOk("description"); ok {
		input.Description = aws.String(v.(string))
	}

	if v, ok := d.GetOk("tags"); ok {
		input.Tags = keyvaluetags.New(v.(map[string]interface{})).IgnoreAws().SagemakerTags()
	}

	// for some reason even if the operation is retried the same response is given even though the role is valid. a short sleep before creation solves it.
	time.Sleep(1 * time.Minute)
	log.Printf("[DEBUG] sagemaker Image create config: %#v", *input)
	err := resource.Retry(1*time.Minute, func() *resource.RetryError {
		var err error
		_, err = conn.CreateImage(input)
		if err != nil {
			return resource.NonRetryableError(fmt.Errorf("error creating SageMaker Image: %w", err))
		}

		d.SetId(name)

		out, err := waiter.ImageCreated(conn, d.Id())

		if strings.Contains(aws.StringValue(out.FailureReason), "Unable to assume role with RoleArn") {
			return resource.RetryableError(err)
		}
		if err != nil {
			return resource.NonRetryableError(fmt.Errorf("error waiting for SageMaker Image (%s) to create: %w", d.Id(), err))
		}
		return nil
	})
	if isResourceTimeoutError(err) {
		_, err = conn.CreateImage(input)
		_, err = waiter.ImageCreated(conn, d.Id())
	}
	if err != nil {
		return fmt.Errorf("error creating SageMaker Image %s: %w", name, err)
	}

	return resourceAwsSagemakerImageRead(d, meta)
}

func resourceAwsSagemakerImageRead(d *schema.ResourceData, meta interface{}) error {
	conn := meta.(*AWSClient).sagemakerconn
	ignoreTagsConfig := meta.(*AWSClient).IgnoreTagsConfig

	image, err := finder.ImageByName(conn, d.Id())
	if err != nil {
		if isAWSErr(err, sagemaker.ErrCodeResourceNotFound, "No Image with the name") {
			d.SetId("")
			log.Printf("[WARN] Unable to find SageMaker Image (%s); removing from state", d.Id())
			return nil
		}
		return fmt.Errorf("error reading SageMaker Image (%s): %w", d.Id(), err)

	}

	arn := aws.StringValue(image.ImageArn)
	d.Set("image_name", image.ImageName)
	d.Set("arn", arn)
	d.Set("role_arn", image.RoleArn)
	d.Set("display_name", image.DisplayName)
	d.Set("description", image.Description)

	tags, err := keyvaluetags.SagemakerListTags(conn, arn)

	if err != nil {
		return fmt.Errorf("error listing tags for SageMaker Image (%s): %w", d.Id(), err)
	}

	if err := d.Set("tags", tags.IgnoreAws().IgnoreConfig(ignoreTagsConfig).Map()); err != nil {
		return fmt.Errorf("error setting tags: %w", err)
	}

	return nil
}

func resourceAwsSagemakerImageUpdate(d *schema.ResourceData, meta interface{}) error {
	conn := meta.(*AWSClient).sagemakerconn
	needsUpdate := false

	input := &sagemaker.UpdateImageInput{
		ImageName: aws.String(d.Id()),
	}

	var deleteProperties []*string

	if d.HasChange("description") {
		if v, ok := d.GetOk("description"); ok {
			input.Description = aws.String(v.(string))
		} else {
			deleteProperties = append(deleteProperties, aws.String("Description"))
			input.DeleteProperties = deleteProperties
		}
		needsUpdate = true
	}

	if d.HasChange("display_name") {
		if v, ok := d.GetOk("display_name"); ok {
			input.DisplayName = aws.String(v.(string))
		} else {
			deleteProperties = append(deleteProperties, aws.String("DisplayName"))
			input.DeleteProperties = deleteProperties
		}
		needsUpdate = true
	}

	if needsUpdate {
		log.Printf("[DEBUG] sagemaker Image update config: %#v", *input)
		_, err := conn.UpdateImage(input)
		if err != nil {
			return fmt.Errorf("error updating SageMaker Image: %w", err)
		}

		if _, err := waiter.ImageCreated(conn, d.Id()); err != nil {
			return fmt.Errorf("error waiting for SageMaker Image (%s) to update: %w", d.Id(), err)
		}
	}

	if d.HasChange("tags") {
		o, n := d.GetChange("tags")

		if err := keyvaluetags.SagemakerUpdateTags(conn, d.Get("arn").(string), o, n); err != nil {
			return fmt.Errorf("error updating SageMaker Image (%s) tags: %s", d.Id(), err)
		}
	}

	return resourceAwsSagemakerImageRead(d, meta)
}

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

	input := &sagemaker.DeleteImageInput{
		ImageName: aws.String(d.Id()),
	}

	if _, err := conn.DeleteImage(input); err != nil {
		if isAWSErr(err, sagemaker.ErrCodeResourceNotFound, "No Image with the name") {
			return nil
		}
		return fmt.Errorf("error deleting SageMaker Image (%s): %w", d.Id(), err)
	}

	if _, err := waiter.ImageDeleted(conn, d.Id()); err != nil {
		if isAWSErr(err, sagemaker.ErrCodeResourceNotFound, "No Image with the name") {
			return nil
		}
		return fmt.Errorf("error waiting for SageMaker Image (%s) to delete: %w", d.Id(), err)

	}

	return nil
}
<commit_msg>comment<commit_after>package aws

import (
	"fmt"
	"log"
	"regexp"
	"strings"
	"time"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/service/sagemaker"
	"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
	"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
	"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
	"github.com/terraform-providers/terraform-provider-aws/aws/internal/keyvaluetags"
	"github.com/terraform-providers/terraform-provider-aws/aws/internal/service/sagemaker/finder"
	"github.com/terraform-providers/terraform-provider-aws/aws/internal/service/sagemaker/waiter"
)

func resourceAwsSagemakerImage() *schema.Resource {
	return &schema.Resource{
		Create: resourceAwsSagemakerImageCreate,
		Read:   resourceAwsSagemakerImageRead,
		Update: resourceAwsSagemakerImageUpdate,
		Delete: resourceAwsSagemakerImageDelete,
		Importer: &schema.ResourceImporter{
			State: schema.ImportStatePassthrough,
		},

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

			"image_name": {
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
				ValidateFunc: validation.All(
					validation.StringLenBetween(1, 63),
					validation.StringMatch(regexp.MustCompile(`^[a-zA-Z0-9](-*[a-zA-Z0-9])*$`), "Valid characters are a-z, A-Z, 0-9, and - (hyphen)."),
				),
			},
			"role_arn": {
				Type:         schema.TypeString,
				Required:     true,
				ForceNew:     true,
				ValidateFunc: validateArn,
			},
			"display_name": {
				Type:         schema.TypeString,
				Optional:     true,
				ValidateFunc: validation.StringLenBetween(1, 128),
			},
			"description": {
				Type:         schema.TypeString,
				Optional:     true,
				ValidateFunc: validation.StringLenBetween(1, 512),
			},
			"tags": tagsSchema(),
		},
	}
}

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

	name := d.Get("image_name").(string)
	input := &sagemaker.CreateImageInput{
		ImageName: aws.String(name),
		RoleArn:   aws.String(d.Get("role_arn").(string)),
	}

	if v, ok := d.GetOk("display_name"); ok {
		input.DisplayName = aws.String(v.(string))
	}

	if v, ok := d.GetOk("description"); ok {
		input.Description = aws.String(v.(string))
	}

	if v, ok := d.GetOk("tags"); ok {
		input.Tags = keyvaluetags.New(v.(map[string]interface{})).IgnoreAws().SagemakerTags()
	}

	// for some reason even if the operation is retried the same error response is given even though the role is valid. a short sleep before creation solves it.
	time.Sleep(1 * time.Minute)
	log.Printf("[DEBUG] sagemaker Image create config: %#v", *input)
	err := resource.Retry(1*time.Minute, func() *resource.RetryError {
		var err error
		_, err = conn.CreateImage(input)
		if err != nil {
			return resource.NonRetryableError(fmt.Errorf("error creating SageMaker Image: %w", err))
		}

		d.SetId(name)

		out, err := waiter.ImageCreated(conn, d.Id())

		if strings.Contains(aws.StringValue(out.FailureReason), "Unable to assume role with RoleArn") {
			return resource.RetryableError(err)
		}
		if err != nil {
			return resource.NonRetryableError(fmt.Errorf("error waiting for SageMaker Image (%s) to create: %w", d.Id(), err))
		}
		return nil
	})
	if isResourceTimeoutError(err) {
		_, err = conn.CreateImage(input)
		_, err = waiter.ImageCreated(conn, d.Id())
	}
	if err != nil {
		return fmt.Errorf("error creating SageMaker Image %s: %w", name, err)
	}

	return resourceAwsSagemakerImageRead(d, meta)
}

func resourceAwsSagemakerImageRead(d *schema.ResourceData, meta interface{}) error {
	conn := meta.(*AWSClient).sagemakerconn
	ignoreTagsConfig := meta.(*AWSClient).IgnoreTagsConfig

	image, err := finder.ImageByName(conn, d.Id())
	if err != nil {
		if isAWSErr(err, sagemaker.ErrCodeResourceNotFound, "No Image with the name") {
			d.SetId("")
			log.Printf("[WARN] Unable to find SageMaker Image (%s); removing from state", d.Id())
			return nil
		}
		return fmt.Errorf("error reading SageMaker Image (%s): %w", d.Id(), err)

	}

	arn := aws.StringValue(image.ImageArn)
	d.Set("image_name", image.ImageName)
	d.Set("arn", arn)
	d.Set("role_arn", image.RoleArn)
	d.Set("display_name", image.DisplayName)
	d.Set("description", image.Description)

	tags, err := keyvaluetags.SagemakerListTags(conn, arn)

	if err != nil {
		return fmt.Errorf("error listing tags for SageMaker Image (%s): %w", d.Id(), err)
	}

	if err := d.Set("tags", tags.IgnoreAws().IgnoreConfig(ignoreTagsConfig).Map()); err != nil {
		return fmt.Errorf("error setting tags: %w", err)
	}

	return nil
}

func resourceAwsSagemakerImageUpdate(d *schema.ResourceData, meta interface{}) error {
	conn := meta.(*AWSClient).sagemakerconn
	needsUpdate := false

	input := &sagemaker.UpdateImageInput{
		ImageName: aws.String(d.Id()),
	}

	var deleteProperties []*string

	if d.HasChange("description") {
		if v, ok := d.GetOk("description"); ok {
			input.Description = aws.String(v.(string))
		} else {
			deleteProperties = append(deleteProperties, aws.String("Description"))
			input.DeleteProperties = deleteProperties
		}
		needsUpdate = true
	}

	if d.HasChange("display_name") {
		if v, ok := d.GetOk("display_name"); ok {
			input.DisplayName = aws.String(v.(string))
		} else {
			deleteProperties = append(deleteProperties, aws.String("DisplayName"))
			input.DeleteProperties = deleteProperties
		}
		needsUpdate = true
	}

	if needsUpdate {
		log.Printf("[DEBUG] sagemaker Image update config: %#v", *input)
		_, err := conn.UpdateImage(input)
		if err != nil {
			return fmt.Errorf("error updating SageMaker Image: %w", err)
		}

		if _, err := waiter.ImageCreated(conn, d.Id()); err != nil {
			return fmt.Errorf("error waiting for SageMaker Image (%s) to update: %w", d.Id(), err)
		}
	}

	if d.HasChange("tags") {
		o, n := d.GetChange("tags")

		if err := keyvaluetags.SagemakerUpdateTags(conn, d.Get("arn").(string), o, n); err != nil {
			return fmt.Errorf("error updating SageMaker Image (%s) tags: %s", d.Id(), err)
		}
	}

	return resourceAwsSagemakerImageRead(d, meta)
}

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

	input := &sagemaker.DeleteImageInput{
		ImageName: aws.String(d.Id()),
	}

	if _, err := conn.DeleteImage(input); err != nil {
		if isAWSErr(err, sagemaker.ErrCodeResourceNotFound, "No Image with the name") {
			return nil
		}
		return fmt.Errorf("error deleting SageMaker Image (%s): %w", d.Id(), err)
	}

	if _, err := waiter.ImageDeleted(conn, d.Id()); err != nil {
		if isAWSErr(err, sagemaker.ErrCodeResourceNotFound, "No Image with the name") {
			return nil
		}
		return fmt.Errorf("error waiting for SageMaker Image (%s) to delete: %w", d.Id(), err)

	}

	return nil
}
<|endoftext|>


<commit_before>// +build ignore

package main

import (
	"math"
	"math/rand"
)

// shuffle a Slice
func shuffle(data []string) {
	n := len(data)
	for i := n - 1; i >= 0; i-- {
		j := rand.Intn(i + 1)
		data[i], data[j] = data[j], data[i]
	}
}

// Convert degrees to radians
func radians(degrees float64) float64 {
	return degrees * math.Pi / 180.0
}

// Calculates distance between two latitude-longitude coordinates.
func distance(a [2]float64, b [2]float64) float64 {
	R := 3963.0 // radius of Earth (miles)
	lat1, lon1 := radians(a[0]), radians(a[1])
	lat2, lon2 := radians(b[0]), radians(b[1])
	return math.Acos(math.Sin(lat1)*math.Sin(lat2)+
		math.Cos(lat1)*math.Cos(lat2)*math.Cos(lon1-lon2)) * R
}

type Tuple [2]float64
type DMap map[string]float64

type America struct {
	Cities         map[string]Tuple
	DistanceMatrix map[string]DMap
}

func NewAmerica() *America {
	a := new(America)
	a.Cities = map[string]Tuple{
		"Grand Canyon, AZ":                      {36.106965, 112.112997},
		"Bryce Canyon, UT":                      {37.593038, 112.187090},
		"Craters of the Moon, ID":               {43.416650, 113.516650},
		"Yellowstone, WY":                       {44.462085, 110.642441},
		"Pikes Peak, CO":                        {38.840871, 105.042260},
		"Carlsbad Caverns, NM":                  {32.123169, 104.587450},
		"The Alamo, TX":                         {29.425967, 98.486142},
		"Chickasaw, OK":                         {34.457043, 97.012213},
		"Toltec Mounds, AR":                     {34.647037, 92.065143},
		"Graceland, TN":                         {35.047691, 90.026049},
		"Vicksburg, MS":                         {32.346550, 90.849850},
		"French Quarter, New Orleans, LA":       {29.958443, 90.064411},
		"USS Alabama, AL":                       {30.681803, 88.014426},
		"Cape Canaveral, FL":                    {28.388333, 80.603611},
		"Okefenokee Swamp, GA":                  {31.056794, 82.272327},
		"Fort Sumter, SC":                       {32.752348, 79.874692},
		"Lost World Caverns, WV":                {37.801788, 80.445630},
		"Wright Brothers Visitor Center, NC":    {35.908226, 75.675730},
		"Mount Vernon, VA":                      {38.729314, 77.107386},
		"White House, DC":                       {38.897676, 77.036530},
		"Maryland State House, MD":              {38.978828, 76.490974},
		"New Castle Historic District, DE":      {39.658242, 75.562335},
		"Congress Hall, Cape May, NJ":           {38.931843, 74.924184},
		"Liberty Bell, PA":                      {39.949610, 75.150282},
		"Statue of Liberty, NY":                 {40.689249, 74.044500},
		"Mark Twain House, Hartford, CT":        {41.766759, 72.701173},
		"The Breakers, Newport, RI":             {41.469858, 71.298265},
		"USS Constitution, Boston, MA":          {42.372470, 71.056575},
		"Acadia National Park, ME":              {44.338556, 68.273335},
		"Mount Washington, Bretton Woods, NH":   {44.258120, 71.441189},
		"Shelburne Farms, VT":                   {44.408948, 73.247227},
		"Olympia Entertainment, Detroit, MI":    {42.387579, 83.084943},
		"Spring Grove Cemetery, Cincinnati, OH": {39.174331, 84.524997},
		"Mammoth Cave National Park, KY":        {37.186998, 86.100528},
		"West Baden Springs Hotel, IN":          {38.566697, 86.617524},
		"Gateway Arch, St. Louis, MO":           {38.624691, 90.184776},
		"Lincoln Visitor Center, IL":            {39.797519, 89.646184},
		"Taliesin, WI":                          {43.141031, 90.070467},
		"Fort Snelling, MN":                     {44.892850, 93.180627},
		"Terrace Hill, IA":                      {41.583218, 93.648542},
		"C. W. Parker Carousel Museum, KS":      {39.317245, 94.909536},
		"Ashfall Fossil Bed, NE":                {42.425000, 98.158611},
		"Mount Rushmore, SD":                    {43.879102, 103.459067},
		"Fort Union Trading Post, ND":           {48.000160, 104.041483},
		"Glacier National Park, MT":             {48.759613, 113.787023},
		"Hanford Site, WA":                      {46.550684, 119.488974},
		"Columbia River Gorge, OR":              {45.711564, 121.519633},
		"Cable Car Museum, San Francisco, CA":   {37.794781, 122.411715},
		"San Andreas Fault, CA":                 {36.576088, 120.987632},
		"Hoover Dam, NV":                        {36.016066, 114.737732}}
	/*"New York City": {40.72, 74.00},
	"Los Angeles":   {34.05, 118.25},
	"Chicago":       {41.88, 87.63},
	"Houston":       {29.77, 95.38},
	"Phoenix":       {33.45, 112.07},
	"Philadelphia":  {39.95, 75.17},
	"San Antonio":   {29.53, 98.47},
	"Dallas":        {32.78, 96.80},
	"San Diego":     {32.78, 117.15},
	"San Jose":      {37.30, 121.87},
	"Detroit":       {42.33, 83.05},
	"San Francisco": {37.78, 122.42},
	"Jacksonville":  {30.32, 81.70},
	"Indianapolis":  {39.78, 86.15},
	"Austin":        {30.27, 97.77},
	"Columbus":      {39.98, 82.98},
	"Fort Worth":    {32.75, 97.33},
	"Charlotte":     {35.23, 80.85},
	"Memphis":       {35.12, 89.97},
	"Baltimore":     {39.28, 76.62}}*/
	// create a distance matrix
	a.DistanceMatrix = map[string]DMap{}
	for ka, va := range a.Cities {
		a.DistanceMatrix[ka] = DMap{}
		for kb, vb := range a.Cities {
			if kb == ka {
				a.DistanceMatrix[ka][kb] = 0.0
			} else {
				a.DistanceMatrix[ka][kb] = distance(va, vb)
			}
		}
	}
	return a
}

func (self *America) CitiesKeys() []string {
	ks := []string{}
	for k, _ := range self.Cities {
		ks = append(ks, k)
	}
	return ks
}
<commit_msg>Delete unused code<commit_after>// +build ignore

package main

import (
	"math"
	"math/rand"
)

// shuffle a Slice
func shuffle(data []string) {
	n := len(data)
	for i := n - 1; i >= 0; i-- {
		j := rand.Intn(i + 1)
		data[i], data[j] = data[j], data[i]
	}
}

// Convert degrees to radians
func radians(degrees float64) float64 {
	return degrees * math.Pi / 180.0
}

// Calculates distance between two latitude-longitude coordinates.
func distance(a [2]float64, b [2]float64) float64 {
	R := 3963.0 // radius of Earth (miles)
	lat1, lon1 := radians(a[0]), radians(a[1])
	lat2, lon2 := radians(b[0]), radians(b[1])
	return math.Acos(math.Sin(lat1)*math.Sin(lat2)+
		math.Cos(lat1)*math.Cos(lat2)*math.Cos(lon1-lon2)) * R
}

type Tuple [2]float64
type DMap map[string]float64

type America struct {
	Cities         map[string]Tuple
	DistanceMatrix map[string]DMap
}

func NewAmerica() *America {
	a := new(America)
	a.Cities = map[string]Tuple{
		"Grand Canyon, AZ":                      {36.106965, 112.112997},
		"Bryce Canyon, UT":                      {37.593038, 112.187090},
		"Craters of the Moon, ID":               {43.416650, 113.516650},
		"Yellowstone, WY":                       {44.462085, 110.642441},
		"Pikes Peak, CO":                        {38.840871, 105.042260},
		"Carlsbad Caverns, NM":                  {32.123169, 104.587450},
		"The Alamo, TX":                         {29.425967, 98.486142},
		"Chickasaw, OK":                         {34.457043, 97.012213},
		"Toltec Mounds, AR":                     {34.647037, 92.065143},
		"Graceland, TN":                         {35.047691, 90.026049},
		"Vicksburg, MS":                         {32.346550, 90.849850},
		"French Quarter, New Orleans, LA":       {29.958443, 90.064411},
		"USS Alabama, AL":                       {30.681803, 88.014426},
		"Cape Canaveral, FL":                    {28.388333, 80.603611},
		"Okefenokee Swamp, GA":                  {31.056794, 82.272327},
		"Fort Sumter, SC":                       {32.752348, 79.874692},
		"Lost World Caverns, WV":                {37.801788, 80.445630},
		"Wright Brothers Visitor Center, NC":    {35.908226, 75.675730},
		"Mount Vernon, VA":                      {38.729314, 77.107386},
		"White House, DC":                       {38.897676, 77.036530},
		"Maryland State House, MD":              {38.978828, 76.490974},
		"New Castle Historic District, DE":      {39.658242, 75.562335},
		"Congress Hall, Cape May, NJ":           {38.931843, 74.924184},
		"Liberty Bell, PA":                      {39.949610, 75.150282},
		"Statue of Liberty, NY":                 {40.689249, 74.044500},
		"Mark Twain House, Hartford, CT":        {41.766759, 72.701173},
		"The Breakers, Newport, RI":             {41.469858, 71.298265},
		"USS Constitution, Boston, MA":          {42.372470, 71.056575},
		"Acadia National Park, ME":              {44.338556, 68.273335},
		"Mount Washington, Bretton Woods, NH":   {44.258120, 71.441189},
		"Shelburne Farms, VT":                   {44.408948, 73.247227},
		"Olympia Entertainment, Detroit, MI":    {42.387579, 83.084943},
		"Spring Grove Cemetery, Cincinnati, OH": {39.174331, 84.524997},
		"Mammoth Cave National Park, KY":        {37.186998, 86.100528},
		"West Baden Springs Hotel, IN":          {38.566697, 86.617524},
		"Gateway Arch, St. Louis, MO":           {38.624691, 90.184776},
		"Lincoln Visitor Center, IL":            {39.797519, 89.646184},
		"Taliesin, WI":                          {43.141031, 90.070467},
		"Fort Snelling, MN":                     {44.892850, 93.180627},
		"Terrace Hill, IA":                      {41.583218, 93.648542},
		"C. W. Parker Carousel Museum, KS":      {39.317245, 94.909536},
		"Ashfall Fossil Bed, NE":                {42.425000, 98.158611},
		"Mount Rushmore, SD":                    {43.879102, 103.459067},
		"Fort Union Trading Post, ND":           {48.000160, 104.041483},
		"Glacier National Park, MT":             {48.759613, 113.787023},
		"Hanford Site, WA":                      {46.550684, 119.488974},
		"Columbia River Gorge, OR":              {45.711564, 121.519633},
		"Cable Car Museum, San Francisco, CA":   {37.794781, 122.411715},
		"San Andreas Fault, CA":                 {36.576088, 120.987632},
		"Hoover Dam, NV":                        {36.016066, 114.737732}}

	// create a distance matrix
	a.DistanceMatrix = map[string]DMap{}
	for ka, va := range a.Cities {
		a.DistanceMatrix[ka] = DMap{}
		for kb, vb := range a.Cities {
			if kb == ka {
				a.DistanceMatrix[ka][kb] = 0.0
			} else {
				a.DistanceMatrix[ka][kb] = distance(va, vb)
			}
		}
	}
	return a
}

func (self *America) CitiesKeys() []string {
	ks := []string{}
	for k, _ := range self.Cities {
		ks = append(ks, k)
	}
	return ks
}
<|endoftext|>


<commit_before>//
// Copyright (c) 2003-2005 Maxim Sobolev. All rights reserved.
// Copyright (c) 2021 Sippy Software, Inc. All rights reserved.
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation and/or
// other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package main

import (
    "sync"
    "time"

    "sippy"
    "sippy/headers"
    "sippy/types"
)

type callController struct {
    uaA             sippy_types.UA
    uaO             sippy_types.UA
    lock            *sync.Mutex // this must be a reference to prevent memory leak
    id              int64
    cmap            *callMap
    identity_hf     sippy_header.SipHeader
    date_hf         *sippy_header.SipDate
}

func NewCallController(cmap *callMap, identity_hf sippy_header.SipHeader, date_hf *sippy_header.SipDate) *callController {
    self := &callController{
        id              : <-next_cc_id,
        uaO             : nil,
        lock            : new(sync.Mutex),
        cmap            : cmap,
        identity_hf     : identity_hf,
        date_hf         : date_hf,
    }
    self.uaA = sippy.NewUA(cmap.sip_tm, cmap.config, cmap.config.nh_addr, self, self.lock, nil)
    self.uaA.SetDeadCb(self.aDead)
    //self.uaA.SetCreditTime(5 * time.Second)
    return self
}

func (self *callController) RecvEvent(event sippy_types.CCEvent, ua sippy_types.UA) {
    if ua == self.uaA {
        if ev_try, ok := event.(*sippy.CCEventTry); ok {
            if ! self.SshakenVerify(ev_try) {
                self.uaA.RecvEvent(sippy.NewCCEventFail(608, "Rejected", event.GetRtime(), ""))
                return
            }
        }
        if self.uaO == nil {
            ev_try, ok := event.(*sippy.CCEventTry)
            if ! ok {
                self.uaA.RecvEvent(sippy.NewCCEventDisconnect(nil, event.GetRtime(), ""))
                return
            }
            self.uaO = sippy.NewUA(self.cmap.sip_tm, self.cmap.config, self.cmap.config.nh_addr, self, self.lock, nil)
            identity, date, err := self.SshakenAuth(ev_try.GetCLI(), ev_try.GetCLD())
            if err == nil {
                extra_headers := []sippy_header.SipHeader{
                    sippy_header.NewSipDate(date),
                    sippy_header.NewSipGenericHF("Identity", identity),
                }
                self.uaO.SetExtraHeaders(extra_headers)
            }
            self.uaO.SetDeadCb(self.oDead)
            self.uaO.SetRAddr(self.cmap.config.nh_addr)
        }
        self.uaO.RecvEvent(event)
    } else {
        self.uaA.RecvEvent(event)
    }
}

func (self *callController) SshakenVerify(ev_try *sippy.CCEventTry) bool {
    if self.identity_hf == nil || self.date_hf == nil {
        return false
    }
    identity := self.identity_hf.StringBody()
    date_ts, err := self.date_hf.GetTime()
    if err != nil {
        self.cmap.logger.Error("Error parsing Date: header: " + err.Error())
        return false
    }
    orig_tn := ev_try.GetCLI()
    dest_tn := ev_try.GetCLD()
    err = self.cmap.sshaken.Verify(identity, orig_tn, dest_tn, date_ts)
    return err == nil
}

func (self *callController) SshakenAuth(cli, cld string) (string, time.Time, error) {
    date_ts := time.Now()
    identity, err := self.cmap.sshaken.Authenticate(date_ts, cli, cld)
    return identity, date_ts, err
}

func (self *callController) aDead() {
    self.cmap.Remove(self.id)
}

func (self *callController) oDead() {
    self.cmap.Remove(self.id)
}

func (self *callController) Shutdown() {
    self.uaA.Disconnect(nil, "")
}

func (self *callController) String() string {
    res := "uaA:" + self.uaA.String() + ", uaO: "
    if self.uaO == nil {
        res += "nil"
    } else {
        res += self.uaO.String()
    }
    return res
}
<commit_msg>Add some debug.<commit_after>//
// Copyright (c) 2003-2005 Maxim Sobolev. All rights reserved.
// Copyright (c) 2021 Sippy Software, Inc. All rights reserved.
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation and/or
// other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package main

import (
    "sync"
    "time"

    "sippy"
    "sippy/headers"
    "sippy/types"
)

type callController struct {
    uaA             sippy_types.UA
    uaO             sippy_types.UA
    lock            *sync.Mutex // this must be a reference to prevent memory leak
    id              int64
    cmap            *callMap
    identity_hf     sippy_header.SipHeader
    date_hf         *sippy_header.SipDate
    call_id	string
}

func NewCallController(cmap *callMap, identity_hf sippy_header.SipHeader, date_hf *sippy_header.SipDate) *callController {
    self := &callController{
        id              : <-next_cc_id,
        uaO             : nil,
        lock            : new(sync.Mutex),
        cmap            : cmap,
        identity_hf     : identity_hf,
        date_hf         : date_hf,
    }
    self.uaA = sippy.NewUA(cmap.sip_tm, cmap.config, cmap.config.nh_addr, self, self.lock, nil)
    self.uaA.SetDeadCb(self.aDead)
    //self.uaA.SetCreditTime(5 * time.Second)
    return self
}

func (self *callController) Error(msg string) {
	self.cmap.logger.Error(self.call_id + ": " + msg)
}

func (self *callController) RecvEvent(event sippy_types.CCEvent, ua sippy_types.UA) {
    if ua == self.uaA {
        if ev_try, ok := event.(*sippy.CCEventTry); ok {
	    self.call_id = ev_try.GetSipCallId().StringBody()
            if ! self.SshakenVerify(ev_try) {
                self.uaA.RecvEvent(sippy.NewCCEventFail(608, "Rejected", event.GetRtime(), ""))
                return
            }
        }
        if self.uaO == nil {
            ev_try, ok := event.(*sippy.CCEventTry)
            if ! ok {
                self.uaA.RecvEvent(sippy.NewCCEventDisconnect(nil, event.GetRtime(), ""))
                return
            }
            self.uaO = sippy.NewUA(self.cmap.sip_tm, self.cmap.config, self.cmap.config.nh_addr, self, self.lock, nil)
            identity, date, err := self.SshakenAuth(ev_try.GetCLI(), ev_try.GetCLD())
            if err == nil {
                extra_headers := []sippy_header.SipHeader{
                    sippy_header.NewSipDate(date),
                    sippy_header.NewSipGenericHF("Identity", identity),
                }
                self.uaO.SetExtraHeaders(extra_headers)
            }
            self.uaO.SetDeadCb(self.oDead)
            self.uaO.SetRAddr(self.cmap.config.nh_addr)
        }
        self.uaO.RecvEvent(event)
    } else {
        self.uaA.RecvEvent(event)
    }
}

func (self *callController) SshakenVerify(ev_try *sippy.CCEventTry) bool {
    if self.identity_hf == nil || self.date_hf == nil {
        self.Error("Verification failure: no identity provided")
        return false
    }
    identity := self.identity_hf.StringBody()
    date_ts, err := self.date_hf.GetTime()
    if err != nil {
        self.Error("Error parsing Date: header: " + err.Error())
        return false
    }
    orig_tn := ev_try.GetCLI()
    dest_tn := ev_try.GetCLD()
    err = self.cmap.sshaken.Verify(identity, orig_tn, dest_tn, date_ts)
    if err != nil {
	    self.Error("Verification failure: " + err.Error())
    }
    return err == nil
}

func (self *callController) SshakenAuth(cli, cld string) (string, time.Time, error) {
    date_ts := time.Now()
    identity, err := self.cmap.sshaken.Authenticate(date_ts, cli, cld)
    return identity, date_ts, err
}

func (self *callController) aDead() {
    self.cmap.Remove(self.id)
}

func (self *callController) oDead() {
    self.cmap.Remove(self.id)
}

func (self *callController) Shutdown() {
    self.uaA.Disconnect(nil, "")
}

func (self *callController) String() string {
    res := "uaA:" + self.uaA.String() + ", uaO: "
    if self.uaO == nil {
        res += "nil"
    } else {
        res += self.uaO.String()
    }
    return res
}
<|endoftext|>


<commit_before>package towerfall

import (
	"fmt"
	"log"
	"math"
	"math/rand"
	"sort"

	"github.com/deckarep/golang-set"
	"github.com/pkg/errors"
)

// AllColors is a list of the available player colors
var AllColors = []interface{}{
	"green",
	"blue",
	"pink",
	"orange",
	"white",
	"yellow",
	"cyan",
	"purple",
	"red",
}

// Colors is the definitive set of all the colors
var Colors = mapset.NewSetFromSlice(AllColors)

const scoreMultiplier = 7
const scoreSweep = (97 * scoreMultiplier)
const scoreKill = (21 * scoreMultiplier)
const scoreSelf = (-35 * scoreMultiplier) // Negative 1.66 times of a kill
const scoreWinner = (350 * scoreMultiplier)
const scoreSecond = (150 * scoreMultiplier)
const scoreThird = (70 * scoreMultiplier)
const scoreFourth = (30 * scoreMultiplier)

const finalMultiplier = 2.5
const finalExponential = 1.05

// ScoreData is a structured Key/Value pair list for scores
type ScoreData struct {
	Key    string
	Value  int
	Player *Player
}

// Player is a representation of one player in a match
type Player struct {
	ID             uint         `json:"id"`
	MatchID        uint         `sql:",pk" json:"match_id"`
	PersonID       string       `json:"person_id"`
	Person         *Person      `json:"person"`
	Nick           string       `json:"nick"`
	Color          string       `json:"color"`
	PreferredColor string       `json:"preferred_color"`
	ArcherType     int          `json:"archer_type" sql:",notnull"`
	Shots          int          `json:"shots" sql:",notnull"`
	Sweeps         int          `json:"sweeps" sql:",notnull"`
	Kills          int          `json:"kills" sql:",notnull"`
	Self           int          `json:"self" sql:",notnull"`
	MatchScore     int          `json:"match_score" sql:",notnull"`
	TotalScore     int          `json:"total_score" sql:",notnull"`
	State          *PlayerState `json:"state"`
	Match          *Match       `json:"-" sql:"-"`
	DisplayNames   []string     `sql:",array" json:"display_names"`
}

// A PlayerSummary is a tournament-wide summary of the scores a player has
type PlayerSummary struct {
	ID           uint    `json:"id"`
	TournamentID uint    `json:"-"`
	PersonID     string  `json:"person_id"`
	Person       *Person `json:"person"`
	Shots        int     `json:"shots" sql:",notnull"`
	Sweeps       int     `json:"sweeps" sql:",notnull"`
	Kills        int     `json:"kills" sql:",notnull"`
	Self         int     `json:"self" sql:",notnull"`
	Matches      int     `json:"matches" sql:",notnull"`
	TotalScore   int     `json:"score" sql:",notnull"`
	SkillScore   int     `json:"skill_score" sql:",notnull"`
}

type PlayerState struct {
	ID        uint   `json:"id"`
	PlayerID  uint   `json:"-"`
	Arrows    Arrows `json:"arrows"`
	Shield    bool   `json:"shield"`
	Wings     bool   `json:"wings"`
	Hat       bool   `json:"hat"`
	Invisible bool   `json:"invisible"`
	Speed     bool   `json:"speed"`
	Alive     bool   `json:"alive"`
	Lava      bool   `json:"lava"`
	Killer    int    `json:"killer" sql:",notnull"`
}

// NewPlayer returns a new instance of a player
func NewPlayer(ps *Person) *Player {
	p := &Player{
		PersonID:       ps.PersonID,
		Person:         ps,
		Nick:           ps.Nick,
		ArcherType:     ps.ArcherType,
		State:          NewPlayerState(),
		PreferredColor: ps.PreferredColor,
		DisplayNames:   ps.DisplayNames,
	}

	if p.PreferredColor != "" {
		p.PreferredColor = ps.PreferredColor
	} else {
		p.PreferredColor = RandomColor(Colors)
	}

	return p
}

func NewPlayerState() *PlayerState {
	ps := &PlayerState{
		Arrows: make(Arrows, 0),
		Alive:  true,
		Hat:    true,
		Killer: -2,
	}
	return ps
}

// NewPlayerSummary returns a new instance of a tournament player
func NewPlayerSummary(ps *Person) *PlayerSummary {
	p := &PlayerSummary{
		PersonID: ps.PersonID,
		Person:   ps,
	}
	return p
}

func (p *Player) String() string {
	return fmt.Sprintf(
		"<(%d) %s %s: %dsh %dsw %dk %ds>",
		p.ID,
		p.Nick,
		p.Color,
		p.Shots,
		p.Sweeps,
		p.Kills,
		p.Self,
	)
}

// Name returns the nickname
func (p *Player) Name() string {
	return p.Nick
}

// NumericColor is the numeric representation of the color the player has
func (p *Player) NumericColor() int {
	for x, c := range AllColors {
		if p.Color == c {
			return x
		}
	}

	// No color was found - this is a bug. Return default.
	log.Printf("Player '%s' did not match a color for '%s'", p.Nick, p.Color)
	return 0
}

// Score calculates the score to determine runnerup positions.
func (p *PlayerSummary) Score() (out int) {
	out += p.Sweeps * scoreSweep
	out += p.Kills * scoreKill
	out += p.Self * scoreSelf

	// Negative score is not allowed
	if out <= 0 {
		out = 0
	}

	return
}

// Score calculates the score to determine runnerup positions.
func (p *Player) Score() (out int) {
	out += p.Sweeps * scoreSweep
	out += p.Kills * scoreKill
	out += p.Self * scoreSelf

	// Negative score is not allowed
	if out <= 0 {
		out = 0
	}

	// Match score is added afterwards so that no one is stuck on 0.
	out += p.MatchScore

	return
}

// Summary resturns a Summary{} object for the player
func (p *Player) Summary() PlayerSummary {
	return PlayerSummary{
		PersonID: p.PersonID,
		Person:   p.Person,
		Shots:    p.Shots,
		Sweeps:   p.Sweeps,
		Kills:    p.Kills,
		Self:     p.Self,
	}
}

// Player returns a new Player{} object from the summary
func (p *PlayerSummary) Player() Player {
	if p.Person == nil {
		var err error
		p.Person, err = globalDB.GetPerson(p.PersonID)
		if err != nil {
			log.Fatal(err)
		}
	}

	return *NewPlayer(p.Person)
}

// getPerson gets the Person for a player
func (p *Player) getPerson() *Person {
	var err error
	if p.Person == nil {
		p.Person, err = globalDB.GetPerson(p.PersonID)
		if err != nil {
			log.Fatal(err)
		}
	}

	return p.Person
}

// ScoreData returns this players set of ScoreData
func (p *Player) ScoreData() []ScoreData {
	sd := []ScoreData{
		{Key: "kills", Value: p.Kills, Player: p},
		{Key: "shots", Value: p.Shots, Player: p},
		{Key: "sweeps", Value: p.Sweeps, Player: p},
		{Key: "self", Value: p.Self, Player: p},
	}
	return sd
}

// AddShot increases the shot count
func (p *Player) AddShot() {
	p.Shots++
}

// RemoveShot decreases the shot count
// Fails silently if shots are zero.
func (p *Player) RemoveShot() {
	if p.Shots == 0 {
		log.Printf("Not removing shot from %s; already at zero", p.Nick)
		return
	}
	p.Shots--
}

// AddSweep increases the sweep count
func (p *Player) AddSweep() {
	p.Sweeps++
}

// AddKills increases the kill count and adds a sweep if necessary
func (p *Player) AddKills(kills int) {
	p.Kills += kills
	if kills == 3 {
		p.AddSweep()
	}
}

// RemoveKill decreases the kill count
// Doesn't to anything if kills are at zero.
func (p *Player) RemoveKill() {
	if p.Kills == 0 {
		log.Printf("Not removing kill from %s; already at zero", p.Nick)
		return
	}
	p.Kills--
}

// AddSelf increases the self count and decreases the kill
func (p *Player) AddSelf() {
	p.Self++
	p.RemoveKill()
}

// Reset resets the stats on a PlayerSummary to 0
//
// It is to be run in Match.Start()
func (p *Player) Reset() {
	p.Shots = 0
	p.Sweeps = 0
	p.Kills = 0
	p.Self = 0
	p.State = NewPlayerState()
}

// ByColorConflict is a sort.Interface that sorts players by their score
type ByColorConflict []PlayerSummary

func (s ByColorConflict) Len() int { return len(s) }

func (s ByColorConflict) Swap(i, j int) { s[i], s[j] = s[j], s[i] }

func (s ByColorConflict) Less(i, j int) bool {
	if s[i].Person.Userlevel != s[j].Person.Userlevel {
		return s[i].Person.Userlevel > s[j].Person.Userlevel
	}
	return s[i].SkillScore > s[j].SkillScore
}

// ByScore is a sort.Interface that sorts players by their score
type ByScore []Player

func (s ByScore) Len() int {
	return len(s)

}
func (s ByScore) Swap(i, j int) {
	s[i], s[j] = s[j], s[i]

}
func (s ByScore) Less(i, j int) bool {
	// Technically not Less, but we want biggest first...
	return s[i].Score() > s[j].Score()
}

// SortByColorConflicts returns a list in an unspecified order,
// Probably by User level and then score.
func SortByColorConflicts(m *Match, ps []Person) (tmp []PlayerSummary, err error) {
	var tp *PlayerSummary
	tmp = make([]PlayerSummary, len(ps))
	for i, p := range ps {
		// TODO(thiderman): This is not very elegant and should be replaced.
		tp, err = m.Tournament.GetPlayerSummary(&p)
		if err != nil {
			return tmp, errors.WithStack(err)
		}
		tmp[i] = *tp
	}
	sort.Sort(ByColorConflict(tmp))
	return
}

// ByKills is a sort.Interface that sorts players by their kills
type ByKills []*Player

func (s ByKills) Len() int {
	return len(s)

}
func (s ByKills) Swap(i, j int) {
	s[i], s[j] = s[j], s[i]

}
func (s ByKills) Less(i, j int) bool {
	// Technically not Less, but we want biggest first...
	iKills := s[i].Kills
	jKills := s[j].Kills
	if iKills == jKills {
		return s[i].Score() > s[j].Score()
	}
	return iKills > jKills
}

// SortByKills returns a list in order of the kills the players have
func SortByKills(ps []*Player) []*Player {
	tmp := make([]*Player, len(ps))
	copy(tmp, ps)
	sort.Sort(ByKills(tmp))
	return tmp
}

// RandomColor returns a random color from the ColorList
func RandomColor(s mapset.Set) string {
	colors := s.ToSlice()
	x := len(colors)
	return colors[rand.Intn(x)].(string)
}

// AvailableColors returns a ColorList with the colors not used in a match
func AvailableColors(m *Match) mapset.Set {
	colors := mapset.NewSetFromSlice(AllColors)
	ret := colors.Difference(m.presentColors)
	return ret
}

// Reset resets the stats on a PlayerSummary to 0
//
// It is to be run in Match.Start()
func (p *PlayerSummary) Reset() {
	p.Shots = 0
	p.Sweeps = 0
	p.Kills = 0
	p.Self = 0
	p.Matches = 0
}

// Update updates a player with the scores of another
//
// This is primarily used by the tournament score calculator
func (p *PlayerSummary) Update(other PlayerSummary) {
	p.Shots += other.Shots
	p.Sweeps += other.Sweeps
	p.Kills += other.Kills
	p.Self += other.Self
	p.TotalScore = p.Score()

	// Every call to this method is per match. Count every call
	// as if a match.
	p.Matches++
	// log.Printf("Updated player: %d, %d", p.TotalScore, p.Matches)
}

// DividePlayoffPlayers divides the playoff players into four buckets based
// on their score
//
// The input is expected to be sorted with score descending
func DividePlayoffPlayers(ps []*PlayerSummary) ([][]*PlayerSummary, error) {
	ret := [][]*PlayerSummary{
		[]*PlayerSummary{},
		[]*PlayerSummary{},
		[]*PlayerSummary{},
		[]*PlayerSummary{},
	}

	for x, p := range ps {
		ret[x%4] = append(ret[x%4], p)
	}

	return ret, nil
}

// FinalMultiplier returns the multiplier used for the winner scores
// in the final
//
// The longer at tournament lasts, the more points you'll get for
// winning the final.
func FinalMultiplier(numMatches int) float64 {
	// We only count extra when there has been more than 16 matches
	x := numMatches - 16

	// If there haven't been, just return the default
	if x <= 0 {
		return finalMultiplier
	}

	return finalMultiplier * math.Pow(finalExponential, float64(x))
}
<commit_msg>Add Index to Player{}<commit_after>package towerfall

import (
	"fmt"
	"log"
	"math"
	"math/rand"
	"sort"

	"github.com/deckarep/golang-set"
	"github.com/pkg/errors"
)

// AllColors is a list of the available player colors
var AllColors = []interface{}{
	"green",
	"blue",
	"pink",
	"orange",
	"white",
	"yellow",
	"cyan",
	"purple",
	"red",
}

// Colors is the definitive set of all the colors
var Colors = mapset.NewSetFromSlice(AllColors)

const scoreMultiplier = 7
const scoreSweep = (97 * scoreMultiplier)
const scoreKill = (21 * scoreMultiplier)
const scoreSelf = (-35 * scoreMultiplier) // Negative 1.66 times of a kill
const scoreWinner = (350 * scoreMultiplier)
const scoreSecond = (150 * scoreMultiplier)
const scoreThird = (70 * scoreMultiplier)
const scoreFourth = (30 * scoreMultiplier)

const finalMultiplier = 2.5
const finalExponential = 1.05

// ScoreData is a structured Key/Value pair list for scores
type ScoreData struct {
	Key    string
	Value  int
	Player *Player
}

// Player is a representation of one player in a match
type Player struct {
	ID             uint         `json:"id"`
	MatchID        uint         `sql:",pk" json:"match_id"`
	PersonID       string       `json:"person_id"`
	Index          int          `json:"index" sql:",notnull"`
	Person         *Person      `json:"person"`
	Nick           string       `json:"nick"`
	Color          string       `json:"color"`
	PreferredColor string       `json:"preferred_color"`
	ArcherType     int          `json:"archer_type" sql:",notnull"`
	Shots          int          `json:"shots" sql:",notnull"`
	Sweeps         int          `json:"sweeps" sql:",notnull"`
	Kills          int          `json:"kills" sql:",notnull"`
	Self           int          `json:"self" sql:",notnull"`
	MatchScore     int          `json:"match_score" sql:",notnull"`
	TotalScore     int          `json:"total_score" sql:",notnull"`
	State          *PlayerState `json:"state"`
	Match          *Match       `json:"-" sql:"-"`
	DisplayNames   []string     `sql:",array" json:"display_names"`
}

// A PlayerSummary is a tournament-wide summary of the scores a player has
type PlayerSummary struct {
	ID           uint    `json:"id"`
	TournamentID uint    `json:"-"`
	PersonID     string  `json:"person_id"`
	Person       *Person `json:"person"`
	Shots        int     `json:"shots" sql:",notnull"`
	Sweeps       int     `json:"sweeps" sql:",notnull"`
	Kills        int     `json:"kills" sql:",notnull"`
	Self         int     `json:"self" sql:",notnull"`
	Matches      int     `json:"matches" sql:",notnull"`
	TotalScore   int     `json:"score" sql:",notnull"`
	SkillScore   int     `json:"skill_score" sql:",notnull"`
}

type PlayerState struct {
	ID        uint   `json:"id"`
	PlayerID  uint   `json:"player_id"`
	Index     int    `json:"index" sql:",notnull"`
	Arrows    Arrows `json:"arrows" sql:",array"`
	Shield    bool   `json:"shield" sql:",notnull"`
	Wings     bool   `json:"wings" sql:",notnull"`
	Hat       bool   `json:"hat" sql:",notnull"`
	Invisible bool   `json:"invisible" sql:",notnull"`
	Speed     bool   `json:"speed" sql:",notnull"`
	Alive     bool   `json:"alive" sql:",notnull"`
	Lava      bool   `json:"lava" sql:",notnull"`
	Killer    int    `json:"killer" sql:",notnull"`
}

// NewPlayer returns a new instance of a player
func NewPlayer(ps *Person) *Player {
	p := &Player{
		PersonID:       ps.PersonID,
		Person:         ps,
		Nick:           ps.Nick,
		ArcherType:     ps.ArcherType,
		State:          NewPlayerState(),
		PreferredColor: ps.PreferredColor,
		DisplayNames:   ps.DisplayNames,
	}

	if p.PreferredColor != "" {
		p.PreferredColor = ps.PreferredColor
	} else {
		p.PreferredColor = RandomColor(Colors)
	}

	return p
}

func NewPlayerState() *PlayerState {
	ps := &PlayerState{
		Arrows: make(Arrows, 0),
		Alive:  true,
		Hat:    true,
		Killer: -2,
	}
	return ps
}

// NewPlayerSummary returns a new instance of a tournament player
func NewPlayerSummary(ps *Person) *PlayerSummary {
	p := &PlayerSummary{
		PersonID: ps.PersonID,
		Person:   ps,
	}
	return p
}

func (p *Player) String() string {
	return fmt.Sprintf(
		"<(%d) %s %s: %dsh %dsw %dk %ds>",
		p.ID,
		p.Nick,
		p.Color,
		p.Shots,
		p.Sweeps,
		p.Kills,
		p.Self,
	)
}

// Name returns the nickname
func (p *Player) Name() string {
	return p.Nick
}

// NumericColor is the numeric representation of the color the player has
func (p *Player) NumericColor() int {
	for x, c := range AllColors {
		if p.Color == c {
			return x
		}
	}

	// No color was found - this is a bug. Return default.
	log.Printf("Player '%s' did not match a color for '%s'", p.Nick, p.Color)
	return 0
}

// Score calculates the score to determine runnerup positions.
func (p *PlayerSummary) Score() (out int) {
	out += p.Sweeps * scoreSweep
	out += p.Kills * scoreKill
	out += p.Self * scoreSelf

	// Negative score is not allowed
	if out <= 0 {
		out = 0
	}

	return
}

// Score calculates the score to determine runnerup positions.
func (p *Player) Score() (out int) {
	out += p.Sweeps * scoreSweep
	out += p.Kills * scoreKill
	out += p.Self * scoreSelf

	// Negative score is not allowed
	if out <= 0 {
		out = 0
	}

	// Match score is added afterwards so that no one is stuck on 0.
	out += p.MatchScore

	return
}

// Summary resturns a Summary{} object for the player
func (p *Player) Summary() PlayerSummary {
	return PlayerSummary{
		PersonID: p.PersonID,
		Person:   p.Person,
		Shots:    p.Shots,
		Sweeps:   p.Sweeps,
		Kills:    p.Kills,
		Self:     p.Self,
	}
}

// Player returns a new Player{} object from the summary
func (p *PlayerSummary) Player() Player {
	if p.Person == nil {
		var err error
		p.Person, err = globalDB.GetPerson(p.PersonID)
		if err != nil {
			log.Fatal(err)
		}
	}

	return *NewPlayer(p.Person)
}

// getPerson gets the Person for a player
func (p *Player) getPerson() *Person {
	var err error
	if p.Person == nil {
		p.Person, err = globalDB.GetPerson(p.PersonID)
		if err != nil {
			log.Fatal(err)
		}
	}

	return p.Person
}

// ScoreData returns this players set of ScoreData
func (p *Player) ScoreData() []ScoreData {
	sd := []ScoreData{
		{Key: "kills", Value: p.Kills, Player: p},
		{Key: "shots", Value: p.Shots, Player: p},
		{Key: "sweeps", Value: p.Sweeps, Player: p},
		{Key: "self", Value: p.Self, Player: p},
	}
	return sd
}

// AddShot increases the shot count
func (p *Player) AddShot() {
	p.Shots++
}

// RemoveShot decreases the shot count
// Fails silently if shots are zero.
func (p *Player) RemoveShot() {
	if p.Shots == 0 {
		log.Printf("Not removing shot from %s; already at zero", p.Nick)
		return
	}
	p.Shots--
}

// AddSweep increases the sweep count
func (p *Player) AddSweep() {
	p.Sweeps++
}

// AddKills increases the kill count and adds a sweep if necessary
func (p *Player) AddKills(kills int) {
	p.Kills += kills
	if kills == 3 {
		p.AddSweep()
	}
}

// RemoveKill decreases the kill count
// Doesn't to anything if kills are at zero.
func (p *Player) RemoveKill() {
	if p.Kills == 0 {
		log.Printf("Not removing kill from %s; already at zero", p.Nick)
		return
	}
	p.Kills--
}

// AddSelf increases the self count and decreases the kill
func (p *Player) AddSelf() {
	p.Self++
	p.RemoveKill()
}

// Reset resets the stats on a PlayerSummary to 0
//
// It is to be run in Match.Start()
func (p *Player) Reset() {
	p.Shots = 0
	p.Sweeps = 0
	p.Kills = 0
	p.Self = 0
	p.State = NewPlayerState()
}

// ByColorConflict is a sort.Interface that sorts players by their score
type ByColorConflict []PlayerSummary

func (s ByColorConflict) Len() int { return len(s) }

func (s ByColorConflict) Swap(i, j int) { s[i], s[j] = s[j], s[i] }

func (s ByColorConflict) Less(i, j int) bool {
	if s[i].Person.Userlevel != s[j].Person.Userlevel {
		return s[i].Person.Userlevel > s[j].Person.Userlevel
	}
	return s[i].SkillScore > s[j].SkillScore
}

// ByScore is a sort.Interface that sorts players by their score
type ByScore []Player

func (s ByScore) Len() int {
	return len(s)

}
func (s ByScore) Swap(i, j int) {
	s[i], s[j] = s[j], s[i]

}
func (s ByScore) Less(i, j int) bool {
	// Technically not Less, but we want biggest first...
	return s[i].Score() > s[j].Score()
}

// SortByColorConflicts returns a list in an unspecified order,
// Probably by User level and then score.
func SortByColorConflicts(m *Match, ps []Person) (tmp []PlayerSummary, err error) {
	var tp *PlayerSummary
	tmp = make([]PlayerSummary, len(ps))
	for i, p := range ps {
		// TODO(thiderman): This is not very elegant and should be replaced.
		tp, err = m.Tournament.GetPlayerSummary(&p)
		if err != nil {
			return tmp, errors.WithStack(err)
		}
		tmp[i] = *tp
	}
	sort.Sort(ByColorConflict(tmp))
	return
}

// ByKills is a sort.Interface that sorts players by their kills
type ByKills []*Player

func (s ByKills) Len() int {
	return len(s)

}
func (s ByKills) Swap(i, j int) {
	s[i], s[j] = s[j], s[i]

}
func (s ByKills) Less(i, j int) bool {
	// Technically not Less, but we want biggest first...
	iKills := s[i].Kills
	jKills := s[j].Kills
	if iKills == jKills {
		return s[i].Score() > s[j].Score()
	}
	return iKills > jKills
}

// SortByKills returns a list in order of the kills the players have
func SortByKills(ps []*Player) []*Player {
	tmp := make([]*Player, len(ps))
	copy(tmp, ps)
	sort.Sort(ByKills(tmp))
	return tmp
}

// RandomColor returns a random color from the ColorList
func RandomColor(s mapset.Set) string {
	colors := s.ToSlice()
	x := len(colors)
	return colors[rand.Intn(x)].(string)
}

// AvailableColors returns a ColorList with the colors not used in a match
func AvailableColors(m *Match) mapset.Set {
	colors := mapset.NewSetFromSlice(AllColors)
	ret := colors.Difference(m.presentColors)
	return ret
}

// Reset resets the stats on a PlayerSummary to 0
//
// It is to be run in Match.Start()
func (p *PlayerSummary) Reset() {
	p.Shots = 0
	p.Sweeps = 0
	p.Kills = 0
	p.Self = 0
	p.Matches = 0
}

// Update updates a player with the scores of another
//
// This is primarily used by the tournament score calculator
func (p *PlayerSummary) Update(other PlayerSummary) {
	p.Shots += other.Shots
	p.Sweeps += other.Sweeps
	p.Kills += other.Kills
	p.Self += other.Self
	p.TotalScore = p.Score()

	// Every call to this method is per match. Count every call
	// as if a match.
	p.Matches++
	// log.Printf("Updated player: %d, %d", p.TotalScore, p.Matches)
}

// DividePlayoffPlayers divides the playoff players into four buckets based
// on their score
//
// The input is expected to be sorted with score descending
func DividePlayoffPlayers(ps []*PlayerSummary) ([][]*PlayerSummary, error) {
	ret := [][]*PlayerSummary{
		[]*PlayerSummary{},
		[]*PlayerSummary{},
		[]*PlayerSummary{},
		[]*PlayerSummary{},
	}

	for x, p := range ps {
		ret[x%4] = append(ret[x%4], p)
	}

	return ret, nil
}

// FinalMultiplier returns the multiplier used for the winner scores
// in the final
//
// The longer at tournament lasts, the more points you'll get for
// winning the final.
func FinalMultiplier(numMatches int) float64 {
	// We only count extra when there has been more than 16 matches
	x := numMatches - 16

	// If there haven't been, just return the default
	if x <= 0 {
		return finalMultiplier
	}

	return finalMultiplier * math.Pow(finalExponential, float64(x))
}
<|endoftext|>


<commit_before>// Copyright (c) 2017 Andreas Auernhammer. All rights reserved.
// Use of this source code is governed by a license that can be
// found in the LICENSE file.

package auth

import (
	"bytes"
	"encoding/hex"
	"testing"
)

func fromHex(s string) []byte {
	b, err := hex.DecodeString(s)
	if err != nil {
		panic(err)
	}
	return b
}

func TestVectors(t *testing.T) {
	context := []byte("libtests")
	key := fromHex("000102030405060708090a0b0c0d0e0f")
	msg := make([]byte, 64)
	for i, v := range vectors {
		msg[i] = byte(i)

		tag := Sum(msg, context, key)
		if !bytes.Equal(tag[:], fromHex(v)) {
			t.Errorf("Failed at %d:\ngot:  %s\nwant: %s", i, hex.EncodeToString(tag[:]), v)
		}
	}
}

var vectors = []string{
	"f896e134f1a0c57e3caa11d37b48b5f3", "6df99f0e43e07c965c8b0f73d2ac9cd9", "ed001efc0e97d65b029bc997ef5f583b", "345e55d3a5b85574f38ee7b2662eb2eb",
	"6a6e245fda79d718f22e2cbe8d4556fd", "4850fc430a8055b96403324f4071b076", "99035dee17cdcddb9da4e5d9c5152ab2", "2477c9803dcbb6a86c4712374b205d9e",
	"916a038d182135002cdee0a61d2cb4b0", "62decae7c1e724dda73336e9956d2c4d", "c7c923bdbeb69074d918b7ed31b03dc2", "af95b43e7e939e1c5d55797a34d9343d",
	"cbb9fb310be777185e562b6b2b9a7548", "2baf051709deaebf4fcb387625ad8af4", "3a056cc5c9f18f31b00dc9d14766594c", "9bcfe38d12cfbfce83f4029458484961",
	"6e563359b4f674834aceeb80dd2eca04", "c8a4cd6594f79b3df6bf1426d5ffdb96", "751289b7ae385295309d62ae0ae7e9b2", "e56732e9505db8ab6823a2fcf6073f18",
	"ff793ba05b33ad2b40a28eed9bc5c9cc", "be07061fedca56082de9042a0ca18efe", "726d65f0eb9eb73999b316b3403e8551", "7b7f1cb11a1d589054f96ded6780b385",
	"c8614e59fb9d2f45d920b0e31ff70ba9", "97f7c865af57c4064532e5f3e47d0ee3", "fc6eed3abb33870978e01925931c2c77", "68517491cc1c0159039adef40e4a5884",
	"53f59cf2da263c41e11e4431f21ba975", "a042397d1177281ecfdeb94c7dada4b8", "2030770f95d4b08e6fe059158bfaaa80", "b8a4242bb9ecf78a30fbe1229a1cafca",
	"5e25dafd501eafde576bf1556bfa8c7b", "35310328ee7312987b1438f00cbd732b", "56379aa5f4ec19e52e1cbedb6cd54cf4", "b5d6db8d32c0614f87205cdeb43ec151",
	"303ae259d78a95b82a46cea9ca78d478", "d293b47452d4aab18cc01e80e63929bc", "808cceaa44a6d89eac19cca7f4f2a9a9", "a77c20c1fdc5db759e03f7394b10762e",
	"98c96bb66c170d184f394765decc87b8", "2308d737a6f27aeb18d76276223c4908", "91129370532baedb45aa01a72c517c77", "cd74314bb04228f71dd546e352ed19d6",
	"b2a422f69dab7b80f9c79f3601d27f5f", "658a50433acdea6f9c46888e2e4964cd", "ea2c33e0b9f1a241d4b90d2dc684e609", "068ea33c5d4fb4935ecc5bebd8a93d48",
	"d58e48c555dbadc09bff32223512398f", "07b69429bf3e7db8ac65a1099feeaa5f", "17a0607f65a4c6257d9f321a5bf7b4f2", "5f404445854ddab9c463f35fadc2cff8",
	"613bee96449b8c0cd52c2253a6635841", "c3fa9171de16beaf68ccffd49c1d10bb", "fa7fd667a792c36633a46556b19c324f", "dba0acbe3d5a0ad6b3e7a731820b153d",
	"91be4de60f5ba40ea02cbefd2072a1f9", "cd0b02ef791b0e206c38ae90109a561e", "80d0ca00aab2b1bdab63fc5237c908f1", "95f82495193d28373f5f661d6284a641",
	"1f622a4201c740db47dbc1b244c2afc8", "8b2de6c0ac314ddba29d49eb58c2a31d", "6e04979c2cf8f5bc7616b35da54f089c", "17c193f5ffa3e315c2a744f32b7b779c",
}
<commit_msg>auth: add benchmarks<commit_after>// Copyright (c) 2017 Andreas Auernhammer. All rights reserved.
// Use of this source code is governed by a license that can be
// found in the LICENSE file.

package auth

import (
	"bytes"
	"encoding/hex"
	"testing"
)

func fromHex(s string) []byte {
	b, err := hex.DecodeString(s)
	if err != nil {
		panic(err)
	}
	return b
}

func TestVectors(t *testing.T) {
	context := []byte("libtests")
	key := fromHex("000102030405060708090a0b0c0d0e0f")
	msg := make([]byte, 64)
	for i, v := range vectors {
		msg[i] = byte(i)

		tag := Sum(msg, context, key)
		if !bytes.Equal(tag[:], fromHex(v)) {
			t.Errorf("Failed at %d:\ngot:  %s\nwant: %s", i, hex.EncodeToString(tag[:]), v)
		}
	}
}

var vectors = []string{
	"f896e134f1a0c57e3caa11d37b48b5f3", "6df99f0e43e07c965c8b0f73d2ac9cd9", "ed001efc0e97d65b029bc997ef5f583b", "345e55d3a5b85574f38ee7b2662eb2eb",
	"6a6e245fda79d718f22e2cbe8d4556fd", "4850fc430a8055b96403324f4071b076", "99035dee17cdcddb9da4e5d9c5152ab2", "2477c9803dcbb6a86c4712374b205d9e",
	"916a038d182135002cdee0a61d2cb4b0", "62decae7c1e724dda73336e9956d2c4d", "c7c923bdbeb69074d918b7ed31b03dc2", "af95b43e7e939e1c5d55797a34d9343d",
	"cbb9fb310be777185e562b6b2b9a7548", "2baf051709deaebf4fcb387625ad8af4", "3a056cc5c9f18f31b00dc9d14766594c", "9bcfe38d12cfbfce83f4029458484961",
	"6e563359b4f674834aceeb80dd2eca04", "c8a4cd6594f79b3df6bf1426d5ffdb96", "751289b7ae385295309d62ae0ae7e9b2", "e56732e9505db8ab6823a2fcf6073f18",
	"ff793ba05b33ad2b40a28eed9bc5c9cc", "be07061fedca56082de9042a0ca18efe", "726d65f0eb9eb73999b316b3403e8551", "7b7f1cb11a1d589054f96ded6780b385",
	"c8614e59fb9d2f45d920b0e31ff70ba9", "97f7c865af57c4064532e5f3e47d0ee3", "fc6eed3abb33870978e01925931c2c77", "68517491cc1c0159039adef40e4a5884",
	"53f59cf2da263c41e11e4431f21ba975", "a042397d1177281ecfdeb94c7dada4b8", "2030770f95d4b08e6fe059158bfaaa80", "b8a4242bb9ecf78a30fbe1229a1cafca",
	"5e25dafd501eafde576bf1556bfa8c7b", "35310328ee7312987b1438f00cbd732b", "56379aa5f4ec19e52e1cbedb6cd54cf4", "b5d6db8d32c0614f87205cdeb43ec151",
	"303ae259d78a95b82a46cea9ca78d478", "d293b47452d4aab18cc01e80e63929bc", "808cceaa44a6d89eac19cca7f4f2a9a9", "a77c20c1fdc5db759e03f7394b10762e",
	"98c96bb66c170d184f394765decc87b8", "2308d737a6f27aeb18d76276223c4908", "91129370532baedb45aa01a72c517c77", "cd74314bb04228f71dd546e352ed19d6",
	"b2a422f69dab7b80f9c79f3601d27f5f", "658a50433acdea6f9c46888e2e4964cd", "ea2c33e0b9f1a241d4b90d2dc684e609", "068ea33c5d4fb4935ecc5bebd8a93d48",
	"d58e48c555dbadc09bff32223512398f", "07b69429bf3e7db8ac65a1099feeaa5f", "17a0607f65a4c6257d9f321a5bf7b4f2", "5f404445854ddab9c463f35fadc2cff8",
	"613bee96449b8c0cd52c2253a6635841", "c3fa9171de16beaf68ccffd49c1d10bb", "fa7fd667a792c36633a46556b19c324f", "dba0acbe3d5a0ad6b3e7a731820b153d",
	"91be4de60f5ba40ea02cbefd2072a1f9", "cd0b02ef791b0e206c38ae90109a561e", "80d0ca00aab2b1bdab63fc5237c908f1", "95f82495193d28373f5f661d6284a641",
	"1f622a4201c740db47dbc1b244c2afc8", "8b2de6c0ac314ddba29d49eb58c2a31d", "6e04979c2cf8f5bc7616b35da54f089c", "17c193f5ffa3e315c2a744f32b7b779c",
}

func benchWrite(size int, b *testing.B) {
	key := make([]byte, KeySize)
	context := []byte("runbench")
	msg := make([]byte, size)

	h := New(context, key)
	b.SetBytes(int64(size))
	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		h.Write(msg)
	}
}

func BenchmarkWrite8(b *testing.B)  { benchWrite(8, b) }
func BenchmarkWrite64(b *testing.B) { benchWrite(64, b) }
func BenchmarkWrite1K(b *testing.B) { benchWrite(1024, b) }

func benchSum(size int, b *testing.B) {
	key := make([]byte, KeySize)
	context := []byte("runbench")
	msg := make([]byte, size)

	b.SetBytes(int64(size))
	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		Sum(msg, context, key)
	}
}

func BenchmarkSum8(b *testing.B)  { benchSum(8, b) }
func BenchmarkSum64(b *testing.B) { benchSum(64, b) }
func BenchmarkSum1K(b *testing.B) { benchSum(1024, b) }
<|endoftext|>


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

import (
	"testing"
)

func TestConfiguration_LoadConfiguration_Success(t *testing.T) {
	servers, err := LoadConfiguration("../../../../conf/servers.json")

	if err != nil {
		t.Errorf("Loading the configuration file caused the error: %s", err.Error())
	}

	if len(servers) != 15 {
		t.Errorf("The configuration file should have %d servers but it only has %d", 15, len(servers))
	}
}

func TestConfiguration_LoadConfiguration_Failure(t *testing.T) {
	servers, err := LoadConfiguration("conf/servers-does-not-exist.json")

	if err == nil {
		t.Error("Loading the configuration of a non-existing directory should have caused an error")
	}

	if len(servers) != 0 {
		t.Error("There should be no servers while loading a configuration from a non-existing directory")
	}
}

func TestConfiguration_LoadConfiguration_BadJSON(t *testing.T) {
	servers, err := LoadConfiguration("../../../../conf/bad-servers.json")

	if err == nil {
		t.Error("Loading the configuration of a non-existing directory should have caused an error")
	}

	if len(servers) != 0 {
		t.Error("There should be no servers while loading a configuration from a non-existing directory")
	}
}
<commit_msg>Finally, it's building!!!!<commit_after>/*
 * The MIT License (MIT)
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
package application

import (
	"testing"
)

func TestConfiguration_LoadConfiguration_Success(t *testing.T) {
	servers, err := LoadConfiguration("../conf/servers.json")

	if err != nil {
		t.Errorf("Loading the configuration file caused the error: %s", err.Error())
	}

	if len(servers) != 15 {
		t.Errorf("The configuration file should have %d servers but it only has %d", 15, len(servers))
	}
}

func TestConfiguration_LoadConfiguration_Failure(t *testing.T) {
	servers, err := LoadConfiguration("conf/servers-does-not-exist.json")

	if err == nil {
		t.Error("Loading the configuration of a non-existing directory should have caused an error")
	}

	if len(servers) != 0 {
		t.Error("There should be no servers while loading a configuration from a non-existing directory")
	}
}

func TestConfiguration_LoadConfiguration_BadJSON(t *testing.T) {
	servers, err := LoadConfiguration("../../../../conf/bad-servers.json")

	if err == nil {
		t.Error("Loading the configuration of a non-existing directory should have caused an error")
	}

	if len(servers) != 0 {
		t.Error("There should be no servers while loading a configuration from a non-existing directory")
	}
}
<|endoftext|>


<commit_before>package state

import "fmt"

// Environment represents the state of an environment.
type Environment struct {
	st *State
	annotator
}

// GetEnv returns the environment entity.
func (st *State) GetEnvironment() *Environment {
	env := &Environment{
		st:        st,
		annotator: annotator{st: st},
	}
	env.annotator.entityName = env.EntityName()
	return env
}

// EntityName returns a name identifying the environment.
// The returned name will be different from other EntityName values returned
// by any other entities from the same state.
func (e Environment) EntityName() string {
	return "environment"
}

// SetPassword currently just returns an error. Implemented here so that
// an environment can be used as an Entity.
func (e Environment) SetPassword(pass string) error {
	return fmt.Errorf("cannot set password of environment")
}

// PasswordValid currently just returns false. Implemented here so that
// an environment can be used as an Entity.
func (e Environment) PasswordValid(pass string) bool {
	return false
}

// Refresh currently just returns an error. Implemented here so that
// an environment can be used as an Entity.
func (e Environment) Refresh() error {
	return fmt.Errorf("cannot refresh the environment")
}
<commit_msg>Checkpoint.<commit_after>package state

import "fmt"

// Environment represents the state of an environment.
type Environment struct {
	st *State
	annotator
}

// GetEnvironment returns the environment entity.
func (st *State) GetEnvironment() *Environment {
	env := &Environment{
		st:        st,
		annotator: annotator{st: st},
	}
	env.annotator.entityName = env.EntityName()
	return env
}

// EntityName returns a name identifying the environment.
// The returned name will be different from other EntityName values returned
// by any other entities from the same state.
func (e Environment) EntityName() string {
	return "environment"
}

// SetPassword currently just returns an error. Implemented here so that
// an environment can be used as an Entity.
func (e Environment) SetPassword(pass string) error {
	return fmt.Errorf("cannot set password of environment")
}

// PasswordValid currently just returns false. Implemented here so that
// an environment can be used as an Entity.
func (e Environment) PasswordValid(pass string) bool {
	return false
}

// Refresh currently just returns an error. Implemented here so that
// an environment can be used as an Entity.
func (e Environment) Refresh() error {
	return fmt.Errorf("cannot refresh the environment")
}
<|endoftext|>


<commit_before>// launchpad.net/juju/state
//
// Copyright (c) 2011-2012 Canonical Ltd.

package state

import (
	"fmt"
	"launchpad.net/juju/go/state/presence"
	"path"
	"strconv"
	"strings"
	"time"
)

const providerMachineId = "provider-machine-id"

// Machine represents the state of a machine.
type Machine struct {
	st  *State
	key string
}

// Id returns the machine id.
func (m *Machine) Id() int {
	return machineId(m.key)
}

// AgentAlive returns whether the respective remote agent is alive.
func (m *Machine) AgentAlive() (bool, error) {
	return presence.Alive(m.st.zk, m.zkAgentPath())
}

// WaitAgentAlive blocks until the respective agent is alive.
func (m *Machine) WaitAgentAlive(timeout time.Duration) error {
	err := presence.WaitAlive(m.st.zk, m.zkAgentPath(), timeout)
	if err != nil {
		return fmt.Errorf("state: waiting for agent of machine %d: %v", m.Id(), err)
	}
	return nil
}

// SetAgentAlive signals that the agent for machine m is alive
// by starting a pinger on its presence node. It returns the
// started pinger.
func (m *Machine) SetAgentAlive() (*presence.Pinger, error) {
	return presence.StartPinger(m.st.zk, m.zkAgentPath(), agentPingerPeriod)
}

// InstanceId returns the provider-specific machine id for this machine.
func (m *Machine) InstanceId() (string, error) {
	config, err := readConfigNode(m.st.zk, m.zkPath())
	if err != nil {
		return "", err
	}
	v, ok := config.Get(providerMachineId)
	if !ok {
		// missing key is fine
		return "", nil
	}
	if id, ok := v.(string); ok {
		return id, nil
	}
	return "", fmt.Errorf("invalid contents, expecting string, got %T", v)
}

// SetInstanceId sets the provider-specific machine id for this machine.
func (m *Machine) SetInstanceId(id string) error {
	config, err := readConfigNode(m.st.zk, m.zkPath())
	if err != nil {
		return err
	}
	config.Set(providerMachineId, id)
	_, err = config.Write()
	return err
}

// zkKey returns the ZooKeeper key of the machine.
func (m *Machine) zkKey() string {
	return m.key
}

// zkPath returns the ZooKeeper base path for the machine.
func (m *Machine) zkPath() string {
	return path.Join(zkMachinesPath, m.zkKey())
}

// zkAgentPath returns the ZooKeeper path for the machine agent.
func (m *Machine) zkAgentPath() string {
	return path.Join(m.zkPath(), "agent")
}

// machineId returns the machine id corresponding to machineKey.
func machineId(machineKey string) (id int) {
	if machineKey == "" {
		panic("machineId: empty machine key")
	}
	i := strings.Index(machineKey, "-")
	var id64 int64
	var err error
	if i >= 0 {
		id64, err = strconv.ParseInt(machineKey[i+1:], 10, 32)
	}
	if i < 0 || err != nil {
		panic("machineId: invalid machine key: " + machineKey)
	}
	return int(id64)
}

// machineKey returns the machine key corresponding to machineId.
func machineKey(machineId int) string {
	return fmt.Sprintf("machine-%010d", machineId)
}

// MachinesChange contains information about
// machines that have been added or deleted.
type MachinesChange struct {
	Added, Deleted []*Machine
}
<commit_msg>fixed comment<commit_after>// launchpad.net/juju/state
//
// Copyright (c) 2011-2012 Canonical Ltd.

package state

import (
	"fmt"
	"launchpad.net/juju/go/state/presence"
	"path"
	"strconv"
	"strings"
	"time"
)

const providerMachineId = "provider-machine-id"

// Machine represents the state of a machine.
type Machine struct {
	st  *State
	key string
}

// Id returns the machine id.
func (m *Machine) Id() int {
	return machineId(m.key)
}

// AgentAlive returns whether the respective remote agent is alive.
func (m *Machine) AgentAlive() (bool, error) {
	return presence.Alive(m.st.zk, m.zkAgentPath())
}

// WaitAgentAlive blocks until the respective agent is alive.
func (m *Machine) WaitAgentAlive(timeout time.Duration) error {
	err := presence.WaitAlive(m.st.zk, m.zkAgentPath(), timeout)
	if err != nil {
		return fmt.Errorf("state: waiting for agent of machine %d: %v", m.Id(), err)
	}
	return nil
}

// SetAgentAlive signals that the agent for machine m is alive
// by starting a pinger on its presence node. It returns the
// started pinger.
func (m *Machine) SetAgentAlive() (*presence.Pinger, error) {
	return presence.StartPinger(m.st.zk, m.zkAgentPath(), agentPingerPeriod)
}

// InstanceId returns the provider specific machine id for this machine.
func (m *Machine) InstanceId() (string, error) {
	config, err := readConfigNode(m.st.zk, m.zkPath())
	if err != nil {
		return "", err
	}
	v, ok := config.Get(providerMachineId)
	if !ok {
		// missing key is fine
		return "", nil
	}
	if id, ok := v.(string); ok {
		return id, nil
	}
	return "", fmt.Errorf("invalid contents, expecting string, got %T", v)
}

// SetInstanceId sets the provider specific machine id for this machine.
func (m *Machine) SetInstanceId(id string) error {
	config, err := readConfigNode(m.st.zk, m.zkPath())
	if err != nil {
		return err
	}
	config.Set(providerMachineId, id)
	_, err = config.Write()
	return err
}

// zkKey returns the ZooKeeper key of the machine.
func (m *Machine) zkKey() string {
	return m.key
}

// zkPath returns the ZooKeeper base path for the machine.
func (m *Machine) zkPath() string {
	return path.Join(zkMachinesPath, m.zkKey())
}

// zkAgentPath returns the ZooKeeper path for the machine agent.
func (m *Machine) zkAgentPath() string {
	return path.Join(m.zkPath(), "agent")
}

// machineId returns the machine id corresponding to machineKey.
func machineId(machineKey string) (id int) {
	if machineKey == "" {
		panic("machineId: empty machine key")
	}
	i := strings.Index(machineKey, "-")
	var id64 int64
	var err error
	if i >= 0 {
		id64, err = strconv.ParseInt(machineKey[i+1:], 10, 32)
	}
	if i < 0 || err != nil {
		panic("machineId: invalid machine key: " + machineKey)
	}
	return int(id64)
}

// machineKey returns the machine key corresponding to machineId.
func machineKey(machineId int) string {
	return fmt.Sprintf("machine-%010d", machineId)
}

// MachinesChange contains information about
// machines that have been added or deleted.
type MachinesChange struct {
	Added, Deleted []*Machine
}
<|endoftext|>


<commit_before>package states

import (
	"github.com/zclconf/go-cty/cty"

	"github.com/hashicorp/terraform/addrs"
)

// Module is a container for the states of objects within a particular module.
type Module struct {
	Addr addrs.ModuleInstance

	// Resources contains the state for each resource. The keys in this map are
	// an implementation detail and must not be used by outside callers.
	Resources map[string]*Resource

	// OutputValues contains the state for each output value. The keys in this
	// map are output value names.
	OutputValues map[string]*OutputValue

	// LocalValues contains the value for each named output value. The keys
	// in this map are local value names.
	LocalValues map[string]cty.Value
}

// NewModule constructs an empty module state for the given module address.
func NewModule(addr addrs.ModuleInstance) *Module {
	return &Module{
		Addr:         addr,
		Resources:    map[string]*Resource{},
		OutputValues: map[string]*OutputValue{},
		LocalValues:  map[string]cty.Value{},
	}
}

// Resource returns the state for the resource with the given address within
// the receiving module state, or nil if the requested resource is not tracked
// in the state.
func (ms *Module) Resource(addr addrs.Resource) *Resource {
	return ms.Resources[addr.String()]
}

// ResourceInstance returns the state for the resource instance with the given
// address within the receiving module state, or nil if the requested instance
// is not tracked in the state.
func (ms *Module) ResourceInstance(addr addrs.ResourceInstance) *ResourceInstance {
	rs := ms.Resource(addr.Resource)
	if rs == nil {
		return nil
	}
	return rs.Instance(addr.Key)
}

// SetResourceMeta updates the resource-level metadata for the resource
// with the given address, creating the resource state for it if it doesn't
// already exist.
func (ms *Module) SetResourceMeta(addr addrs.Resource, eachMode EachMode, provider addrs.AbsProviderConfig) {
	rs := ms.Resource(addr)
	if rs == nil {
		rs = &Resource{
			Addr:      addr,
			Instances: map[addrs.InstanceKey]*ResourceInstance{},
		}
		ms.Resources[addr.String()] = rs
	}

	rs.EachMode = eachMode
	rs.ProviderConfig = provider
}

// RemoveResource removes the entire state for the given resource, taking with
// it any instances associated with the resource. This should generally be
// called only for resource objects whose instances have all been destroyed.
func (ms *Module) RemoveResource(addr addrs.Resource) {
	delete(ms.Resources, addr.String())
}

// SetResourceInstanceCurrent saves the given instance object as the current
// generation of the resource instance with the given address, simulataneously
// updating the recorded provider configuration address, dependencies, and
// resource EachMode.
//
// Any existing current instance object for the given resource is overwritten.
// Set obj to nil to remove the primary generation object altogether. If there
// are no deposed objects then the instance will be removed altogether.
//
// The provider address and "each mode" are resource-wide settings and so they
// are updated for all other instances of the same resource as a side-effect of
// this call.
func (ms *Module) SetResourceInstanceCurrent(addr addrs.ResourceInstance, obj *ResourceInstanceObjectSrc, provider addrs.AbsProviderConfig) {
	rs := ms.Resource(addr.Resource)
	// if the resource is nil and the object is nil, don't do anything!
	// you'll probably just cause issues
	if obj == nil && rs == nil {
		return
	}
	if obj == nil && rs != nil {
		// does the resource have any other objects?
		// if not then delete the whole resource
		if len(rs.Instances) == 0 {
			delete(ms.Resources, addr.Resource.String())
			return
		}
		// check for an existing resource, now that we've ensured that rs.Instances is more than 0/not nil
		is := rs.Instance(addr.Key)
		if is == nil {
			// if there is no instance, but the resource exists and has other instances,
			// be chill, just return
			return
		}
		// if we have an instance, update the current
		is.Current = obj
		if !is.HasObjects() {
			// If we have no objects at all then we'll clean up.
			delete(rs.Instances, addr.Key)
			if len(rs.Instances) == 0 {
				delete(ms.Resources, addr.Resource.String())
				return
			}
		}
		// Nothing more to do here, so return!
		return
	}
	if rs == nil && obj != nil {
		// We don't have have a resource so make one, which is a side effect of setResourceMeta
		ms.SetResourceMeta(addr.Resource, eachModeForInstanceKey(addr.Key), provider)
		// now we have a resource! so update the rs value to point to it
		rs = ms.Resource(addr.Resource)
	}
	// Get our instance from the resource; it could be there or not at this point
	is := rs.Instance(addr.Key)
	if is == nil {
		// if we don't have a resource, create one and add to the instances
		is = rs.CreateInstance(addr.Key)
		// update the resource meta because we have a new instance, so EachMode may have changed
		ms.SetResourceMeta(addr.Resource, eachModeForInstanceKey(addr.Key), provider)
	}
	// Call setResourceMeta one last time, with the resource's current EachMode, lest the
	// provider has updated
	ms.SetResourceMeta(addr.Resource, rs.EachMode, provider)
	is.Current = obj
}

// SetResourceInstanceDeposed saves the given instance object as a deposed
// generation of the resource instance with the given address and deposed key.
//
// Call this method only for pre-existing deposed objects that already have
// a known DeposedKey. For example, this method is useful if reloading objects
// that were persisted to a state file. To mark the current object as deposed,
// use DeposeResourceInstanceObject instead.
//
// The resource that contains the given instance must already exist in the
// state, or this method will panic. Use Resource to check first if its
// presence is not already guaranteed.
//
// Any existing current instance object for the given resource and deposed key
// is overwritten. Set obj to nil to remove the deposed object altogether. If
// the instance is left with no objects after this operation then it will
// be removed from its containing resource altogether.
func (ms *Module) SetResourceInstanceDeposed(addr addrs.ResourceInstance, key DeposedKey, obj *ResourceInstanceObjectSrc, provider addrs.AbsProviderConfig) {
	ms.SetResourceMeta(addr.Resource, eachModeForInstanceKey(addr.Key), provider)

	rs := ms.Resource(addr.Resource)
	is := rs.EnsureInstance(addr.Key)
	if obj != nil {
		is.Deposed[key] = obj
	} else {
		delete(is.Deposed, key)
	}

	if !is.HasObjects() {
		// If we have no objects at all then we'll clean up.
		delete(rs.Instances, addr.Key)
	}
	if rs.EachMode == NoEach && len(rs.Instances) == 0 {
		// Also clean up if we only expect to have one instance anyway
		// and there are none. We leave the resource behind if an each mode
		// is active because an empty list or map of instances is a valid state.
		delete(ms.Resources, addr.Resource.String())
	}
}

// ForgetResourceInstanceAll removes the record of all objects associated with
// the specified resource instance, if present. If not present, this is a no-op.
func (ms *Module) ForgetResourceInstanceAll(addr addrs.ResourceInstance) {
	rs := ms.Resource(addr.Resource)
	if rs == nil {
		return
	}
	delete(rs.Instances, addr.Key)

	if rs.EachMode == NoEach && len(rs.Instances) == 0 {
		// Also clean up if we only expect to have one instance anyway
		// and there are none. We leave the resource behind if an each mode
		// is active because an empty list or map of instances is a valid state.
		delete(ms.Resources, addr.Resource.String())
	}
}

// ForgetResourceInstanceDeposed removes the record of the deposed object with
// the given address and key, if present. If not present, this is a no-op.
func (ms *Module) ForgetResourceInstanceDeposed(addr addrs.ResourceInstance, key DeposedKey) {
	rs := ms.Resource(addr.Resource)
	if rs == nil {
		return
	}
	is := rs.Instance(addr.Key)
	if is == nil {
		return
	}
	delete(is.Deposed, key)

	if !is.HasObjects() {
		// If we have no objects at all then we'll clean up.
		delete(rs.Instances, addr.Key)
	}
	if rs.EachMode == NoEach && len(rs.Instances) == 0 {
		// Also clean up if we only expect to have one instance anyway
		// and there are none. We leave the resource behind if an each mode
		// is active because an empty list or map of instances is a valid state.
		delete(ms.Resources, addr.Resource.String())
	}
}

// deposeResourceInstanceObject is the real implementation of
// SyncState.DeposeResourceInstanceObject.
func (ms *Module) deposeResourceInstanceObject(addr addrs.ResourceInstance, forceKey DeposedKey) DeposedKey {
	is := ms.ResourceInstance(addr)
	if is == nil {
		return NotDeposed
	}
	return is.deposeCurrentObject(forceKey)
}

// maybeRestoreResourceInstanceDeposed is the real implementation of
// SyncState.MaybeRestoreResourceInstanceDeposed.
func (ms *Module) maybeRestoreResourceInstanceDeposed(addr addrs.ResourceInstance, key DeposedKey) bool {
	rs := ms.Resource(addr.Resource)
	if rs == nil {
		return false
	}
	is := rs.Instance(addr.Key)
	if is == nil {
		return false
	}
	if is.Current != nil {
		return false
	}
	if len(is.Deposed) == 0 {
		return false
	}
	is.Current = is.Deposed[key]
	delete(is.Deposed, key)
	return true
}

// SetOutputValue writes an output value into the state, overwriting any
// existing value of the same name.
func (ms *Module) SetOutputValue(name string, value cty.Value, sensitive bool) *OutputValue {
	os := &OutputValue{
		Value:     value,
		Sensitive: sensitive,
	}
	ms.OutputValues[name] = os
	return os
}

// RemoveOutputValue removes the output value of the given name from the state,
// if it exists. This method is a no-op if there is no value of the given
// name.
func (ms *Module) RemoveOutputValue(name string) {
	delete(ms.OutputValues, name)
}

// SetLocalValue writes a local value into the state, overwriting any
// existing value of the same name.
func (ms *Module) SetLocalValue(name string, value cty.Value) {
	ms.LocalValues[name] = value
}

// RemoveLocalValue removes the local value of the given name from the state,
// if it exists. This method is a no-op if there is no value of the given
// name.
func (ms *Module) RemoveLocalValue(name string) {
	delete(ms.LocalValues, name)
}

// PruneResourceHusks is a specialized method that will remove any Resource
// objects that do not contain any instances, even if they have an EachMode.
//
// You probably shouldn't call this! See the method of the same name on
// type State for more information on what this is for and the rare situations
// where it is safe to use.
func (ms *Module) PruneResourceHusks() {
	for _, rs := range ms.Resources {
		if len(rs.Instances) == 0 {
			ms.RemoveResource(rs.Addr)
		}
	}
}

// empty returns true if the receving module state is contributing nothing
// to the state. In other words, it returns true if the module could be
// removed from the state altogether without changing the meaning of the state.
//
// In practice a module containing no objects is the same as a non-existent
// module, and so we can opportunistically clean up once a module becomes
// empty on the assumption that it will be re-added if needed later.
func (ms *Module) empty() bool {
	if ms == nil {
		return true
	}

	// This must be updated to cover any new collections added to Module
	// in future.
	return (len(ms.Resources) == 0 &&
		len(ms.OutputValues) == 0 &&
		len(ms.LocalValues) == 0)
}
<commit_msg>Only need this one call, don't call the meta func<commit_after>package states

import (
	"github.com/zclconf/go-cty/cty"

	"github.com/hashicorp/terraform/addrs"
)

// Module is a container for the states of objects within a particular module.
type Module struct {
	Addr addrs.ModuleInstance

	// Resources contains the state for each resource. The keys in this map are
	// an implementation detail and must not be used by outside callers.
	Resources map[string]*Resource

	// OutputValues contains the state for each output value. The keys in this
	// map are output value names.
	OutputValues map[string]*OutputValue

	// LocalValues contains the value for each named output value. The keys
	// in this map are local value names.
	LocalValues map[string]cty.Value
}

// NewModule constructs an empty module state for the given module address.
func NewModule(addr addrs.ModuleInstance) *Module {
	return &Module{
		Addr:         addr,
		Resources:    map[string]*Resource{},
		OutputValues: map[string]*OutputValue{},
		LocalValues:  map[string]cty.Value{},
	}
}

// Resource returns the state for the resource with the given address within
// the receiving module state, or nil if the requested resource is not tracked
// in the state.
func (ms *Module) Resource(addr addrs.Resource) *Resource {
	return ms.Resources[addr.String()]
}

// ResourceInstance returns the state for the resource instance with the given
// address within the receiving module state, or nil if the requested instance
// is not tracked in the state.
func (ms *Module) ResourceInstance(addr addrs.ResourceInstance) *ResourceInstance {
	rs := ms.Resource(addr.Resource)
	if rs == nil {
		return nil
	}
	return rs.Instance(addr.Key)
}

// SetResourceMeta updates the resource-level metadata for the resource
// with the given address, creating the resource state for it if it doesn't
// already exist.
func (ms *Module) SetResourceMeta(addr addrs.Resource, eachMode EachMode, provider addrs.AbsProviderConfig) {
	rs := ms.Resource(addr)
	if rs == nil {
		rs = &Resource{
			Addr:      addr,
			Instances: map[addrs.InstanceKey]*ResourceInstance{},
		}
		ms.Resources[addr.String()] = rs
	}

	rs.EachMode = eachMode
	rs.ProviderConfig = provider
}

// RemoveResource removes the entire state for the given resource, taking with
// it any instances associated with the resource. This should generally be
// called only for resource objects whose instances have all been destroyed.
func (ms *Module) RemoveResource(addr addrs.Resource) {
	delete(ms.Resources, addr.String())
}

// SetResourceInstanceCurrent saves the given instance object as the current
// generation of the resource instance with the given address, simulataneously
// updating the recorded provider configuration address, dependencies, and
// resource EachMode.
//
// Any existing current instance object for the given resource is overwritten.
// Set obj to nil to remove the primary generation object altogether. If there
// are no deposed objects then the instance will be removed altogether.
//
// The provider address and "each mode" are resource-wide settings and so they
// are updated for all other instances of the same resource as a side-effect of
// this call.
func (ms *Module) SetResourceInstanceCurrent(addr addrs.ResourceInstance, obj *ResourceInstanceObjectSrc, provider addrs.AbsProviderConfig) {
	rs := ms.Resource(addr.Resource)
	// if the resource is nil and the object is nil, don't do anything!
	// you'll probably just cause issues
	if obj == nil && rs == nil {
		return
	}
	if obj == nil && rs != nil {
		// does the resource have any other objects?
		// if not then delete the whole resource
		if len(rs.Instances) == 0 {
			delete(ms.Resources, addr.Resource.String())
			return
		}
		// check for an existing resource, now that we've ensured that rs.Instances is more than 0/not nil
		is := rs.Instance(addr.Key)
		if is == nil {
			// if there is no instance, but the resource exists and has other instances,
			// be chill, just return
			return
		}
		// if we have an instance, update the current
		is.Current = obj
		if !is.HasObjects() {
			// If we have no objects at all then we'll clean up.
			delete(rs.Instances, addr.Key)
			if len(rs.Instances) == 0 {
				delete(ms.Resources, addr.Resource.String())
				return
			}
		}
		// Nothing more to do here, so return!
		return
	}
	if rs == nil && obj != nil {
		// We don't have have a resource so make one, which is a side effect of setResourceMeta
		ms.SetResourceMeta(addr.Resource, eachModeForInstanceKey(addr.Key), provider)
		// now we have a resource! so update the rs value to point to it
		rs = ms.Resource(addr.Resource)
	}
	// Get our instance from the resource; it could be there or not at this point
	is := rs.Instance(addr.Key)
	if is == nil {
		// if we don't have a resource, create one and add to the instances
		is = rs.CreateInstance(addr.Key)
		// update the resource meta because we have a new instance, so EachMode may have changed
		ms.SetResourceMeta(addr.Resource, eachModeForInstanceKey(addr.Key), provider)
	}
	// Update the resource's ProviderConfig, in case the provider has updated
	rs.ProviderConfig = provider
	is.Current = obj
}

// SetResourceInstanceDeposed saves the given instance object as a deposed
// generation of the resource instance with the given address and deposed key.
//
// Call this method only for pre-existing deposed objects that already have
// a known DeposedKey. For example, this method is useful if reloading objects
// that were persisted to a state file. To mark the current object as deposed,
// use DeposeResourceInstanceObject instead.
//
// The resource that contains the given instance must already exist in the
// state, or this method will panic. Use Resource to check first if its
// presence is not already guaranteed.
//
// Any existing current instance object for the given resource and deposed key
// is overwritten. Set obj to nil to remove the deposed object altogether. If
// the instance is left with no objects after this operation then it will
// be removed from its containing resource altogether.
func (ms *Module) SetResourceInstanceDeposed(addr addrs.ResourceInstance, key DeposedKey, obj *ResourceInstanceObjectSrc, provider addrs.AbsProviderConfig) {
	ms.SetResourceMeta(addr.Resource, eachModeForInstanceKey(addr.Key), provider)

	rs := ms.Resource(addr.Resource)
	is := rs.EnsureInstance(addr.Key)
	if obj != nil {
		is.Deposed[key] = obj
	} else {
		delete(is.Deposed, key)
	}

	if !is.HasObjects() {
		// If we have no objects at all then we'll clean up.
		delete(rs.Instances, addr.Key)
	}
	if rs.EachMode == NoEach && len(rs.Instances) == 0 {
		// Also clean up if we only expect to have one instance anyway
		// and there are none. We leave the resource behind if an each mode
		// is active because an empty list or map of instances is a valid state.
		delete(ms.Resources, addr.Resource.String())
	}
}

// ForgetResourceInstanceAll removes the record of all objects associated with
// the specified resource instance, if present. If not present, this is a no-op.
func (ms *Module) ForgetResourceInstanceAll(addr addrs.ResourceInstance) {
	rs := ms.Resource(addr.Resource)
	if rs == nil {
		return
	}
	delete(rs.Instances, addr.Key)

	if rs.EachMode == NoEach && len(rs.Instances) == 0 {
		// Also clean up if we only expect to have one instance anyway
		// and there are none. We leave the resource behind if an each mode
		// is active because an empty list or map of instances is a valid state.
		delete(ms.Resources, addr.Resource.String())
	}
}

// ForgetResourceInstanceDeposed removes the record of the deposed object with
// the given address and key, if present. If not present, this is a no-op.
func (ms *Module) ForgetResourceInstanceDeposed(addr addrs.ResourceInstance, key DeposedKey) {
	rs := ms.Resource(addr.Resource)
	if rs == nil {
		return
	}
	is := rs.Instance(addr.Key)
	if is == nil {
		return
	}
	delete(is.Deposed, key)

	if !is.HasObjects() {
		// If we have no objects at all then we'll clean up.
		delete(rs.Instances, addr.Key)
	}
	if rs.EachMode == NoEach && len(rs.Instances) == 0 {
		// Also clean up if we only expect to have one instance anyway
		// and there are none. We leave the resource behind if an each mode
		// is active because an empty list or map of instances is a valid state.
		delete(ms.Resources, addr.Resource.String())
	}
}

// deposeResourceInstanceObject is the real implementation of
// SyncState.DeposeResourceInstanceObject.
func (ms *Module) deposeResourceInstanceObject(addr addrs.ResourceInstance, forceKey DeposedKey) DeposedKey {
	is := ms.ResourceInstance(addr)
	if is == nil {
		return NotDeposed
	}
	return is.deposeCurrentObject(forceKey)
}

// maybeRestoreResourceInstanceDeposed is the real implementation of
// SyncState.MaybeRestoreResourceInstanceDeposed.
func (ms *Module) maybeRestoreResourceInstanceDeposed(addr addrs.ResourceInstance, key DeposedKey) bool {
	rs := ms.Resource(addr.Resource)
	if rs == nil {
		return false
	}
	is := rs.Instance(addr.Key)
	if is == nil {
		return false
	}
	if is.Current != nil {
		return false
	}
	if len(is.Deposed) == 0 {
		return false
	}
	is.Current = is.Deposed[key]
	delete(is.Deposed, key)
	return true
}

// SetOutputValue writes an output value into the state, overwriting any
// existing value of the same name.
func (ms *Module) SetOutputValue(name string, value cty.Value, sensitive bool) *OutputValue {
	os := &OutputValue{
		Value:     value,
		Sensitive: sensitive,
	}
	ms.OutputValues[name] = os
	return os
}

// RemoveOutputValue removes the output value of the given name from the state,
// if it exists. This method is a no-op if there is no value of the given
// name.
func (ms *Module) RemoveOutputValue(name string) {
	delete(ms.OutputValues, name)
}

// SetLocalValue writes a local value into the state, overwriting any
// existing value of the same name.
func (ms *Module) SetLocalValue(name string, value cty.Value) {
	ms.LocalValues[name] = value
}

// RemoveLocalValue removes the local value of the given name from the state,
// if it exists. This method is a no-op if there is no value of the given
// name.
func (ms *Module) RemoveLocalValue(name string) {
	delete(ms.LocalValues, name)
}

// PruneResourceHusks is a specialized method that will remove any Resource
// objects that do not contain any instances, even if they have an EachMode.
//
// You probably shouldn't call this! See the method of the same name on
// type State for more information on what this is for and the rare situations
// where it is safe to use.
func (ms *Module) PruneResourceHusks() {
	for _, rs := range ms.Resources {
		if len(rs.Instances) == 0 {
			ms.RemoveResource(rs.Addr)
		}
	}
}

// empty returns true if the receving module state is contributing nothing
// to the state. In other words, it returns true if the module could be
// removed from the state altogether without changing the meaning of the state.
//
// In practice a module containing no objects is the same as a non-existent
// module, and so we can opportunistically clean up once a module becomes
// empty on the assumption that it will be re-added if needed later.
func (ms *Module) empty() bool {
	if ms == nil {
		return true
	}

	// This must be updated to cover any new collections added to Module
	// in future.
	return (len(ms.Resources) == 0 &&
		len(ms.OutputValues) == 0 &&
		len(ms.LocalValues) == 0)
}
<|endoftext|>