<commit_before>package main

import (
	"time"

	sdk "github.com/dysolution/espsdk"
	"github.com/icrowley/fake"
)

var bullets = make(map[string]Bullet)
var bombs = make(map[string]Bomb)

func bullet(name string, method string, url string, payload sdk.RESTObject) {
	bullets[name] = Bullet{&client, name, method, url, payload}
}

func makeBomb(name string, bullets ...Bullet) {
	var bs []Bullet
	for _, bullet := range bullets {
		bs = append(bs, bullet)
	}
	bombs[name] = Bomb{
		Bullets: bs,
	}
}

func defineBullets() {
	bullet("get_batches", "GET", sdk.Batches, nil)

	bullet("create_batch", "POST", sdk.Batches, sdk.Batch{
		SubmissionName: appID + ": " + fake.FullName(),
		SubmissionType: "getty_creative_video",
	})

	badBatch := sdk.Batch{ID: -1}
	bullet("get_invalid_batch", "GET", badBatch.Path(), badBatch)

	edPhoto := sdk.Contribution{
		SubmissionBatchID:    86102,
		CameraShotDate:       time.Now().Format("01/02/2006"),
		ContentProviderName:  "provider",
		ContentProviderTitle: "Contributor",
		CountryOfShoot:       fake.Country(),
		CreditLine:           fake.FullName(),
		FileName:             fake.Word() + ".jpg",
		Headline:             fake.Sentence(),
		IptcCategory:         "S",
		SiteDestination:      []string{"Editorial", "WireImage.com"},
		Source:               "AFP",
	}
	bullet("create_photo", "POST", edPhoto.Path(), edPhoto)

	edBatch := sdk.Batch{ID: 86103}
	bullet("get_photos", "GET", edBatch.Path(), edBatch)

	release := sdk.Release{
		SubmissionBatchID: 86103,
		FileName:          "some_property.jpg",
		ReleaseType:       "Property",
		FilePath:          "submission/releases/batch_86103/24780225369200015_some_property.jpg",
		MimeType:          "image/jpeg",
	}
	bullet("create_release", "POST", release.Path(), release)
}

// ExampleConfig returns an example of a complete configuration for the app.
// When marshaled into JSON, this can be used as the contents of the config
// file.
func ExampleConfig() Raid {
	defineBullets()

	makeBomb("create_and_confirm_batch",
		bullets["get_batches"],
		bullets["create_batch"],
		bullets["get_batches"],
	)
	makeBomb("get_invalid_batches",
		bullets["get_invalid_batch"],
	)
	makeBomb("create_and_confirm_photo",
		bullets["create_photo"],
		bullets["get_photos"],
	)
	makeBomb("upload_a_release",
		bullets["create_release"],
	)

	return NewRaid(
		bombs["create_and_confirm_batch"],
		bombs["get_invalid_batches"],
		bombs["create_and_confirm_photo"],
		bombs["upload_a_release"],
	)
}
<commit_msg>properly capitalize IPTC<commit_after>package main

import (
	"time"

	sdk "github.com/dysolution/espsdk"
	"github.com/icrowley/fake"
)

var bullets = make(map[string]Bullet)
var bombs = make(map[string]Bomb)

func bullet(name string, method string, url string, payload sdk.RESTObject) {
	bullets[name] = Bullet{&client, name, method, url, payload}
}

func makeBomb(name string, bullets ...Bullet) {
	var bs []Bullet
	for _, bullet := range bullets {
		bs = append(bs, bullet)
	}
	bombs[name] = Bomb{
		Bullets: bs,
	}
}

func defineBullets() {
	bullet("get_batches", "GET", sdk.Batches, nil)

	bullet("create_batch", "POST", sdk.Batches, sdk.Batch{
		SubmissionName: appID + ": " + fake.FullName(),
		SubmissionType: "getty_creative_video",
	})

	badBatch := sdk.Batch{ID: -1}
	bullet("get_invalid_batch", "GET", badBatch.Path(), badBatch)

	edPhoto := sdk.Contribution{
		SubmissionBatchID:    86102,
		CameraShotDate:       time.Now().Format("01/02/2006"),
		ContentProviderName:  "provider",
		ContentProviderTitle: "Contributor",
		CountryOfShoot:       fake.Country(),
		CreditLine:           fake.FullName(),
		FileName:             fake.Word() + ".jpg",
		Headline:             fake.Sentence(),
		IPTCCategory:         "S",
		SiteDestination:      []string{"Editorial", "WireImage.com"},
		Source:               "AFP",
	}
	bullet("create_photo", "POST", edPhoto.Path(), edPhoto)

	edBatch := sdk.Batch{ID: 86103}
	bullet("get_photos", "GET", edBatch.Path(), edBatch)

	release := sdk.Release{
		SubmissionBatchID: 86103,
		FileName:          "some_property.jpg",
		ReleaseType:       "Property",
		FilePath:          "submission/releases/batch_86103/24780225369200015_some_property.jpg",
		MimeType:          "image/jpeg",
	}
	bullet("create_release", "POST", release.Path(), release)
}

// ExampleConfig returns an example of a complete configuration for the app.
// When marshaled into JSON, this can be used as the contents of the config
// file.
func ExampleConfig() Raid {
	defineBullets()

	makeBomb("create_and_confirm_batch",
		bullets["get_batches"],
		bullets["create_batch"],
		bullets["get_batches"],
	)
	makeBomb("get_invalid_batches",
		bullets["get_invalid_batch"],
	)
	makeBomb("create_and_confirm_photo",
		bullets["create_photo"],
		bullets["get_photos"],
	)
	makeBomb("upload_a_release",
		bullets["create_release"],
	)

	return NewRaid(
		bombs["create_and_confirm_batch"],
		bombs["get_invalid_batches"],
		bombs["create_and_confirm_photo"],
		bombs["upload_a_release"],
	)
}
<|endoftext|>


<commit_before>// Copyright 2016 Google Inc. All rights reserved.
// Use of this source code is governed by the Apache 2.0
// license that can be found in the LICENSE file.

// Command subscriptions is a tool to manage Google Cloud Pub/Sub subscriptions by using the Pub/Sub API.
// See more about Google Cloud Pub/Sub at https://cloud.google.com/pubsub/docs/overview.
package main

import (
	"fmt"
	"log"
	"os"
	"sync"
	"time"

	"golang.org/x/net/context"

	"cloud.google.com/go/iam"
	"cloud.google.com/go/pubsub"
	"google.golang.org/api/iterator"
)

func main() {
	ctx := context.Background()
	proj := os.Getenv("GOOGLE_CLOUD_PROJECT")
	if proj == "" {
		fmt.Fprintf(os.Stderr, "GOOGLE_CLOUD_PROJECT environment variable must be set.\n")
		os.Exit(1)
	}
	client, err := pubsub.NewClient(ctx, proj)
	if err != nil {
		log.Fatalf("Could not create pubsub Client: %v", err)
	}

	// Print all the subscriptions in the project.
	fmt.Println("Listing all subscriptions from the project:")
	subs, err := list(client)
	if err != nil {
		log.Fatal(err)
	}
	for _, sub := range subs {
		fmt.Println(sub)
	}

	t := createTopicIfNotExists(client)

	const sub = "example-subscription"
	// Create a new subscription.
	if err := create(client, sub, t); err != nil {
		log.Fatal(err)
	}

	// Pull messages via the subscription.
	if err := pullMsgs(client, sub, t); err != nil {
		log.Fatal(err)
	}

	// Delete the subscription.
	if err := delete(client, sub); err != nil {
		log.Fatal(err)
	}
}

func list(client *pubsub.Client) ([]*pubsub.Subscription, error) {
	ctx := context.Background()
	// [START pubsub_list_subscriptions]
	var subs []*pubsub.Subscription
	it := client.Subscriptions(ctx)
	for {
		s, err := it.Next()
		if err == iterator.Done {
			break
		}
		if err != nil {
			return nil, err
		}
		subs = append(subs, s)
	}
	// [END pubsub_list_subscriptions]
	return subs, nil
}

func pullMsgs(client *pubsub.Client, name string, topic *pubsub.Topic) error {
	ctx := context.Background()

	// Publish 10 messages on the topic.
	var results []*pubsub.PublishResult
	for i := 0; i < 10; i++ {
		res := topic.Publish(ctx, &pubsub.Message{
			Data: []byte(fmt.Sprintf("hello world #%d", i)),
		})
		results = append(results, res)
	}

	// Check that all messages were published.
	for _, r := range results {
		_, err := r.Get(ctx)
		if err != nil {
			return err
		}
	}

	// [START pubsub_subscriber_async_pull]
	// [START pubsub_quickstart_subscriber]
	// Consume 10 messages.
	var mu sync.Mutex
	received := 0
	sub := client.Subscription(name)
	cctx, cancel := context.WithCancel(ctx)
	err := sub.Receive(cctx, func(ctx context.Context, msg *pubsub.Message) {
		msg.Ack()
		fmt.Printf("Got message: %q\n", string(msg.Data))
		mu.Lock()
		defer mu.Unlock()
		received++
		if received == 10 {
			cancel()
		}
	})
	if err != nil {
		return err
	}
	// [END pubsub_subscriber_async_pull]
	// [END pubsub_quickstart_subscriber]
	return nil
}

func pullMsgsError(client *pubsub.Client, name string) error {
	ctx := context.Background()
	// [START pubsub_subscriber_error_listener]
	// If the service returns a non-retryable error, Receive returns that error after
	// all of the outstanding calls to the handler have returned.
	err := client.Subscription(name).Receive(ctx, func(ctx context.Context, msg *pubsub.Message) {
		fmt.Printf("Got message: %q\n", string(msg.Data))
		msg.Ack()
	})
	if err != nil {
		return err
	}
	// [END pubsub_subscriber_error_listener]
	return nil
}

func pullMsgsSettings(client *pubsub.Client, name string) error {
	ctx := context.Background()
	// [START pubsub_subscriber_flow_settings]
	sub := client.Subscription(name)
	sub.ReceiveSettings.MaxOutstandingMessages = 10
	err := sub.Receive(ctx, func(ctx context.Context, msg *pubsub.Message) {
		fmt.Printf("Got message: %q\n", string(msg.Data))
		msg.Ack()
	})
	if err != nil {
		return err
	}
	// [END pubsub_subscriber_flow_settings]
	return nil
}

func create(client *pubsub.Client, name string, topic *pubsub.Topic) error {
	ctx := context.Background()
	// [START pubsub_create_pull_subscription]
	sub, err := client.CreateSubscription(ctx, name, pubsub.SubscriptionConfig{
		Topic:       topic,
		AckDeadline: 20 * time.Second,
	})
	if err != nil {
		return err
	}
	fmt.Printf("Created subscription: %v\n", sub)
	// [END pubsub_create_pull_subscription]
	return nil
}

func createWithEndpoint(client *pubsub.Client, name string, topic *pubsub.Topic, endpoint string) error {
	ctx := context.Background()
	// [START pubsub_create_push_subscription]

	// For example, endpoint is "https://my-test-project.appspot.com/push".
	sub, err := client.CreateSubscription(ctx, name, pubsub.SubscriptionConfig{
		Topic:       topic,
		AckDeadline: 10 * time.Second,
		PushConfig:  pubsub.PushConfig{Endpoint: endpoint},
	})
	if err != nil {
		return err
	}
	fmt.Printf("Created subscription: %v\n", sub)
	// [END pubsub_create_push_subscription]
	return nil
}

func updateEndpoint(client *pubsub.Client, name string, endpoint string) error {
	ctx := context.Background()
	// [START pubsub_update_push_configuration]

	// For example, endpoint is "https://my-test-project.appspot.com/push".
	subConfig, err := client.Subscription(name).Update(ctx, pubsub.SubscriptionConfigToUpdate{
		PushConfig: &pubsub.PushConfig{Endpoint: endpoint},
	})
	if err != nil {
		return err
	}
	fmt.Printf("Updated subscription config: %#v", subConfig)
	// [END pubsub_update_push_configuration]
	return nil
}

func delete(client *pubsub.Client, name string) error {
	ctx := context.Background()
	// [START pubsub_delete_subscription]
	sub := client.Subscription(name)
	if err := sub.Delete(ctx); err != nil {
		return err
	}
	fmt.Println("Subscription deleted.")
	// [END pubsub_delete_subscription]
	return nil
}

func createTopicIfNotExists(c *pubsub.Client) *pubsub.Topic {
	ctx := context.Background()

	const topic = "example-topic"
	// Create a topic to subscribe to.
	t := c.Topic(topic)
	ok, err := t.Exists(ctx)
	if err != nil {
		log.Fatal(err)
	}
	if ok {
		return t
	}

	t, err = c.CreateTopic(ctx, topic)
	if err != nil {
		log.Fatalf("Failed to create the topic: %v", err)
	}
	return t
}

func getPolicy(c *pubsub.Client, subName string) (*iam.Policy, error) {
	ctx := context.Background()

	// [START pubsub_get_subscription_policy]
	policy, err := c.Subscription(subName).IAM().Policy(ctx)
	if err != nil {
		return nil, err
	}
	for _, role := range policy.Roles() {
		log.Printf("%q: %q", role, policy.Members(role))
	}
	// [END pubsub_get_subscription_policy]
	return policy, nil
}

func addUsers(c *pubsub.Client, subName string) error {
	ctx := context.Background()

	// [START pubsub_set_subscription_policy]
	sub := c.Subscription(subName)
	policy, err := sub.IAM().Policy(ctx)
	if err != nil {
		return err
	}
	// Other valid prefixes are "serviceAccount:", "user:"
	// See the documentation for more values.
	policy.Add(iam.AllUsers, iam.Viewer)
	policy.Add("group:cloud-logs@google.com", iam.Editor)
	if err := sub.IAM().SetPolicy(ctx, policy); err != nil {
		return err
	}
	// NOTE: It may be necessary to retry this operation if IAM policies are
	// being modified concurrently. SetPolicy will return an error if the policy
	// was modified since it was retrieved.
	// [END pubsub_set_subscription_policy]
	return nil
}

func testPermissions(c *pubsub.Client, subName string) ([]string, error) {
	ctx := context.Background()

	// [START pubsub_test_subscription_permissions]
	sub := c.Subscription(subName)
	perms, err := sub.IAM().TestPermissions(ctx, []string{
		"pubsub.subscriptions.consume",
		"pubsub.subscriptions.update",
	})
	if err != nil {
		return nil, err
	}
	for _, perm := range perms {
		log.Printf("Allowed: %v", perm)
	}
	// [END pubsub_test_subscription_permissions]
	return perms, nil
}
<commit_msg>pubsub: make subName var name more specific (#573)<commit_after>// Copyright 2016 Google Inc. All rights reserved.
// Use of this source code is governed by the Apache 2.0
// license that can be found in the LICENSE file.

// Command subscriptions is a tool to manage Google Cloud Pub/Sub subscriptions by using the Pub/Sub API.
// See more about Google Cloud Pub/Sub at https://cloud.google.com/pubsub/docs/overview.
package main

import (
	"fmt"
	"log"
	"os"
	"sync"
	"time"

	"golang.org/x/net/context"

	"cloud.google.com/go/iam"
	"cloud.google.com/go/pubsub"
	"google.golang.org/api/iterator"
)

func main() {
	ctx := context.Background()
	proj := os.Getenv("GOOGLE_CLOUD_PROJECT")
	if proj == "" {
		fmt.Fprintf(os.Stderr, "GOOGLE_CLOUD_PROJECT environment variable must be set.\n")
		os.Exit(1)
	}
	client, err := pubsub.NewClient(ctx, proj)
	if err != nil {
		log.Fatalf("Could not create pubsub Client: %v", err)
	}

	// Print all the subscriptions in the project.
	fmt.Println("Listing all subscriptions from the project:")
	subs, err := list(client)
	if err != nil {
		log.Fatal(err)
	}
	for _, sub := range subs {
		fmt.Println(sub)
	}

	t := createTopicIfNotExists(client)

	const sub = "example-subscription"
	// Create a new subscription.
	if err := create(client, sub, t); err != nil {
		log.Fatal(err)
	}

	// Pull messages via the subscription.
	if err := pullMsgs(client, sub, t); err != nil {
		log.Fatal(err)
	}

	// Delete the subscription.
	if err := delete(client, sub); err != nil {
		log.Fatal(err)
	}
}

func list(client *pubsub.Client) ([]*pubsub.Subscription, error) {
	ctx := context.Background()
	// [START pubsub_list_subscriptions]
	var subs []*pubsub.Subscription
	it := client.Subscriptions(ctx)
	for {
		s, err := it.Next()
		if err == iterator.Done {
			break
		}
		if err != nil {
			return nil, err
		}
		subs = append(subs, s)
	}
	// [END pubsub_list_subscriptions]
	return subs, nil
}

func pullMsgs(client *pubsub.Client, subName string, topic *pubsub.Topic) error {
	ctx := context.Background()

	// Publish 10 messages on the topic.
	var results []*pubsub.PublishResult
	for i := 0; i < 10; i++ {
		res := topic.Publish(ctx, &pubsub.Message{
			Data: []byte(fmt.Sprintf("hello world #%d", i)),
		})
		results = append(results, res)
	}

	// Check that all messages were published.
	for _, r := range results {
		_, err := r.Get(ctx)
		if err != nil {
			return err
		}
	}

	// [START pubsub_subscriber_async_pull]
	// [START pubsub_quickstart_subscriber]
	// Consume 10 messages.
	var mu sync.Mutex
	received := 0
	sub := client.Subscription(subName)
	cctx, cancel := context.WithCancel(ctx)
	err := sub.Receive(cctx, func(ctx context.Context, msg *pubsub.Message) {
		msg.Ack()
		fmt.Printf("Got message: %q\n", string(msg.Data))
		mu.Lock()
		defer mu.Unlock()
		received++
		if received == 10 {
			cancel()
		}
	})
	if err != nil {
		return err
	}
	// [END pubsub_subscriber_async_pull]
	// [END pubsub_quickstart_subscriber]
	return nil
}

func pullMsgsError(client *pubsub.Client, subName string) error {
	ctx := context.Background()
	// [START pubsub_subscriber_error_listener]
	// If the service returns a non-retryable error, Receive returns that error after
	// all of the outstanding calls to the handler have returned.
	err := client.Subscription(subName).Receive(ctx, func(ctx context.Context, msg *pubsub.Message) {
		fmt.Printf("Got message: %q\n", string(msg.Data))
		msg.Ack()
	})
	if err != nil {
		return err
	}
	// [END pubsub_subscriber_error_listener]
	return nil
}

func pullMsgsSettings(client *pubsub.Client, subName string) error {
	ctx := context.Background()
	// [START pubsub_subscriber_flow_settings]
	sub := client.Subscription(subName)
	sub.ReceiveSettings.MaxOutstandingMessages = 10
	err := sub.Receive(ctx, func(ctx context.Context, msg *pubsub.Message) {
		fmt.Printf("Got message: %q\n", string(msg.Data))
		msg.Ack()
	})
	if err != nil {
		return err
	}
	// [END pubsub_subscriber_flow_settings]
	return nil
}

func create(client *pubsub.Client, subName string, topic *pubsub.Topic) error {
	ctx := context.Background()
	// [START pubsub_create_pull_subscription]
	sub, err := client.CreateSubscription(ctx, subName, pubsub.SubscriptionConfig{
		Topic:       topic,
		AckDeadline: 20 * time.Second,
	})
	if err != nil {
		return err
	}
	fmt.Printf("Created subscription: %v\n", sub)
	// [END pubsub_create_pull_subscription]
	return nil
}

func createWithEndpoint(client *pubsub.Client, subName string, topic *pubsub.Topic, endpoint string) error {
	ctx := context.Background()
	// [START pubsub_create_push_subscription]

	// For example, endpoint is "https://my-test-project.appspot.com/push".
	sub, err := client.CreateSubscription(ctx, subName, pubsub.SubscriptionConfig{
		Topic:       topic,
		AckDeadline: 10 * time.Second,
		PushConfig:  pubsub.PushConfig{Endpoint: endpoint},
	})
	if err != nil {
		return err
	}
	fmt.Printf("Created subscription: %v\n", sub)
	// [END pubsub_create_push_subscription]
	return nil
}

func updateEndpoint(client *pubsub.Client, subName string, endpoint string) error {
	ctx := context.Background()
	// [START pubsub_update_push_configuration]

	// For example, endpoint is "https://my-test-project.appspot.com/push".
	subConfig, err := client.Subscription(subName).Update(ctx, pubsub.SubscriptionConfigToUpdate{
		PushConfig: &pubsub.PushConfig{Endpoint: endpoint},
	})
	if err != nil {
		return err
	}
	fmt.Printf("Updated subscription config: %#v", subConfig)
	// [END pubsub_update_push_configuration]
	return nil
}

func delete(client *pubsub.Client, subName string) error {
	ctx := context.Background()
	// [START pubsub_delete_subscription]
	sub := client.Subscription(subName)
	if err := sub.Delete(ctx); err != nil {
		return err
	}
	fmt.Println("Subscription deleted.")
	// [END pubsub_delete_subscription]
	return nil
}

func createTopicIfNotExists(c *pubsub.Client) *pubsub.Topic {
	ctx := context.Background()

	const topic = "example-topic"
	// Create a topic to subscribe to.
	t := c.Topic(topic)
	ok, err := t.Exists(ctx)
	if err != nil {
		log.Fatal(err)
	}
	if ok {
		return t
	}

	t, err = c.CreateTopic(ctx, topic)
	if err != nil {
		log.Fatalf("Failed to create the topic: %v", err)
	}
	return t
}

func getPolicy(c *pubsub.Client, subName string) (*iam.Policy, error) {
	ctx := context.Background()

	// [START pubsub_get_subscription_policy]
	policy, err := c.Subscription(subName).IAM().Policy(ctx)
	if err != nil {
		return nil, err
	}
	for _, role := range policy.Roles() {
		log.Printf("%q: %q", role, policy.Members(role))
	}
	// [END pubsub_get_subscription_policy]
	return policy, nil
}

func addUsers(c *pubsub.Client, subName string) error {
	ctx := context.Background()

	// [START pubsub_set_subscription_policy]
	sub := c.Subscription(subName)
	policy, err := sub.IAM().Policy(ctx)
	if err != nil {
		return err
	}
	// Other valid prefixes are "serviceAccount:", "user:"
	// See the documentation for more values.
	policy.Add(iam.AllUsers, iam.Viewer)
	policy.Add("group:cloud-logs@google.com", iam.Editor)
	if err := sub.IAM().SetPolicy(ctx, policy); err != nil {
		return err
	}
	// NOTE: It may be necessary to retry this operation if IAM policies are
	// being modified concurrently. SetPolicy will return an error if the policy
	// was modified since it was retrieved.
	// [END pubsub_set_subscription_policy]
	return nil
}

func testPermissions(c *pubsub.Client, subName string) ([]string, error) {
	ctx := context.Background()

	// [START pubsub_test_subscription_permissions]
	sub := c.Subscription(subName)
	perms, err := sub.IAM().TestPermissions(ctx, []string{
		"pubsub.subscriptions.consume",
		"pubsub.subscriptions.update",
	})
	if err != nil {
		return nil, err
	}
	for _, perm := range perms {
		log.Printf("Allowed: %v", perm)
	}
	// [END pubsub_test_subscription_permissions]
	return perms, nil
}
<|endoftext|>


<commit_before>package sms

import (
	"bufio"
	"fmt"
	"io"
	"net/http"
	"strconv"
)

const (
	uri         = "https://sms-rassilka.com/api/simple"
	defaultFrom = "inform"

	// In progress delivery statuses.
	StatusQueued     = "0"
	StatusSent       = "1"
	StatusModerating = "10"

	// Successful delivery statuses.
	StatusDelivered = "3"

	// Unsuccessful delivery statuses.
	StatusUnavailable    = "4"
	StatusRejected       = "11"
	StatusSpam           = "15"
	StatusInvPhone       = "16"
	StatusStopListGlobal = "20"
	StatusStopListLocal  = "21"
	StatusExpired        = "25"

	// Outdated statuses for backward compatibility.
	StatusOld2 = "2"
	StatusOld5 = "5"
	StatusOld6 = "6"
)

// Sender is a library facade for sending SMS and retrieving delivery statuses.
type Sender struct {
	// Login on https://sms-rassilka.com
	Login string

	// MD5-hash of your password.
	PasswordMD5 string

	// SandboxMode is used to test the connection without actually wasting your balance.
	// If false, real SMS are sent and real delivery statuses are retrieved.
	// If true, no SMS are really sent and delivery statuses are fake.
	SandboxMode bool

	// Client allows to make requests with your own HTTP client.
	Client http.Client
}

// SendResult represents a result of sending an SMS.
type SendResult struct {
	SMSID     string
	SMSCnt    int
	SentAt    string
	DebugInfo string
}

// SendSMS sends an SMS right away with the default Sender.
func (s Sender) SendSMS(to, text string) (SendResult, error) {
	return s.sendSMS(to, text, defaultFrom, "")
}

// SendSMSFrom sends an SMS right away from the specified Sender.
func (s Sender) SendSMSFrom(to, text, from string) (SendResult, error) {
	return s.sendSMS(to, text, from, "")
}

// SendSMSAt sends an SMS from the default Sender at the specified time.
func (s Sender) SendSMSAt(to, text, sendTime string) (SendResult, error) {
	return s.sendSMS(to, text, defaultFrom, sendTime)
}

// SendSMSFromAt sends an SMS from the specified Sender at the specified time.
func (s Sender) SendSMSFromAt(to, text, from, sendTime string) (SendResult, error) {
	return s.sendSMS(to, text, from, sendTime)
}

// QueryStatus requests delivery status of an SMS.
func (s Sender) QueryStatus(SMSID string) (DeliveryStatus, error) {
	args := map[string]string{
		"smsId": SMSID,
	}
	resp, err := s.request(uri+"/status", args)
	if err != nil {
		return "", fmt.Errorf("failed to request status: %v", err.Error())
	}
	defer resp.Close()
	return s.parseStatusResponse(resp)
}

func (s Sender) parseStatusResponse(resp io.Reader) (DeliveryStatus, error) {
	scanner := bufio.NewScanner(resp)
	scanner.Scan()
	code := scanner.Text()
	scanner.Scan()
	t := scanner.Text()
	if code != "1" {
		return "", fmt.Errorf("error response: %s %s", code, t)
	}
	return DeliveryStatus(t), nil
}

func (s Sender) sendSMS(to, text, from, sendTime string) (SendResult, error) {
	args := map[string]string{
		"to":   to,
		"text": text,
	}
	if from != "" {
		args["from"] = from
	}
	if sendTime != "" {
		args["sendTime"] = sendTime
	}
	resp, err := s.request(uri+"/send", args)
	if err != nil {
		return SendResult{}, fmt.Errorf("failed to request the service: %v", err)
	}
	defer resp.Close()
	return s.parseSendSMSResponse(resp)
}

func (s Sender) parseSendSMSResponse(resp io.Reader) (SendResult, error) {
	scanner := bufio.NewScanner(resp)
	scanner.Scan()
	code := scanner.Text()
	if code != "1" {
		scanner.Scan()
		return SendResult{}, fmt.Errorf("got error response: %s %s", code, scanner.Text())
	}

	sr := SendResult{}
	for line := 0; scanner.Scan(); line++ {
		switch line {
		case 0:
			sr.SMSID = scanner.Text()
		case 1:
			c, err := strconv.Atoi(scanner.Text())
			if err != nil {
				return SendResult{}, fmt.Errorf("bad SMS count: %v", err)
			}
			sr.SMSCnt = c
		case 2:
			sr.SentAt = scanner.Text()
		default:
			sr.DebugInfo += scanner.Text() + "\n"
		}
	}
	if sr.SMSID == "" {
		return SendResult{}, fmt.Errorf("empty SMSID in the response")
	}
	if sr.SentAt == "" {
		return SendResult{}, fmt.Errorf("empty SentAt in the response")
	}
	if err := scanner.Err(); err != nil {
		return SendResult{}, fmt.Errorf("bad response: %v", err.Error())
	}
	return sr, nil
}

func (s Sender) request(uri string, args map[string]string) (io.ReadCloser, error) {
	// The error is caught during tests.
	req, _ := http.NewRequest(http.MethodGet, uri, nil)
	q := req.URL.Query()
	q.Set("login", s.Login)
	q.Set("password", s.PasswordMD5)
	if s.SandboxMode {
		q.Set("mode", "dev")
	}
	for k, v := range args {
		q.Set(k, v)
	}
	req.URL.RawQuery = q.Encode()
	resp, err := s.Client.Do(req)
	if err != nil {
		return nil, err
	}
	return resp.Body, nil
}

// DeliveryStatus represents a delivery status. If you need an exact status, compare with constants above.
type DeliveryStatus string

// IsInProgress tells if a message is still being processed.
func (d DeliveryStatus) IsInProgress() bool {
	return d == StatusQueued || d == StatusSent || d == StatusModerating
}

// IsDelivered tells if a message has in fact been delivered.
func (d DeliveryStatus) IsDelivered() bool {
	return d == StatusDelivered
}

// IsUndelivered tells if a message has been processed and undelivered by any reason.
func (d DeliveryStatus) IsUndelivered() bool {
	return !d.IsInProgress() && !d.IsDelivered()
}
<commit_msg>Removed unneeded constants<commit_after>package sms

import (
	"bufio"
	"fmt"
	"io"
	"net/http"
	"strconv"
)

const (
	// In progress delivery statuses.
	StatusQueued     = "0"
	StatusSent       = "1"
	StatusModerating = "10"

	// Successful delivery statuses.
	StatusDelivered = "3"

	// Unsuccessful delivery statuses.
	StatusUnavailable    = "4"
	StatusRejected       = "11"
	StatusSpam           = "15"
	StatusInvPhone       = "16"
	StatusStopListGlobal = "20"
	StatusStopListLocal  = "21"
	StatusExpired        = "25"

	// Outdated statuses for backward compatibility.
	StatusOld2 = "2"
	StatusOld5 = "5"
	StatusOld6 = "6"
)

// Sender is a library facade for sending SMS and retrieving delivery statuses.
type Sender struct {
	// Login on https://sms-rassilka.com
	Login string

	// MD5-hash of your password.
	PasswordMD5 string

	// SandboxMode is used to test the connection without actually wasting your balance.
	// If false, real SMS are sent and real delivery statuses are retrieved.
	// If true, no SMS are really sent and delivery statuses are fake.
	SandboxMode bool

	// Client allows to make requests with your own HTTP client.
	Client http.Client
}

// SendResult represents a result of sending an SMS.
type SendResult struct {
	SMSID     string
	SMSCnt    int
	SentAt    string
	DebugInfo string
}

// SendSMS sends an SMS right away with the default Sender.
func (s Sender) SendSMS(to, text string) (SendResult, error) {
	return s.sendSMS(to, text, "inform", "")
}

// SendSMSFrom sends an SMS right away from the specified Sender.
func (s Sender) SendSMSFrom(to, text, from string) (SendResult, error) {
	return s.sendSMS(to, text, from, "")
}

// SendSMSAt sends an SMS from the default Sender at the specified time.
func (s Sender) SendSMSAt(to, text, sendTime string) (SendResult, error) {
	return s.sendSMS(to, text, "inform", sendTime)
}

// SendSMSFromAt sends an SMS from the specified Sender at the specified time.
func (s Sender) SendSMSFromAt(to, text, from, sendTime string) (SendResult, error) {
	return s.sendSMS(to, text, from, sendTime)
}

// QueryStatus requests delivery status of an SMS.
func (s Sender) QueryStatus(SMSID string) (DeliveryStatus, error) {
	args := map[string]string{
		"smsId": SMSID,
	}
	resp, err := s.request("/status", args)
	if err != nil {
		return "", fmt.Errorf("failed to request status: %v", err.Error())
	}
	defer resp.Close()
	return s.parseStatusResponse(resp)
}

func (s Sender) parseStatusResponse(resp io.Reader) (DeliveryStatus, error) {
	scanner := bufio.NewScanner(resp)
	scanner.Scan()
	code := scanner.Text()
	scanner.Scan()
	t := scanner.Text()
	if code != "1" {
		return "", fmt.Errorf("error response: %s %s", code, t)
	}
	return DeliveryStatus(t), nil
}

func (s Sender) sendSMS(to, text, from, sendTime string) (SendResult, error) {
	args := map[string]string{
		"to":   to,
		"text": text,
	}
	if from != "" {
		args["from"] = from
	}
	if sendTime != "" {
		args["sendTime"] = sendTime
	}
	resp, err := s.request("/send", args)
	if err != nil {
		return SendResult{}, fmt.Errorf("failed to request the service: %v", err)
	}
	defer resp.Close()
	return s.parseSendSMSResponse(resp)
}

func (s Sender) parseSendSMSResponse(resp io.Reader) (SendResult, error) {
	scanner := bufio.NewScanner(resp)
	scanner.Scan()
	code := scanner.Text()
	if code != "1" {
		scanner.Scan()
		return SendResult{}, fmt.Errorf("got error response: %s %s", code, scanner.Text())
	}

	sr := SendResult{}
	for line := 0; scanner.Scan(); line++ {
		switch line {
		case 0:
			sr.SMSID = scanner.Text()
		case 1:
			c, err := strconv.Atoi(scanner.Text())
			if err != nil {
				return SendResult{}, fmt.Errorf("bad SMS count: %v", err)
			}
			sr.SMSCnt = c
		case 2:
			sr.SentAt = scanner.Text()
		default:
			sr.DebugInfo += scanner.Text() + "\n"
		}
	}
	if sr.SMSID == "" {
		return SendResult{}, fmt.Errorf("empty SMSID in the response")
	}
	if sr.SentAt == "" {
		return SendResult{}, fmt.Errorf("empty SentAt in the response")
	}
	if err := scanner.Err(); err != nil {
		return SendResult{}, fmt.Errorf("bad response: %v", err.Error())
	}
	return sr, nil
}

func (s Sender) request(path string, args map[string]string) (io.ReadCloser, error) {
	// The error is caught during tests.
	req, _ := http.NewRequest(http.MethodGet, "https://sms-rassilka.com/api/simple" + path, nil)
	q := req.URL.Query()
	q.Set("login", s.Login)
	q.Set("password", s.PasswordMD5)
	if s.SandboxMode {
		q.Set("mode", "dev")
	}
	for k, v := range args {
		q.Set(k, v)
	}
	req.URL.RawQuery = q.Encode()
	resp, err := s.Client.Do(req)
	if err != nil {
		return nil, err
	}
	return resp.Body, nil
}

// DeliveryStatus represents a delivery status. If you need an exact status, compare with constants above.
type DeliveryStatus string

// IsInProgress tells if a message is still being processed.
func (d DeliveryStatus) IsInProgress() bool {
	return d == StatusQueued || d == StatusSent || d == StatusModerating
}

// IsDelivered tells if a message has in fact been delivered.
func (d DeliveryStatus) IsDelivered() bool {
	return d == StatusDelivered
}

// IsUndelivered tells if a message has been processed and undelivered by any reason.
func (d DeliveryStatus) IsUndelivered() bool {
	return !d.IsInProgress() && !d.IsDelivered()
}
<|endoftext|>


<commit_before>/*
 *  Bulldozer Framework
 *  Copyright (C) DesertBit
 */

package dialog

import (
	htmlTemplate "html/template"

	"code.desertbit.com/bulldozer/bulldozer/sessions"
	"code.desertbit.com/bulldozer/bulldozer/template"
	"code.desertbit.com/bulldozer/bulldozer/utils"
	"io/ioutil"
	"strconv"
)

type Size string

const (
	SizeSmall  Size = "small"
	SizeMedium Size = "medium"
	SizeLarge  Size = "large"
)

//###########################//
//### Event Receiver type ###//
//###########################//

type receiver struct{}

func (r *receiver) EventClosed(c *template.Context) {
	// Release the context.
	c.Release()
}

//###################//
//### Dialog type ###//
//###################//

type Dialog struct {
	t        *template.Template
	size     Size
	closable bool
	receiver receiver
}

// New creates a new template and passes the UID to the template.
func New(uid string) *Dialog {
	// Create a new dialog.
	d := &Dialog{
		t:        template.New(uid, "dialog"),
		size:     SizeMedium,
		closable: true,
	}

	// Register the internal dialog events.
	d.t.RegisterEvents(&d.receiver, "dialog")

	// Add the custom dialog functions.
	d.t.Funcs(template.FuncMap{
		"closeDialog": closeModalTemplateFunc,
	})

	return d
}

// Size sets the dialog size specified by a dialog.Size value.
// The defaut size is SizeMedium.
func (d *Dialog) SetSize(size Size) {
	d.size = size
}

// Whenever the modal is closable with a backdrop click or x button
func (d *Dialog) SetClosable(closable bool) {
	d.closable = closable
}

// RegisterEvents is the same as template.RegisterEvents...
func (d *Dialog) RegisterEvents(i interface{}, vars ...string) {
	d.t.RegisterEvents(i, vars...)
}

// OnGetData is the same as template.OnGetData...
func (d *Dialog) OnGetData(f template.GetDataFunc) {
	d.t.OnGetData(f)
}

// ParseFile parses a template file.
func (d *Dialog) ParseFile(filename string) (err error) {
	b, err := ioutil.ReadFile(filename)
	if err != nil {
		return err
	}

	return d.Parse(string(b))
}

// Parse a template text.
func (d *Dialog) Parse(text string) (err error) {
	// Append the dialog javascript code
	text += `{{js load}}
	var e=$("#{{$.Context.DomID}}__d");
	Kepler.modal.closed(e,function(){
		if (e.data('serverClosedDialog')!==true) {{emit dialog.Closed()}}
	});
{{end js}}`

	// Parse the template text.
	_, err = d.t.Parse(text)
	if err != nil {
		return err
	}

	return nil
}

// Create and show a new Dialog.
// The data interface is passed to the template execution call if passed.
func (d *Dialog) Show(s *sessions.Session, data ...interface{}) (*template.Context, error) {
	// Create the optional options for the template.
	opts := template.ExecOpts{
		ID:    s.NewUniqueId(),
		DomID: s.NewUniqueDomID(),
	}

	// Set the data if present.
	if len(data) > 0 {
		opts.Data = data[0]
	}

	// Execute the template
	o, c, err := d.t.ExecuteToString(s, opts)
	if err != nil {
		return nil, err
	}

	// Create the dialog DOM ID.
	dialogDomID := opts.DomID + "__d"

	// Transform to string
	closableStr := strconv.FormatBool(d.closable)

	// Create the command
	cmd := `Bulldozer.utils.addAndShowTmpModal('` + utils.EscapeJS(o) + `',{
			domId:'` + dialogDomID + `',
			closable:` + closableStr + `,
			class:'radius shadow ` + string(d.size) + `'
		});`

	// Execute the command on the client side.
	// The loading indicator is hidden automatically by the Bulldozer.core.execJsLoad() function.
	s.SendCommand(cmd)

	return c, nil
}

// Close the dialog.
func (d *Dialog) Close(c *template.Context) {
	// Close the dialog
	c.Session().SendCommand(`(function(){
		var e=$('#` + c.DomID() + `__d');
		e.data('serverClosedDialog', true);
		Kepler.modal.close(e);
	})();`)

	// Call the event manually.
	d.receiver.EventClosed(c)
}

//###############//
//### Private ###//
//###############//

func closeModalTemplateFunc(c *template.Context) htmlTemplate.JS {
	return htmlTemplate.JS(`Kepler.modal.close("#` + c.DomID() + `__d");`)
}
<commit_msg>further progress<commit_after>/*
 *  Bulldozer Framework
 *  Copyright (C) DesertBit
 */

package dialog

import (
	htmlTemplate "html/template"

	"code.desertbit.com/bulldozer/bulldozer/sessions"
	"code.desertbit.com/bulldozer/bulldozer/template"
	"code.desertbit.com/bulldozer/bulldozer/utils"
	"io/ioutil"
	"strconv"
)

type Size string

const (
	SizeSmall  Size = "small"
	SizeMedium Size = "medium"
	SizeLarge  Size = "large"
)

//###########################//
//### Event Receiver type ###//
//###########################//

type receiver struct{}

func (r *receiver) EventClosed(c *template.Context) {
	// Release the context.
	c.Release()
}

//###################//
//### Dialog type ###//
//###################//

type Dialog struct {
	t        *template.Template
	size     Size
	closable bool
	receiver receiver
}

// New creates a new template and passes the UID to the template.
func New(uid string) *Dialog {
	// Create a new dialog.
	d := &Dialog{
		t:        template.New(uid, "dialog"),
		size:     SizeMedium,
		closable: true,
	}

	// Register the internal dialog events.
	d.t.RegisterEvents(&d.receiver, "dialog")

	// Add the custom dialog functions.
	d.t.Funcs(template.FuncMap{
		"closeDialog": closeModalTemplateFunc,
	})

	return d
}

// AddStyleClass adds one style classes.
func (d *Dialog) AddStyleClass(class string) *Dialog {
	d.t.AddStyleClass(class)
	return d
}

// Size sets the dialog size specified by a dialog.Size value.
// The defaut size is SizeMedium.
func (d *Dialog) SetSize(size Size) *Dialog {
	d.size = size
	return d
}

// Whenever the modal is closable with a backdrop click or x button
func (d *Dialog) SetClosable(closable bool) *Dialog {
	d.closable = closable
	return d
}

// RegisterEvents is the same as template.RegisterEvents...
func (d *Dialog) RegisterEvents(i interface{}, vars ...string) *Dialog {
	d.t.RegisterEvents(i, vars...)
	return d
}

// OnGetData is the same as template.OnGetData...
func (d *Dialog) OnGetData(f template.GetDataFunc) *Dialog {
	d.t.OnGetData(f)
	return d
}

// ParseFile parses a template file.
func (d *Dialog) ParseFile(filename string) (err error) {
	b, err := ioutil.ReadFile(filename)
	if err != nil {
		return err
	}

	return d.Parse(string(b))
}

// Parse a template text.
func (d *Dialog) Parse(text string) (err error) {
	// Append the dialog javascript code
	text += `{{js load}}
	var e=$("#{{$.Context.DomID}}__d");
	Kepler.modal.closed(e,function(){
		if (e.data('serverClosedDialog')!==true) {{emit dialog.Closed()}}
	});
{{end js}}`

	// Parse the template text.
	_, err = d.t.Parse(text)
	if err != nil {
		return err
	}

	return nil
}

// Create and show a new Dialog.
// The data interface is passed to the template execution call if passed.
func (d *Dialog) Show(s *sessions.Session, data ...interface{}) (*template.Context, error) {
	// Create the optional options for the template.
	opts := template.ExecOpts{
		ID:    s.NewUniqueId(),
		DomID: s.NewUniqueDomID(),
	}

	// Set the data if present.
	if len(data) > 0 {
		opts.Data = data[0]
	}

	// Execute the template
	o, c, err := d.t.ExecuteToString(s, opts)
	if err != nil {
		return nil, err
	}

	// Create the dialog DOM ID.
	dialogDomID := opts.DomID + "__d"

	// Transform to string
	closableStr := strconv.FormatBool(d.closable)

	// Create the command
	cmd := `Bulldozer.utils.addAndShowTmpModal('` + utils.EscapeJS(o) + `',{
			domId:'` + dialogDomID + `',
			closable:` + closableStr + `,
			class:'radius shadow ` + string(d.size) + `'
		});`

	// Execute the command on the client side.
	// The loading indicator is hidden automatically by the Bulldozer.core.execJsLoad() function.
	s.SendCommand(cmd)

	return c, nil
}

// Close the dialog.
func (d *Dialog) Close(c *template.Context) {
	// Close the dialog
	c.Session().SendCommand(`(function(){
		var e=$('#` + c.DomID() + `__d');
		e.data('serverClosedDialog', true);
		Kepler.modal.close(e);
	})();`)

	// Call the event manually.
	d.receiver.EventClosed(c)
}

//###############//
//### Private ###//
//###############//

func closeModalTemplateFunc(c *template.Context) htmlTemplate.JS {
	return htmlTemplate.JS(`Kepler.modal.close("#` + c.DomID() + `__d");`)
}
<|endoftext|>


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

package uuid

import (
	"database/sql/driver"
	"errors"
	"fmt"
)

// Scan implements sql.Scanner so UUIDs can be read from databases transparently
// Currently, database types that map to string and []byte are supported. Please
// consult database-specific driver documentation for matching types.
func (uuid *UUID) Scan(src interface{}) error {
	switch src.(type) {
	case string:
		// if an empty UUID comes from a table, we return a null UUID
		if src.(string) == "" {
			return nil
		}

		// see uuid.Parse for required string format
		parsed := Parse(src.(string))

		if parsed == nil {
			return errors.New("Scan: invalid UUID format")
		}

		*uuid = parsed
	case []byte:
		b := src.([]byte)

		// if an empty UUID comes from a table, we return a null UUID
		if len(b) == 0 {
			return nil
		}

		// assumes a simple slice of bytes if 16 bytes
		// otherwise attempts to parse
		if len(b) == 16 {
            parsed := make([]byte, 16)
            copy(parsed, b)
			*uuid = UUID(parsed)
		} else {
			u := Parse(string(b))

			if u == nil {
				return errors.New("Scan: invalid UUID format")
			}

			*uuid = u
		}

	default:
		return fmt.Errorf("Scan: unable to scan type %T into UUID", src)
	}

	return nil
}

// Value implements sql.Valuer so that UUIDs can be written to databases
// transparently. Currently, UUIDs map to strings. Please consult
// database-specific driver documentation for matching types.
func (uuid UUID) Value() (driver.Value, error) {
	return uuid.String(), nil
}
<commit_msg>Go fmt<commit_after>// Copyright 2015 Google Inc.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package uuid

import (
	"database/sql/driver"
	"errors"
	"fmt"
)

// Scan implements sql.Scanner so UUIDs can be read from databases transparently
// Currently, database types that map to string and []byte are supported. Please
// consult database-specific driver documentation for matching types.
func (uuid *UUID) Scan(src interface{}) error {
	switch src.(type) {
	case string:
		// if an empty UUID comes from a table, we return a null UUID
		if src.(string) == "" {
			return nil
		}

		// see uuid.Parse for required string format
		parsed := Parse(src.(string))

		if parsed == nil {
			return errors.New("Scan: invalid UUID format")
		}

		*uuid = parsed
	case []byte:
		b := src.([]byte)

		// if an empty UUID comes from a table, we return a null UUID
		if len(b) == 0 {
			return nil
		}

		// assumes a simple slice of bytes if 16 bytes
		// otherwise attempts to parse
		if len(b) == 16 {
			parsed := make([]byte, 16)
			copy(parsed, b)
			*uuid = UUID(parsed)
		} else {
			u := Parse(string(b))

			if u == nil {
				return errors.New("Scan: invalid UUID format")
			}

			*uuid = u
		}

	default:
		return fmt.Errorf("Scan: unable to scan type %T into UUID", src)
	}

	return nil
}

// Value implements sql.Valuer so that UUIDs can be written to databases
// transparently. Currently, UUIDs map to strings. Please consult
// database-specific driver documentation for matching types.
func (uuid UUID) Value() (driver.Value, error) {
	return uuid.String(), nil
}
<|endoftext|>


<commit_before>package acceptance

import (
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
)

var _ = Describe("Cloud Foundry", func() {
	It("should return CF quota metrics", func() {
		Expect(metricFamilies).To(SatisfyAll(
			HaveKey("paas_op_quota_memory_allocated_megabytes"),
			HaveKey("paas_op_quota_memory_reserved_megabytes"),
			HaveKey("paas_op_quota_routes_reserved_count"),
			HaveKey("paas_op_quota_services_allocated_count"),
			HaveKey("paas_op_quota_services_reserved_count"),
		))
	})

	It("should return CF application metrics", func() {
		Expect(metricFamilies).To(SatisfyAll(
			HaveKey("paas_op_apps_count"),
			HaveKey("paas_op_events_app_crash_count"),
		))
	})

	It("should return CF org metrics", func() {
		Expect(metricFamilies).To(SatisfyAll(
			HaveKey("paas_op_orgs_count"),
			HaveKey("paas_op_spaces_count"),
			HaveKey("paas_op_services_provisioned_count"),
			HaveKey("paas_op_users_count"),
		))
	})

	It("should return CF service metrics", func() {
		Expect(metricFamilies).To(SatisfyAll(
			HaveKey("paas_op_services_provisioned_count"),
			HaveKey("paas_op_users_count"),
		))
	})

	It("should return CF user metrics", func() {
		Expect(metricFamilies).To(SatisfyAll(
			HaveKey("paas_op_users_count"),
		))
	})
})
<commit_msg>metrics: cf acceptance uses Eventually/Should<commit_after>package acceptance

import (
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
)

var _ = Describe("Cloud Foundry", func() {
	It("should return CF quota metrics", func() {
		Eventually(getMetrics).Should(SatisfyAll(
			HaveKey("paas_op_quota_memory_allocated_megabytes"),
			HaveKey("paas_op_quota_memory_reserved_megabytes"),
			HaveKey("paas_op_quota_routes_reserved_count"),
			HaveKey("paas_op_quota_services_allocated_count"),
			HaveKey("paas_op_quota_services_reserved_count"),
		))
	})

	It("should return CF application metrics", func() {
		Eventually(getMetrics).Should(SatisfyAll(
			HaveKey("paas_op_apps_count"),
			HaveKey("paas_op_events_app_crash_count"),
		))
	})

	It("should return CF org metrics", func() {
		Eventually(getMetrics).Should(SatisfyAll(
			HaveKey("paas_op_orgs_count"),
			HaveKey("paas_op_spaces_count"),
			HaveKey("paas_op_services_provisioned_count"),
			HaveKey("paas_op_users_count"),
		))
	})

	It("should return CF service metrics", func() {
		Eventually(getMetrics).Should(SatisfyAll(
			HaveKey("paas_op_services_provisioned_count"),
			HaveKey("paas_op_users_count"),
		))
	})

	It("should return CF user metrics", func() {
		Eventually(getMetrics).Should(SatisfyAll(
			HaveKey("paas_op_users_count"),
		))
	})
})
<|endoftext|>


<commit_before>package sqsd

import (
	"log"
	"time"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/awserr"
	"github.com/aws/aws-sdk-go/service/sqs"
)

// An SQSHandler can poll an SQS queue for messages and delete them after
// processing.
type SQSHandler struct {
	QueueURL           string
	MessagesPerRequest int64
	PollWaitSeconds    int64
	SleepDuration      time.Duration

	client *sqs.SQS
}

// NewSQSHandler creates an SQSHandler with default values.
func NewSQSHandler(queueURL string) *SQSHandler {
	return &SQSHandler{
		QueueURL:           queueURL,
		MessagesPerRequest: 10,
		PollWaitSeconds:    20,
		SleepDuration:      10 * time.Second,
		client:             sqs.New(nil),
	}
}

// Poller begins polling the queue, pushing each received message to the
// channel provided.
func (h *SQSHandler) Poller(msgs chan *sqs.Message) {
	params := &sqs.ReceiveMessageInput{
		QueueUrl:              aws.String(h.QueueURL),
		AttributeNames:        []*string{aws.String("All")},
		MaxNumberOfMessages:   aws.Int64(h.MessagesPerRequest),
		MessageAttributeNames: []*string{aws.String("All")},
		WaitTimeSeconds:       aws.Int64(h.PollWaitSeconds),
	}
	for {
		received, err := h.client.ReceiveMessage(params)
		if err != nil {
			if awsErr, ok := err.(awserr.Error); ok {
				log.Printf("Error reading queue: %s", awsErr)
				// TODO: update receive_error metric
				time.Sleep(h.SleepDuration)
			}
		} else {
			if len(received.Messages) == 0 {
				time.Sleep(h.SleepDuration)
			} else {
				for _, msg := range received.Messages {
					msgs <- msg
				}
			}
		}
	}
}

// Deleter deletes each sqs.Message sent to its channel
func (h *SQSHandler) Deleter(msgs chan *sqs.Message) {
	for msg := range msgs {
		_, err := h.client.DeleteMessage(
			&sqs.DeleteMessageInput{
				QueueUrl:      aws.String(h.QueueURL),
				ReceiptHandle: aws.String(*msg.ReceiptHandle),
			},
		)
		if err != nil {
			if awsErr, ok := err.(awserr.Error); ok {
				log.Printf("Error deleting message: %s", awsErr)
				// TODO: update delete_error metric
			}
		}
	}
}
<commit_msg>Fix Runtime Error.<commit_after>package sqsd

import (
	"log"
	"time"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/awserr"
	"github.com/aws/aws-sdk-go/aws/session"
	"github.com/aws/aws-sdk-go/service/sqs"
)

// An SQSHandler can poll an SQS queue for messages and delete them after
// processing.
type SQSHandler struct {
	QueueURL           string
	MessagesPerRequest int64
	PollWaitSeconds    int64
	SleepDuration      time.Duration

	client *sqs.SQS
}

// NewSQSHandler creates an SQSHandler with default values.
func NewSQSHandler(queueURL string) *SQSHandler {
	sess := session.Must(session.NewSessionWithOptions(session.Options {
	        SharedConfigState: session.SharedConfigEnable,
        }))

	return &SQSHandler{
		QueueURL:           queueURL,
		MessagesPerRequest: 10,
		PollWaitSeconds:    20,
		SleepDuration:      10 * time.Second,
		client:             sqs.New(sess),
	}
}

// Poller begins polling the queue, pushing each received message to the
// channel provided.
func (h *SQSHandler) Poller(msgs chan *sqs.Message) {
	params := &sqs.ReceiveMessageInput{
		QueueUrl:              aws.String(h.QueueURL),
		AttributeNames:        []*string{aws.String("All")},
		MaxNumberOfMessages:   aws.Int64(h.MessagesPerRequest),
		MessageAttributeNames: []*string{aws.String("All")},
		WaitTimeSeconds:       aws.Int64(h.PollWaitSeconds),
	}
	for {
		received, err := h.client.ReceiveMessage(params)
		if err != nil {
			if awsErr, ok := err.(awserr.Error); ok {
				log.Printf("Error reading queue: %s", awsErr)
				// TODO: update receive_error metric
				time.Sleep(h.SleepDuration)
			}
		} else {
			if len(received.Messages) == 0 {
				time.Sleep(h.SleepDuration)
			} else {
				for _, msg := range received.Messages {
					msgs <- msg
				}
			}
		}
	}
}

// Deleter deletes each sqs.Message sent to its channel
func (h *SQSHandler) Deleter(msgs chan *sqs.Message) {
	for msg := range msgs {
		_, err := h.client.DeleteMessage(
			&sqs.DeleteMessageInput{
				QueueUrl:      aws.String(h.QueueURL),
				ReceiptHandle: aws.String(*msg.ReceiptHandle),
			},
		)
		if err != nil {
			if awsErr, ok := err.(awserr.Error); ok {
				log.Printf("Error deleting message: %s", awsErr)
				// TODO: update delete_error metric
			}
		}
	}
}
<|endoftext|>


<commit_before>/*
Package stm provides Software Transactional Memory operations for Go. This is
an alternative to the standard way of writing concurrent code (channels and
mutexes). STM makes it easy to perform arbitrarily complex operations in an
atomic fashion. One of its primary advantages over traditional locking is that
STM transactions are composable, whereas locking functions are not -- the
composition will either deadlock or release the lock between functions (making
it non-atomic).

To begin, create an STM object that wraps the data you want to access
concurrently.

	x := stm.NewVar(3)

You can then use the Atomically method to atomically read and/or write the the
data. This code atomically decrements x:

	stm.Atomically(func(tx *stm.Tx) {
		cur := tx.Get(x).(int)
		tx.Set(x, cur-1)
	})

An important part of STM transactions is retrying. At any point during the
transaction, you can call tx.Retry(), which will abort the transaction, but
not cancel it entirely. The call to Atomically will block until another call
to Atomically finishes, at which point the transaction will be rerun.
Specifically, one of the values read by the transaction (via tx.Get) must be
updated before the transaction will be rerun. As an example, this code will
try to decrement x, but will block as long as x is zero:

	stm.Atomically(func(tx *stm.Tx) {
		cur := tx.Get(x).(int)
		if cur == 0 {
			tx.Retry()
		}
		tx.Set(x, cur-1)
	})

Internally, tx.Retry simply calls panic(stm.Retry). Panicking with any other
value will cancel the transaction; no values will be changed. However, it is
the responsibility of the caller to catch such panics.

Multiple transactions can be composed using Select. If the first transaction
calls Retry, the next transaction will be run, and so on. If all of the
transactions call Retry, the call will block and the entire selection will be
retried. For example, this code implements the "decrement-if-nonzero"
transaction above, but for two values. It will first try to decrement x, then
y, and block if both values are zero.

	func dec(v *stm.Var) {
		return func(tx *stm.Tx) {
			cur := tx.Get(v).(int)
			if cur == 0 {
				tx.Retry()
			}
			tx.Set(v, cur-1)
		}
	}

	// Note that Select does not perform any work itself, but merely
	// returns a transaction function.
	stm.Atomically(stm.Select(dec(x), dec(y)))

An important caveat: transactions must be idempotent (they should have the
same effect every time they are invoked). This is because a transaction may be
retried several times before successfully completing, meaning its side effects
may execute more than once. This will almost certainly cause incorrect
behavior. One common way to get around this is to build up a list of impure
operations inside the transaction, and then perform them after the transaction
completes.

The stm API tries to mimic that of Haskell's Control.Concurrent.STM, but this
is not entirely possible due to Go's type system; we are forced to use
interface{} and type assertions. Furthermore, Haskell can enforce at compile
time that STM variables are not modified outside the STM monad. This is not
possible in Go, so be especially careful when using pointers in your STM code.
*/
package stm

import (
	"sync"
	"sync/atomic"
)

// Retry is a sentinel value. When thrown via panic, it indicates that a
// transaction should be retried.
const Retry = "retry"

// The globalLock serializes transaction verification/committal.
var globalLock sync.Mutex
var globalCond = sync.NewCond(&globalLock)

// A Var holds an STM variable.
type Var struct {
	val atomic.Value
}

// NewVar returns a new STM variable.
func NewVar(val interface{}) *Var {
	v := new(Var)
	v.val.Store(val)
	return v
}

// A Tx represents an atomic transaction.
type Tx struct {
	reads  map[*Var]interface{}
	writes map[*Var]interface{}
}

// verify checks that none of the logged values have changed since the
// transaction began.
// TODO: is pointer equality good enough? probably not, without immutable data
func (tx *Tx) verify() bool {
	for v, val := range tx.reads {
		if v.val.Load() != val {
			return false
		}
	}
	return true
}

// commit writes the values in the transaction log to their respective Vars.
func (tx *Tx) commit() {
	for v, val := range tx.writes {
		v.val.Store(val)
	}
}

// wait blocks until another transaction modifies any of the Vars read by tx.
func (tx *Tx) wait() {
	globalCond.L.Lock()
	for tx.verify() {
		globalCond.Wait()
	}
	globalCond.L.Unlock()
}

// Get returns the value of v as of the start of the transaction.
func (tx *Tx) Get(v *Var) interface{} {
	// If we previously wrote to v, it will be in the write log.
	if val, ok := tx.writes[v]; ok {
		return val
	}
	// If we previously read v, it will be in the read log.
	if val, ok := tx.reads[v]; ok {
		return val
	}
	// Otherwise, record and return its current value.
	tx.reads[v] = v.val.Load()
	return tx.reads[v]
}

// Set sets the value of a Var for the lifetime of the transaction.
func (tx *Tx) Set(v *Var, val interface{}) {
	tx.writes[v] = val
}

// Retry aborts the transaction and retries it when a Var changes.
func (tx *Tx) Retry() {
	panic(Retry)
}

// Assert is a helper function that retries a transaction if the condition is
// not satisfied.
func (tx *Tx) Assert(p bool) {
	if !p {
		tx.Retry()
	}
}

// catchRetry returns true if fn calls tx.Retry.
func catchRetry(fn func(*Tx), tx *Tx) (retry bool) {
	defer func() {
		if r := recover(); r == Retry {
			retry = true
		} else if r != nil {
			panic(r)
		}
	}()
	fn(tx)
	return
}

// Select runs the supplied functions in order. Execution stops when a
// function succeeds without calling Retry. If no functions succeed, the
// entire selection will be retried.
func Select(fns ...func(*Tx)) func(*Tx) {
	return func(tx *Tx) {
		switch len(fns) {
		case 0:
			// empty Select blocks forever
			tx.Retry()
		case 1:
			fns[0](tx)
		default:
			if catchRetry(fns[0], tx) {
				Select(fns[1:]...)(tx)
			}
		}
	}
}

// Atomically executes the atomic function fn.
func Atomically(fn func(*Tx)) {
retry:
	// run the transaction
	tx := &Tx{
		reads:  make(map[*Var]interface{}),
		writes: make(map[*Var]interface{}),
	}
	if catchRetry(fn, tx) {
		tx.wait()
		goto retry
	}
	// verify the read log
	globalLock.Lock()
	if !tx.verify() {
		globalLock.Unlock()
		goto retry
	}
	// commit the write log
	tx.commit()
	globalCond.Broadcast()
	globalLock.Unlock()
}

// AtomicGet is a helper function that atomically reads a value.
func AtomicGet(v *Var) interface{} {
	// since we're only doing one operation, we don't need a full transaction
	globalLock.Lock()
	val := v.val.Load()
	globalLock.Unlock()
	return val
}

// AtomicSet is a helper function that atomically writes a value.
func AtomicSet(v *Var, val interface{}) {
	// since we're only doing one operation, we don't need a full transaction
	globalLock.Lock()
	v.val.Store(val)
	globalCond.Broadcast()
	globalLock.Unlock()
}

// Compose is a helper function that composes multiple transactions into a
// single transaction.
func Compose(fns ...func(*Tx)) func(*Tx) {
	return func(tx *Tx) {
		for _, f := range fns {
			f(tx)
		}
	}
}
<commit_msg>only broadcast when at least one Var changed<commit_after>/*
Package stm provides Software Transactional Memory operations for Go. This is
an alternative to the standard way of writing concurrent code (channels and
mutexes). STM makes it easy to perform arbitrarily complex operations in an
atomic fashion. One of its primary advantages over traditional locking is that
STM transactions are composable, whereas locking functions are not -- the
composition will either deadlock or release the lock between functions (making
it non-atomic).

To begin, create an STM object that wraps the data you want to access
concurrently.

	x := stm.NewVar(3)

You can then use the Atomically method to atomically read and/or write the the
data. This code atomically decrements x:

	stm.Atomically(func(tx *stm.Tx) {
		cur := tx.Get(x).(int)
		tx.Set(x, cur-1)
	})

An important part of STM transactions is retrying. At any point during the
transaction, you can call tx.Retry(), which will abort the transaction, but
not cancel it entirely. The call to Atomically will block until another call
to Atomically finishes, at which point the transaction will be rerun.
Specifically, one of the values read by the transaction (via tx.Get) must be
updated before the transaction will be rerun. As an example, this code will
try to decrement x, but will block as long as x is zero:

	stm.Atomically(func(tx *stm.Tx) {
		cur := tx.Get(x).(int)
		if cur == 0 {
			tx.Retry()
		}
		tx.Set(x, cur-1)
	})

Internally, tx.Retry simply calls panic(stm.Retry). Panicking with any other
value will cancel the transaction; no values will be changed. However, it is
the responsibility of the caller to catch such panics.

Multiple transactions can be composed using Select. If the first transaction
calls Retry, the next transaction will be run, and so on. If all of the
transactions call Retry, the call will block and the entire selection will be
retried. For example, this code implements the "decrement-if-nonzero"
transaction above, but for two values. It will first try to decrement x, then
y, and block if both values are zero.

	func dec(v *stm.Var) {
		return func(tx *stm.Tx) {
			cur := tx.Get(v).(int)
			if cur == 0 {
				tx.Retry()
			}
			tx.Set(v, cur-1)
		}
	}

	// Note that Select does not perform any work itself, but merely
	// returns a transaction function.
	stm.Atomically(stm.Select(dec(x), dec(y)))

An important caveat: transactions must be idempotent (they should have the
same effect every time they are invoked). This is because a transaction may be
retried several times before successfully completing, meaning its side effects
may execute more than once. This will almost certainly cause incorrect
behavior. One common way to get around this is to build up a list of impure
operations inside the transaction, and then perform them after the transaction
completes.

The stm API tries to mimic that of Haskell's Control.Concurrent.STM, but this
is not entirely possible due to Go's type system; we are forced to use
interface{} and type assertions. Furthermore, Haskell can enforce at compile
time that STM variables are not modified outside the STM monad. This is not
possible in Go, so be especially careful when using pointers in your STM code.
*/
package stm

import (
	"sync"
	"sync/atomic"
)

// Retry is a sentinel value. When thrown via panic, it indicates that a
// transaction should be retried.
const Retry = "retry"

// The globalLock serializes transaction verification/committal.
var globalLock sync.Mutex
var globalCond = sync.NewCond(&globalLock)

// A Var holds an STM variable.
type Var struct {
	val atomic.Value
}

// NewVar returns a new STM variable.
func NewVar(val interface{}) *Var {
	v := new(Var)
	v.val.Store(val)
	return v
}

// A Tx represents an atomic transaction.
type Tx struct {
	reads  map[*Var]interface{}
	writes map[*Var]interface{}
}

// verify checks that none of the logged values have changed since the
// transaction began.
// TODO: is pointer equality good enough? probably not, without immutable data
func (tx *Tx) verify() bool {
	for v, val := range tx.reads {
		if v.val.Load() != val {
			return false
		}
	}
	return true
}

// commit writes the values in the transaction log to their respective Vars.
func (tx *Tx) commit() {
	for v, val := range tx.writes {
		v.val.Store(val)
	}
}

// wait blocks until another transaction modifies any of the Vars read by tx.
func (tx *Tx) wait() {
	globalCond.L.Lock()
	for tx.verify() {
		globalCond.Wait()
	}
	globalCond.L.Unlock()
}

// Get returns the value of v as of the start of the transaction.
func (tx *Tx) Get(v *Var) interface{} {
	// If we previously wrote to v, it will be in the write log.
	if val, ok := tx.writes[v]; ok {
		return val
	}
	// If we previously read v, it will be in the read log.
	if val, ok := tx.reads[v]; ok {
		return val
	}
	// Otherwise, record and return its current value.
	tx.reads[v] = v.val.Load()
	return tx.reads[v]
}

// Set sets the value of a Var for the lifetime of the transaction.
func (tx *Tx) Set(v *Var, val interface{}) {
	tx.writes[v] = val
}

// Retry aborts the transaction and retries it when a Var changes.
func (tx *Tx) Retry() {
	panic(Retry)
}

// Assert is a helper function that retries a transaction if the condition is
// not satisfied.
func (tx *Tx) Assert(p bool) {
	if !p {
		tx.Retry()
	}
}

// catchRetry returns true if fn calls tx.Retry.
func catchRetry(fn func(*Tx), tx *Tx) (retry bool) {
	defer func() {
		if r := recover(); r == Retry {
			retry = true
		} else if r != nil {
			panic(r)
		}
	}()
	fn(tx)
	return
}

// Select runs the supplied functions in order. Execution stops when a
// function succeeds without calling Retry. If no functions succeed, the
// entire selection will be retried.
func Select(fns ...func(*Tx)) func(*Tx) {
	return func(tx *Tx) {
		switch len(fns) {
		case 0:
			// empty Select blocks forever
			tx.Retry()
		case 1:
			fns[0](tx)
		default:
			if catchRetry(fns[0], tx) {
				Select(fns[1:]...)(tx)
			}
		}
	}
}

// Atomically executes the atomic function fn.
func Atomically(fn func(*Tx)) {
retry:
	// run the transaction
	tx := &Tx{
		reads:  make(map[*Var]interface{}),
		writes: make(map[*Var]interface{}),
	}
	if catchRetry(fn, tx) {
		tx.wait()
		goto retry
	}
	// verify the read log
	globalLock.Lock()
	if !tx.verify() {
		globalLock.Unlock()
		goto retry
	}
	// commit the write log and broadcast that variables have changed
	if len(tx.writes) > 0 {
		tx.commit()
		globalCond.Broadcast()
	}
	globalLock.Unlock()
}

// AtomicGet is a helper function that atomically reads a value.
func AtomicGet(v *Var) interface{} {
	// since we're only doing one operation, we don't need a full transaction
	globalLock.Lock()
	val := v.val.Load()
	globalLock.Unlock()
	return val
}

// AtomicSet is a helper function that atomically writes a value.
func AtomicSet(v *Var, val interface{}) {
	// since we're only doing one operation, we don't need a full transaction
	globalLock.Lock()
	v.val.Store(val)
	globalCond.Broadcast()
	globalLock.Unlock()
}

// Compose is a helper function that composes multiple transactions into a
// single transaction.
func Compose(fns ...func(*Tx)) func(*Tx) {
	return func(tx *Tx) {
		for _, f := range fns {
			f(tx)
		}
	}
}
<|endoftext|>


<commit_before>package web

import(
  "fmt"
  "net/http"
  "net/url"
  "os"
  "io"
  "io/ioutil"
  "crypto/tls"
  "strings"
  "strconv"
  "../arch"
  "../file"
)

var client = &http.Client{}
var nodeBaseAddress = "https://nodejs.org/dist/"
var npmBaseAddress = "https://github.com/npm/npm/archive/"

func SetProxy(p string, verifyssl bool){
  if p != "" && p != "none" {
    proxyUrl, _ := url.Parse(p)
    client = &http.Client{Transport: &http.Transport{Proxy: http.ProxyURL(proxyUrl), TLSClientConfig: &tls.Config{InsecureSkipVerify: verifyssl}}}
  } else {
    client = &http.Client{Transport: &http.Transport{TLSClientConfig: &tls.Config{InsecureSkipVerify: verifyssl}}}
  }
}

func SetMirrors(node_mirror string, npm_mirror string){
  if node_mirror != "" && node_mirror != "none"{
    nodeBaseAddress = node_mirror;
    if strings.ToLower(nodeBaseAddress[0:4]) != "http" {
      nodeBaseAddress = "http://"+nodeBaseAddress
    }
  }
  if npm_mirror != "" && npm_mirror != "none"{
    npmBaseAddress = npm_mirror;
    if strings.ToLower(npmBaseAddress[0:4]) != "http" {
      npmBaseAddress = "http://"+npmBaseAddress
    }
  }
}

func GetFullNodeUrl(path string) string{
  return nodeBaseAddress+ path;
}

func  GetFullNpmUrl(path string) string{
  return npmBaseAddress + path;
}

func Download(url string, target string) bool {

  output, err := os.Create(target)
  if err != nil {
    fmt.Println("Error while creating", target, "-", err)
  }
  defer output.Close()

  response, err := client.Get(url)
  if err != nil {
    fmt.Println("Error while downloading", url, "-", err)
  }
  defer response.Body.Close()

  _, err = io.Copy(output, response.Body)
  if err != nil {
    fmt.Println("Error while downloading", url, "-", err)
  }

  if response.Status[0:3] != "200" {
    fmt.Println("Download failed. Rolling Back.")
    err := os.Remove(target)
    if err != nil {
      fmt.Println("Rollback failed.",err)
    }
    return false
  }

  return true
}

func GetNodeJS(root string, v string, a string) bool {

  a = arch.Validate(a)

  vpre := ""
  vers := strings.Fields(strings.Replace(v,"."," ",-1))
  main, _ := strconv.ParseInt(vers[0],0,0)

  if a == "32" {
    if main > 0 {
      vpre = "win-x86/"
    } else {
      vpre = ""
    }
  } else if a == "64" {
    if main > 0 {
      vpre = "win-x64/"
    } else {
      vpre = "x64/"
    }
  }

  url := getNodeUrl ( v, vpre );

  if url == "" {
    //No url should mean this version/arch isn't available
    fmt.Println("Node.js v"+v+" " + a + "bit isn't available right now.")
  } else {
   fileName := root+"\\v"+v+"\\node"+a+".exe"

    fmt.Printf("Downloading node.js version "+v+" ("+a+"-bit)... ")

    if Download(url,fileName) {
      fmt.Printf("Complete\n")
      return true
    } else {
      return false
    }
  }
  return false

}

func GetNpm(root string, v string) bool {
  //url := "https://github.com/npm/npm/archive/v"+v+".zip"
  url := GetFullNpmUrl("v"+v+".zip")
  // temp directory to download the .zip file
  tempDir := root+"\\temp"

  // if the temp directory doesn't exist, create it
  if (!file.Exists(tempDir)) {
    fmt.Println("Creating "+tempDir+"\n")
    err := os.Mkdir(tempDir, os.ModePerm)
    if err != nil {
      fmt.Println(err)
      os.Exit(1)
    }
  }
  fileName := tempDir+"\\"+"npm-v"+v+".zip"

  fmt.Printf("Downloading npm version "+v+"... ")
  if Download(url,fileName) {
    fmt.Printf("Complete\n")
    return true
  } else {
    return false
  }
}

func GetRemoteTextFile(url string) string {
  response, httperr := client.Get(url)
  if httperr != nil {
    fmt.Println("\nCould not retrieve "+url+".\n\n")
    fmt.Printf("%s", httperr)
    os.Exit(1)
  } else {
    defer response.Body.Close()
    contents, readerr := ioutil.ReadAll(response.Body)
    if readerr != nil {
      fmt.Printf("%s", readerr)
      os.Exit(1)
    }
    return string(contents)
  }
  os.Exit(1)
  return ""
}

func IsNode64bitAvailable(v string) bool {
  if v == "latest" {
    return true
  }

  // Anything below version 8 doesn't have a 64 bit version
  vers := strings.Fields(strings.Replace(v,"."," ",-1))
  main, _ := strconv.ParseInt(vers[0],0,0)
  minor, _ := strconv.ParseInt(vers[1],0,0)
  if main == 0 && minor < 8 {
    return false
  }

  // TODO: fixme. Assume a 64 bit version exists
  return true
}

func getNodeUrl (v string,  vpre string) string {
  //url := "http://nodejs.org/dist/v"+v+"/" + vpre + "/node.exe"
  url := GetFullNodeUrl("v"+v+"/" + vpre + "/node.exe")
  // Check online to see if a 64 bit version exists
  _, err := client.Head( url )
  if err != nil {
    return ""
  }
  return url;
}
<commit_msg>Add cleanup when download is interrupted by user.<commit_after>package web

import(
  "fmt"
  "net/http"
  "net/url"
  "os"
  "os/signal"
  "io"
  "io/ioutil"
	"strings"
	"syscall"
  "crypto/tls"
  "strconv"
  "../arch"
  "../file"
)

var client = &http.Client{}
var nodeBaseAddress = "https://nodejs.org/dist/"
var npmBaseAddress = "https://github.com/npm/npm/archive/"

func SetProxy(p string, verifyssl bool){
  if p != "" && p != "none" {
    proxyUrl, _ := url.Parse(p)
    client = &http.Client{Transport: &http.Transport{Proxy: http.ProxyURL(proxyUrl), TLSClientConfig: &tls.Config{InsecureSkipVerify: verifyssl}}}
  } else {
    client = &http.Client{Transport: &http.Transport{TLSClientConfig: &tls.Config{InsecureSkipVerify: verifyssl}}}
  }
}

func SetMirrors(node_mirror string, npm_mirror string){
  if node_mirror != "" && node_mirror != "none"{
    nodeBaseAddress = node_mirror;
    if strings.ToLower(nodeBaseAddress[0:4]) != "http" {
      nodeBaseAddress = "http://"+nodeBaseAddress
    }
  }
  if npm_mirror != "" && npm_mirror != "none"{
    npmBaseAddress = npm_mirror;
    if strings.ToLower(npmBaseAddress[0:4]) != "http" {
      npmBaseAddress = "http://"+npmBaseAddress
    }
  }
}

func GetFullNodeUrl(path string) string{
  return nodeBaseAddress+ path;
}

func  GetFullNpmUrl(path string) string{
  return npmBaseAddress + path;
}

func Download(url string, target string, version string) bool {

  output, err := os.Create(target)
  if err != nil {
    fmt.Println("Error while creating", target, "-", err)
  }
  defer output.Close()

  response, err := client.Get(url)
  if err != nil {
    fmt.Println("Error while downloading", url, "-", err)
  }
  defer response.Body.Close()
  c := make(chan os.Signal, 2)
	signal.Notify(c, os.Interrupt, syscall.SIGTERM)
	go func() {
		<-c
		fmt.Println("Download interrupted.Rolling back...")
		output.Close()
		response.Body.Close()
		var err error
		if strings.Contains(target, "node") {
			err = os.RemoveAll(os.Getenv("NVM_HOME") + "\\v" + version)
		} else {
			err = os.Remove(target)
		}
		if err != nil {
			fmt.Println("Error while rolling back", err)
		}
		os.Exit(1)
	}()
  _, err = io.Copy(output, response.Body)
  if err != nil {
    fmt.Println("Error while downloading", url, "-", err)
  }
  if response.Status[0:3] != "200" {
    fmt.Println("Download failed. Rolling Back.")
    err := os.Remove(target)
    if err != nil {
      fmt.Println("Rollback failed.",err)
    }
    return false
  }

  return true
}

func GetNodeJS(root string, v string, a string) bool {

  a = arch.Validate(a)

  vpre := ""
  vers := strings.Fields(strings.Replace(v,"."," ",-1))
  main, _ := strconv.ParseInt(vers[0],0,0)

  if a == "32" {
    if main > 0 {
      vpre = "win-x86/"
    } else {
      vpre = ""
    }
  } else if a == "64" {
    if main > 0 {
      vpre = "win-x64/"
    } else {
      vpre = "x64/"
    }
  }

  url := getNodeUrl ( v, vpre );

  if url == "" {
    //No url should mean this version/arch isn't available
    fmt.Println("Node.js v"+v+" " + a + "bit isn't available right now.")
  } else {
   fileName := root+"\\v"+v+"\\node"+a+".exe"

    fmt.Println("Downloading node.js version "+v+" ("+a+"-bit)... ")

    if Download(url,fileName,v) {
      fmt.Printf("Complete\n")
      return true
    } else {
      return false
    }
  }
  return false

}

func GetNpm(root string, v string) bool {
  //url := "https://github.com/npm/npm/archive/v"+v+".zip"
  url := GetFullNpmUrl("v"+v+".zip")
  // temp directory to download the .zip file
  tempDir := root+"\\temp"

  // if the temp directory doesn't exist, create it
  if (!file.Exists(tempDir)) {
    fmt.Println("Creating "+tempDir+"\n")
    err := os.Mkdir(tempDir, os.ModePerm)
    if err != nil {
      fmt.Println(err)
      os.Exit(1)
    }
  }
  fileName := tempDir+"\\"+"npm-v"+v+".zip"

  fmt.Printf("Downloading npm version "+v+"... ")
  if Download(url,fileName,v) {
    fmt.Printf("Complete\n")
    return true
  } else {
    return false
  }
}

func GetRemoteTextFile(url string) string {
  response, httperr := client.Get(url)
  if httperr != nil {
    fmt.Println("\nCould not retrieve "+url+".\n\n")
    fmt.Printf("%s", httperr)
    os.Exit(1)
  } else {
    defer response.Body.Close()
    contents, readerr := ioutil.ReadAll(response.Body)
    if readerr != nil {
      fmt.Printf("%s", readerr)
      os.Exit(1)
    }
    return string(contents)
  }
  os.Exit(1)
  return ""
}

func IsNode64bitAvailable(v string) bool {
  if v == "latest" {
    return true
  }

  // Anything below version 8 doesn't have a 64 bit version
  vers := strings.Fields(strings.Replace(v,"."," ",-1))
  main, _ := strconv.ParseInt(vers[0],0,0)
  minor, _ := strconv.ParseInt(vers[1],0,0)
  if main == 0 && minor < 8 {
    return false
  }

  // TODO: fixme. Assume a 64 bit version exists
  return true
}

func getNodeUrl (v string,  vpre string) string {
  //url := "http://nodejs.org/dist/v"+v+"/" + vpre + "/node.exe"
  url := GetFullNodeUrl("v"+v+"/" + vpre + "/node.exe")
  // Check online to see if a 64 bit version exists
  _, err := client.Head( url )
  if err != nil {
    return ""
  }
  return url;
}
<|endoftext|>


<commit_before>package updatectl

import (
	"flag"
	"fmt"
	"github.com/coreos/updateservicectl/auth"
	"github.com/coreos/updateservicectl/client/update/v1"
	"log"
	"net/http"
	"os"
	"text/tabwriter"
)

const (
	OK = iota
	// Error Codes
	ERROR_API
	ERROR_USAGE
	ERROR_NO_COMMAND

	cliName        = "deisctl"
	cliDescription = "deisctl update is a command line driven interface to the roller."
)

type StringFlag struct {
	value    *string
	required bool
}

func (f *StringFlag) Set(value string) error {
	f.value = &value
	return nil
}

func (f *StringFlag) Get() *string {
	return f.value
}

func (f *StringFlag) String() string {
	if f.value != nil {
		return *f.value
	}
	return ""
}

type Command struct {
	Name        string       // Name of the Command and the string to use to invoke it
	Summary     string       // One-sentence summary of what the Command does
	Usage       string       // Usage options/arguments
	Description string       // Detailed description of command
	Flags       flag.FlagSet // Set of flags associated with this command
	Run         handlerFunc  // Run a command with the given arguments
	Subcommands []*Command   // Subcommands for this command.
}

var (
	out           *tabwriter.Writer
	globalFlagSet *flag.FlagSet
	commands      []*Command
	globalFlags   struct {
		Server        string
		User          string
		Key           string
		Debug         bool
		Version       bool
		Help          bool
		SkipSSLVerify bool
	}
)

func init() {

	out = new(tabwriter.Writer)
	out.Init(os.Stdout, 0, 8, 1, '\t', 0)
	server := "http://localhost:8000" // default server
	if serverEnv := os.Getenv("DEISCTL_SERVER"); serverEnv != "" {
		server = serverEnv
	}

	globalFlagSet = flag.NewFlagSet(cliName, flag.ExitOnError)
	globalFlagSet.StringVar(&globalFlags.Server, "server", server, "Update server to connect to")
	globalFlagSet.BoolVar(&globalFlags.Debug, "debug", false, "Output debugging info to stderr")
	globalFlagSet.BoolVar(&globalFlags.Version, "version", false, "Print version information and exit.")
	globalFlagSet.BoolVar(&globalFlags.Help, "help", false, "Print usage information and exit.")
	globalFlagSet.BoolVar(&globalFlags.SkipSSLVerify, "skip-ssl-verify", false, "Don't check SSL certificates.")
	globalFlagSet.StringVar(&globalFlags.User, "user", os.Getenv("DEISCTL_USER"), "API Username")
	globalFlagSet.StringVar(&globalFlags.Key, "key", os.Getenv("DEISCTL_KEY"), "API Key")

	commands = []*Command{
		cmdInstance,
	}
}

type handlerFunc func([]string, *update.Service, *tabwriter.Writer) int

func getHawkClient(user string, key string) *http.Client {
	return &http.Client{
		Transport: &auth.HawkRoundTripper{
			User:          user,
			Token:         key,
			SkipSSLVerify: globalFlags.SkipSSLVerify,
		},
	}
}

func handle(fn handlerFunc) func(f *flag.FlagSet) int {
	return func(f *flag.FlagSet) (exit int) {
		user := globalFlags.User
		key := globalFlags.Key
		client := getHawkClient(user, key)
		service, err := update.New(client)
		if err != nil {
			log.Fatal(err)
		}
		service.BasePath = globalFlags.Server + "/_ah/api/update/v1/"
		exit = fn(f.Args(), service, out)
		return
	}
}

func getAllFlags() (flags []*flag.Flag) {
	return getFlags(globalFlagSet)
}

func getFlags(flagset *flag.FlagSet) (flags []*flag.Flag) {
	flags = make([]*flag.Flag, 0)
	flagset.VisitAll(func(f *flag.Flag) {
		flags = append(flags, f)
	})
	return
}

// determine which Command should be run
func findCommand(search string, args []string, commands []*Command) (cmd *Command, name string) {
	if len(args) < 1 {
		return
	}
	if search == "" {
		search = args[0]
	} else {
		search = fmt.Sprintf("%s %s", search, args[0])
	}
	name = search
	for _, c := range commands {
		if c.Name == search {
			cmd = c
			if errHelp := c.Flags.Parse(args[1:]); errHelp != nil {
				//printCommandUsage(cmd)
				os.Exit(ERROR_USAGE)
			}
			if len(cmd.Subcommands) != 0 {
				subArgs := cmd.Flags.Args()
				var subCmd *Command
				subCmd, name = findCommand(search, subArgs, cmd.Subcommands)
				if subCmd != nil {
					cmd = subCmd
				}
			}
			break
		}
	}
	return
}

func Update(Args []string) {
	globalFlagSet.Parse(Args)
	var args = globalFlagSet.Args()

	if len(args) < 1 {
		args = append(args, "help")
	}

	cmd, name := findCommand("", args, commands)

	if cmd == nil {
		fmt.Printf("%v: unknown subcommand: %q\n", cliName, name)
		fmt.Printf("Run '%v help' for usage.\n", cliName)
		os.Exit(ERROR_NO_COMMAND)
	}
	if cmd.Run == nil {
		os.Exit(ERROR_USAGE)
	} else {
		exit := handle(cmd.Run)(&cmd.Flags)
		if exit == ERROR_USAGE {
			fmt.Println("Please check the arguments")
		}
		os.Exit(exit)
	}
}
<commit_msg>feat(deisctl): move server env variable to etcd<commit_after>package updatectl

import (
	"flag"
	"fmt"
	"github.com/coreos/updateservicectl/auth"
	"github.com/coreos/updateservicectl/client/update/v1"
	"log"
	"net/http"
	"os"
	"text/tabwriter"
)

const (
	OK = iota
	// Error Codes
	ERROR_API
	ERROR_USAGE
	ERROR_NO_COMMAND

	cliName        = "deisctl"
	cliDescription = "deisctl update is a command line driven interface to the roller."
)

type StringFlag struct {
	value    *string
	required bool
}

func (f *StringFlag) Set(value string) error {
	f.value = &value
	return nil
}

func (f *StringFlag) Get() *string {
	return f.value
}

func (f *StringFlag) String() string {
	if f.value != nil {
		return *f.value
	}
	return ""
}

type Command struct {
	Name        string       // Name of the Command and the string to use to invoke it
	Summary     string       // One-sentence summary of what the Command does
	Usage       string       // Usage options/arguments
	Description string       // Detailed description of command
	Flags       flag.FlagSet // Set of flags associated with this command
	Run         handlerFunc  // Run a command with the given arguments
	Subcommands []*Command   // Subcommands for this command.
}

var (
	out           *tabwriter.Writer
	globalFlagSet *flag.FlagSet
	commands      []*Command
	globalFlags   struct {
		Server        string
		User          string
		Key           string
		Debug         bool
		Version       bool
		Help          bool
		SkipSSLVerify bool
	}
)

func init() {

	out = new(tabwriter.Writer)
	out.Init(os.Stdout, 0, 8, 1, '\t', 0)
	server := "http://localhost:8000" // default server
	if serverEnv := utils.GetKey(constant.UpdatekeyDir, "server", "DEISCTL_SERVER"); serverEnv != "" {
		server = serverEnv
	}

	globalFlagSet = flag.NewFlagSet(cliName, flag.ExitOnError)
	globalFlagSet.StringVar(&globalFlags.Server, "server", server, "Update server to connect to")
	globalFlagSet.BoolVar(&globalFlags.Debug, "debug", false, "Output debugging info to stderr")
	globalFlagSet.BoolVar(&globalFlags.Version, "version", false, "Print version information and exit.")
	globalFlagSet.BoolVar(&globalFlags.Help, "help", false, "Print usage information and exit.")
	globalFlagSet.BoolVar(&globalFlags.SkipSSLVerify, "skip-ssl-verify", false, "Don't check SSL certificates.")
	globalFlagSet.StringVar(&globalFlags.User, "user", os.Getenv("DEISCTL_USER"), "API Username")
	globalFlagSet.StringVar(&globalFlags.Key, "key", os.Getenv("DEISCTL_KEY"), "API Key")

	commands = []*Command{
		cmdInstance,
	}
}

type handlerFunc func([]string, *update.Service, *tabwriter.Writer) int

func getHawkClient(user string, key string) *http.Client {
	return &http.Client{
		Transport: &auth.HawkRoundTripper{
			User:          user,
			Token:         key,
			SkipSSLVerify: globalFlags.SkipSSLVerify,
		},
	}
}

func handle(fn handlerFunc) func(f *flag.FlagSet) int {
	return func(f *flag.FlagSet) (exit int) {
		user := globalFlags.User
		key := globalFlags.Key
		client := getHawkClient(user, key)
		service, err := update.New(client)
		if err != nil {
			log.Fatal(err)
		}
		service.BasePath = globalFlags.Server + "/_ah/api/update/v1/"
		exit = fn(f.Args(), service, out)
		return
	}
}

func getAllFlags() (flags []*flag.Flag) {
	return getFlags(globalFlagSet)
}

func getFlags(flagset *flag.FlagSet) (flags []*flag.Flag) {
	flags = make([]*flag.Flag, 0)
	flagset.VisitAll(func(f *flag.Flag) {
		flags = append(flags, f)
	})
	return
}

// determine which Command should be run
func findCommand(search string, args []string, commands []*Command) (cmd *Command, name string) {
	if len(args) < 1 {
		return
	}
	if search == "" {
		search = args[0]
	} else {
		search = fmt.Sprintf("%s %s", search, args[0])
	}
	name = search
	for _, c := range commands {
		if c.Name == search {
			cmd = c
			if errHelp := c.Flags.Parse(args[1:]); errHelp != nil {
				//printCommandUsage(cmd)
				os.Exit(ERROR_USAGE)
			}
			if len(cmd.Subcommands) != 0 {
				subArgs := cmd.Flags.Args()
				var subCmd *Command
				subCmd, name = findCommand(search, subArgs, cmd.Subcommands)
				if subCmd != nil {
					cmd = subCmd
				}
			}
			break
		}
	}
	return
}

func Update(Args []string) {
	globalFlagSet.Parse(Args)
	var args = globalFlagSet.Args()

	if len(args) < 1 {
		args = append(args, "help")
	}

	cmd, name := findCommand("", args, commands)

	if cmd == nil {
		fmt.Printf("%v: unknown subcommand: %q\n", cliName, name)
		fmt.Printf("Run '%v help' for usage.\n", cliName)
		os.Exit(ERROR_NO_COMMAND)
	}
	if cmd.Run == nil {
		os.Exit(ERROR_USAGE)
	} else {
		exit := handle(cmd.Run)(&cmd.Flags)
		if exit == ERROR_USAGE {
			fmt.Println("Please check the arguments")
		}
		os.Exit(exit)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"io"
	"math"
	"time"

	"github.com/ajstarks/svgo"
)

type margin struct {
	top, right, bottom, left int
}

type size struct {
	width, height int
}

const (
	startFontStyle  = "text-anchor:start;font-size:12px;font-family:Arial,Helvetica"
	middleFontStyle = "text-anchor:middle;font-size:12px;font-family:Arial,Helvetica"
	endFontStyle    = "text-anchor:end;font-size:12px;font-family:Arial,Helvetica"
)

var gridSize = size{6, 10}

func drawCanvas(canvas *svg.SVG, canvasSize size) {
	canvas.Rect(0, 0, canvasSize.width, canvasSize.height,
		"fill:white;stroke:none")
}

func drawXTitle(canvas *svg.SVG, canvasSize, chartInnerSize size, chartMargin margin, timeElapsed time.Duration) {
	var title string

	if timeElapsed.Hours() > 1 {
		title = "Time elapsed, h"
	} else if timeElapsed.Minutes() > 1 {
		title = "Time elapsed, m"
	} else {
		title = "Time elapsed, s"
	}

	canvas.Text(chartMargin.left+chartInnerSize.width/2, canvasSize.height-6,
		title, middleFontStyle)
}

func drawXAxis(canvas *svg.SVG, canvasSize, chartInnerSize size, chartMargin margin, timeElapsed time.Duration) {
	var gridDuration float64

	if timeElapsed.Hours() > 1 {
		gridDuration = timeElapsed.Hours() / float64(gridSize.width)
	} else if timeElapsed.Minutes() > 1 {
		gridDuration = timeElapsed.Minutes() / float64(gridSize.width)
	} else {
		gridDuration = timeElapsed.Seconds() / float64(gridSize.width)
	}

	for i := 0; i <= gridSize.width; i++ {
		tick := fmt.Sprintf("%.1f", float64(i)*gridDuration)
		canvas.Text(chartMargin.left+i*chartInnerSize.width/gridSize.width,
			canvasSize.height-chartMargin.bottom+15,
			tick, middleFontStyle)
	}
}

func drawYTitle(canvas *svg.SVG, canvasSize, chartInnerSize size, chartMargin margin, title string) {
	canvas.Gtransform(fmt.Sprintf("translate(%d,%d) rotate(-90)", 15, chartMargin.top+chartInnerSize.height/2))
	canvas.Text(0, 0, title, middleFontStyle)
	canvas.Gend()
}

func tickFormatter(maxValue float64) string {
	if maxValue > math.Pow(10, 6) {
		return "%.2g"
	} else if maxValue >= math.Pow(10, 3) {
		return "%.0f"
	} else if maxValue < math.Pow(10, -4) {
		return "%.5f"
	} else {
		for power := -3; power < 1; power++ {
			if maxValue <= math.Pow(10, float64(power)) {
				return fmt.Sprintf("%%.%df", int(math.Abs(float64(power)))+2)
			}
		}
	}
	return "%.1f"
}

func drawYAxis(canvas *svg.SVG, canvasSize, chartInnerSize size, chartMargin margin, hm *heatMap) {
	tickFmt := tickFormatter(hm.MaxValue)
	for i := 0; i <= gridSize.height; i++ {
		tickValue := float64(i) * float64(hm.MaxValue) / float64(gridSize.height)
		tick := fmt.Sprintf(tickFmt, tickValue)
		canvas.Text(chartMargin.left-5,
			canvasSize.height-chartMargin.bottom-i*chartInnerSize.height/gridSize.height,
			tick, endFontStyle)
	}
}

func drawGrid(canvas *svg.SVG, chartInnerSize size, chartMargin margin) {
	// Grid
	const gridStyle = "stroke:black;shape-rendering:crispEdges;stroke-dasharray:2,10"

	for i := 1; i <= gridSize.width-1; i++ {
		canvas.Line(chartMargin.left+i*chartInnerSize.width/gridSize.width,
			chartMargin.top,
			chartMargin.left+i*chartInnerSize.width/gridSize.width,
			chartMargin.top+chartInnerSize.height,
			gridStyle)
	}

	for i := 1; i <= gridSize.height-1; i++ {
		canvas.Line(chartMargin.left,
			chartMargin.top+i*chartInnerSize.height/gridSize.height,
			chartMargin.left+chartInnerSize.width,
			chartMargin.top+i*chartInnerSize.height/gridSize.height,
			gridStyle)
	}

	// Border
	const borderStyle = "fill:none;stroke:black;shape-rendering:crispEdges"
	canvas.Rect(chartMargin.left, chartMargin.top,
		chartInnerSize.width, chartInnerSize.height,
		borderStyle)
}

func drawHeatBar(canvas *svg.SVG, chartInnerSize, chartOuterSize, heatBarInnerSize size, chartMargin, heatBarMargin margin, hm *heatMap) {
	var heatBarColor = []svg.Offcolor{
		{0, "#7F2704", 1.0},
		{25, "#D74701", 1.0},
		{50, "#FC8C3B", 1.0},
		{75, "#FDCFA1", 1.0},
		{100, "#FFFFFF", 1.0},
	}
	canvas.LinearGradient("heatBar", 0, 0, 0, 100, heatBarColor)

	canvas.Rect(chartOuterSize.width+heatBarMargin.left, heatBarMargin.top,
		heatBarInnerSize.width, chartInnerSize.height,
		"fill:url(#heatBar);stroke:black;shape-rendering:crispEdges")

	const heatBarTextMargin = 5

	canvas.Text(chartOuterSize.width+heatBarMargin.left+heatBarInnerSize.width+heatBarTextMargin,
		heatBarMargin.top,
		fmt.Sprintf("%d", hm.maxDensity), startFontStyle)

	canvas.Text(chartOuterSize.width+heatBarMargin.left+heatBarInnerSize.width+heatBarTextMargin,
		heatBarMargin.top+heatBarInnerSize.height,
		"0", startFontStyle)
}

func drawHeatMap(canvas *svg.SVG, canvasSize, chartInnerSize size, chartMargin margin, hm *heatMap) {
	const rectStyle = "fill:%s;stroke:%s"

	for i, row := range hm.Map {
		for j, value := range row {
			idx := math.Pow(float64(value)/float64(hm.maxDensity), 0.15)

			if idx > 0 {
				color := orgColorMap[int(255*idx)]
				canvas.Rect(chartMargin.left+j*chartInnerSize.width/len(row),
					canvasSize.height-chartMargin.bottom-(i+1)*chartInnerSize.height/len(hm.Map),
					chartInnerSize.width/len(row),
					chartInnerSize.height/len(hm.Map),
					fmt.Sprintf(rectStyle, color, color))
			}
		}
	}
}

func generateSVG(output io.Writer, hm *heatMap, title string) {
	// Sizes and margins
	var canvasSize = size{1040, 520}

	var chartMargin = margin{20, 5, 40, 80}
	var heatBarMargin = margin{20, 40, 40, 5}

	var heatBarInnerSize = size{
		18,
		canvasSize.height - heatBarMargin.top - heatBarMargin.bottom,
	}

	var heatBarOuterSize = size{
		heatBarMargin.left + heatBarInnerSize.width + heatBarMargin.right,
		heatBarMargin.top + heatBarInnerSize.height + heatBarMargin.bottom,
	}

	var chartInnerSize = size{
		canvasSize.width - chartMargin.left - chartMargin.right - heatBarOuterSize.width,
		canvasSize.height - chartMargin.top - chartMargin.bottom,
	}

	var chartOuterSize = size{
		chartMargin.left + chartInnerSize.width + chartMargin.right,
		chartMargin.top + chartInnerSize.height + chartMargin.bottom,
	}

	// Drawing
	canvas := svg.New(output)
	canvas.Start(canvasSize.width, canvasSize.height)

	drawCanvas(canvas, canvasSize)

	drawHeatMap(canvas, canvasSize, chartInnerSize, chartMargin, hm)

	timeElapsed := time.Duration(hm.MaxTS-hm.MinTS) * 1e6
	drawXTitle(canvas, canvasSize, chartInnerSize, chartMargin, timeElapsed)
	drawXAxis(canvas, canvasSize, chartInnerSize, chartMargin, timeElapsed)

	drawYAxis(canvas, canvasSize, chartInnerSize, chartMargin, hm)
	drawYTitle(canvas, canvasSize, chartInnerSize, chartMargin, title)

	drawGrid(canvas, chartInnerSize, chartMargin)

	drawHeatBar(canvas, chartInnerSize, chartOuterSize, heatBarInnerSize, chartMargin, heatBarMargin, hm)

	canvas.End()
}
<commit_msg>Fix golint issue<commit_after>package main

import (
	"fmt"
	"io"
	"math"
	"time"

	"github.com/ajstarks/svgo"
)

type margin struct {
	top, right, bottom, left int
}

type size struct {
	width, height int
}

const (
	startFontStyle  = "text-anchor:start;font-size:12px;font-family:Arial,Helvetica"
	middleFontStyle = "text-anchor:middle;font-size:12px;font-family:Arial,Helvetica"
	endFontStyle    = "text-anchor:end;font-size:12px;font-family:Arial,Helvetica"
)

var gridSize = size{6, 10}

func drawCanvas(canvas *svg.SVG, canvasSize size) {
	canvas.Rect(0, 0, canvasSize.width, canvasSize.height,
		"fill:white;stroke:none")
}

func drawXTitle(canvas *svg.SVG, canvasSize, chartInnerSize size, chartMargin margin, timeElapsed time.Duration) {
	var title string

	if timeElapsed.Hours() > 1 {
		title = "Time elapsed, h"
	} else if timeElapsed.Minutes() > 1 {
		title = "Time elapsed, m"
	} else {
		title = "Time elapsed, s"
	}

	canvas.Text(chartMargin.left+chartInnerSize.width/2, canvasSize.height-6,
		title, middleFontStyle)
}

func drawXAxis(canvas *svg.SVG, canvasSize, chartInnerSize size, chartMargin margin, timeElapsed time.Duration) {
	var gridDuration float64

	if timeElapsed.Hours() > 1 {
		gridDuration = timeElapsed.Hours() / float64(gridSize.width)
	} else if timeElapsed.Minutes() > 1 {
		gridDuration = timeElapsed.Minutes() / float64(gridSize.width)
	} else {
		gridDuration = timeElapsed.Seconds() / float64(gridSize.width)
	}

	for i := 0; i <= gridSize.width; i++ {
		tick := fmt.Sprintf("%.1f", float64(i)*gridDuration)
		canvas.Text(chartMargin.left+i*chartInnerSize.width/gridSize.width,
			canvasSize.height-chartMargin.bottom+15,
			tick, middleFontStyle)
	}
}

func drawYTitle(canvas *svg.SVG, canvasSize, chartInnerSize size, chartMargin margin, title string) {
	canvas.Gtransform(fmt.Sprintf("translate(%d,%d) rotate(-90)", 15, chartMargin.top+chartInnerSize.height/2))
	canvas.Text(0, 0, title, middleFontStyle)
	canvas.Gend()
}

func tickFormatter(maxValue float64) string {
	if maxValue > math.Pow(10, 6) {
		return "%.2g"
	} else if maxValue >= math.Pow(10, 3) {
		return "%.0f"
	} else if maxValue < math.Pow(10, -4) {
		return "%.5f"
	}

	for power := -3; power < 1; power++ {
		if maxValue <= math.Pow(10, float64(power)) {
			return fmt.Sprintf("%%.%df", int(math.Abs(float64(power)))+2)
		}
	}

	return "%.1f"
}

func drawYAxis(canvas *svg.SVG, canvasSize, chartInnerSize size, chartMargin margin, hm *heatMap) {
	tickFmt := tickFormatter(hm.MaxValue)
	for i := 0; i <= gridSize.height; i++ {
		tickValue := float64(i) * float64(hm.MaxValue) / float64(gridSize.height)
		tick := fmt.Sprintf(tickFmt, tickValue)
		canvas.Text(chartMargin.left-5,
			canvasSize.height-chartMargin.bottom-i*chartInnerSize.height/gridSize.height,
			tick, endFontStyle)
	}
}

func drawGrid(canvas *svg.SVG, chartInnerSize size, chartMargin margin) {
	// Grid
	const gridStyle = "stroke:black;shape-rendering:crispEdges;stroke-dasharray:2,10"

	for i := 1; i <= gridSize.width-1; i++ {
		canvas.Line(chartMargin.left+i*chartInnerSize.width/gridSize.width,
			chartMargin.top,
			chartMargin.left+i*chartInnerSize.width/gridSize.width,
			chartMargin.top+chartInnerSize.height,
			gridStyle)
	}

	for i := 1; i <= gridSize.height-1; i++ {
		canvas.Line(chartMargin.left,
			chartMargin.top+i*chartInnerSize.height/gridSize.height,
			chartMargin.left+chartInnerSize.width,
			chartMargin.top+i*chartInnerSize.height/gridSize.height,
			gridStyle)
	}

	// Border
	const borderStyle = "fill:none;stroke:black;shape-rendering:crispEdges"
	canvas.Rect(chartMargin.left, chartMargin.top,
		chartInnerSize.width, chartInnerSize.height,
		borderStyle)
}

func drawHeatBar(canvas *svg.SVG, chartInnerSize, chartOuterSize, heatBarInnerSize size, chartMargin, heatBarMargin margin, hm *heatMap) {
	var heatBarColor = []svg.Offcolor{
		{0, "#7F2704", 1.0},
		{25, "#D74701", 1.0},
		{50, "#FC8C3B", 1.0},
		{75, "#FDCFA1", 1.0},
		{100, "#FFFFFF", 1.0},
	}
	canvas.LinearGradient("heatBar", 0, 0, 0, 100, heatBarColor)

	canvas.Rect(chartOuterSize.width+heatBarMargin.left, heatBarMargin.top,
		heatBarInnerSize.width, chartInnerSize.height,
		"fill:url(#heatBar);stroke:black;shape-rendering:crispEdges")

	const heatBarTextMargin = 5

	canvas.Text(chartOuterSize.width+heatBarMargin.left+heatBarInnerSize.width+heatBarTextMargin,
		heatBarMargin.top,
		fmt.Sprintf("%d", hm.maxDensity), startFontStyle)

	canvas.Text(chartOuterSize.width+heatBarMargin.left+heatBarInnerSize.width+heatBarTextMargin,
		heatBarMargin.top+heatBarInnerSize.height,
		"0", startFontStyle)
}

func drawHeatMap(canvas *svg.SVG, canvasSize, chartInnerSize size, chartMargin margin, hm *heatMap) {
	const rectStyle = "fill:%s;stroke:%s"

	for i, row := range hm.Map {
		for j, value := range row {
			idx := math.Pow(float64(value)/float64(hm.maxDensity), 0.15)

			if idx > 0 {
				color := orgColorMap[int(255*idx)]
				canvas.Rect(chartMargin.left+j*chartInnerSize.width/len(row),
					canvasSize.height-chartMargin.bottom-(i+1)*chartInnerSize.height/len(hm.Map),
					chartInnerSize.width/len(row),
					chartInnerSize.height/len(hm.Map),
					fmt.Sprintf(rectStyle, color, color))
			}
		}
	}
}

func generateSVG(output io.Writer, hm *heatMap, title string) {
	// Sizes and margins
	var canvasSize = size{1040, 520}

	var chartMargin = margin{20, 5, 40, 80}
	var heatBarMargin = margin{20, 40, 40, 5}

	var heatBarInnerSize = size{
		18,
		canvasSize.height - heatBarMargin.top - heatBarMargin.bottom,
	}

	var heatBarOuterSize = size{
		heatBarMargin.left + heatBarInnerSize.width + heatBarMargin.right,
		heatBarMargin.top + heatBarInnerSize.height + heatBarMargin.bottom,
	}

	var chartInnerSize = size{
		canvasSize.width - chartMargin.left - chartMargin.right - heatBarOuterSize.width,
		canvasSize.height - chartMargin.top - chartMargin.bottom,
	}

	var chartOuterSize = size{
		chartMargin.left + chartInnerSize.width + chartMargin.right,
		chartMargin.top + chartInnerSize.height + chartMargin.bottom,
	}

	// Drawing
	canvas := svg.New(output)
	canvas.Start(canvasSize.width, canvasSize.height)

	drawCanvas(canvas, canvasSize)

	drawHeatMap(canvas, canvasSize, chartInnerSize, chartMargin, hm)

	timeElapsed := time.Duration(hm.MaxTS-hm.MinTS) * 1e6
	drawXTitle(canvas, canvasSize, chartInnerSize, chartMargin, timeElapsed)
	drawXAxis(canvas, canvasSize, chartInnerSize, chartMargin, timeElapsed)

	drawYAxis(canvas, canvasSize, chartInnerSize, chartMargin, hm)
	drawYTitle(canvas, canvasSize, chartInnerSize, chartMargin, title)

	drawGrid(canvas, chartInnerSize, chartMargin)

	drawHeatBar(canvas, chartInnerSize, chartOuterSize, heatBarInnerSize, chartMargin, heatBarMargin, hm)

	canvas.End()
}
<|endoftext|>