<commit_before>// Package icsi provides an interface to the ICSI certificate notary
//
// http://notary.icsi.berkeley.edu/
package icsi

import (
	"bytes"
	"crypto/sha1"
	"crypto/x509"
	"errors"
	"fmt"
	"net"
	"strconv"
	"strings"
	"time"
)

const notaryDomain = "notary.icsi.berkeley.edu"

type Status int

const (
	Unknown Status = iota
	Seen
	Validated
)

var (
	ipSeen      = net.IP{127, 0, 0, 1}
	ipValidated = net.IP{127, 0, 0, 2}

	errInvalidResponse = errors.New("icsi: invalid response")
	errUnknownVersion  = errors.New("icsi: unknown version")
	errMultipleRecords = errors.New("icsi: multiple records")
)

func dnsname(sha []byte) string {
	return fmt.Sprintf("%x.%s", sha, notaryDomain)
}

func isnxdomain(err error) bool {
	if err, ok := err.(*net.DNSError); ok {
		return err.Err == "no such host"
	}
	return false
}

func QueryStatus(hash []byte) (Status, error) {
	ips, err := net.LookupIP(dnsname(hash))
	if err != nil {
		if isnxdomain(err) {
			return Unknown, nil
		}
		return Unknown, err
	}

	if len(ips) != 1 {
		return Unknown, errMultipleRecords
	}
	if bytes.Equal(ips[0], ipSeen) {
		return Seen, nil
	}
	if bytes.Equal(ips[0], ipValidated) {
		return Validated, nil
	}

	return Unknown, nil
}

type Response struct {
	Version   int
	FirstSeen time.Time
	LastSeen  time.Time
	TimesSeen int
	Validated bool
}

func parseDate(s string) (time.Time, error) {
	i, err := strconv.ParseInt(s, 10, 32)
	if err != nil {
		return time.Time{}, err
	}
	return time.Unix(0, 0).UTC().AddDate(0, 0, int(i)), nil
}

func parseResponse(txt string) (*Response, error) {
	var r Response

	tok := strings.Split(txt, " ")
	for _, t := range tok {
		pair := strings.Split(t, "=")
		if len(pair) != 2 {
			return nil, errInvalidResponse
		}
		switch pair[0] {
		case "version":
			i, err := strconv.ParseInt(pair[1], 10, 32)
			if err != nil {
				return nil, errInvalidResponse
			}
			r.Version = int(i)
		case "first_seen":
			t, err := parseDate(pair[1])
			if err != nil {
				return nil, errInvalidResponse
			}
			r.FirstSeen = t
		case "last_seen":
			t, err := parseDate(pair[1])
			if err != nil {
				return nil, errInvalidResponse
			}
			r.LastSeen = t
		case "times_seen":
			i, err := strconv.ParseInt(pair[1], 10, 32)
			if err != nil {
				return nil, errInvalidResponse
			}
			r.TimesSeen = int(i)
		case "validated":
			i, err := strconv.ParseInt(pair[1], 10, 32)
			if err != nil {
				return nil, errInvalidResponse
			}
			r.Validated = i == 1
		}
	}

	if r.Version != 1 {
		return nil, errUnknownVersion
	}

	return &r, nil

}

func Query(hash []byte) (*Response, error) {
	txts, err := net.LookupTXT(dnsname(hash))
	if err != nil {
		if isnxdomain(err) {
			return nil, nil
		}
		return nil, err
	}

	if len(txts) != 1 {
		return nil, errMultipleRecords
	}

	return parseResponse(txts[0])

}

func Hash(cert *x509.Certificate) []byte {
	h := sha1.New()
	h.Write(cert.Raw)
	return h.Sum(nil)
}
<commit_msg>fix ip comparison<commit_after>// Package icsi provides an interface to the ICSI certificate notary
//
// http://notary.icsi.berkeley.edu/
package icsi

import (
	"bytes"
	"crypto/sha1"
	"crypto/x509"
	"errors"
	"fmt"
	"net"
	"strconv"
	"strings"
	"time"
)

const notaryDomain = "notary.icsi.berkeley.edu"

type Status int

const (
	Unknown Status = iota
	Seen
	Validated
)

var (
	ipSeen      = net.IP{127, 0, 0, 1}
	ipValidated = net.IP{127, 0, 0, 2}

	errInvalidResponse = errors.New("icsi: invalid response")
	errUnknownVersion  = errors.New("icsi: unknown version")
	errMultipleRecords = errors.New("icsi: multiple records")
)

func dnsname(sha []byte) string {
	return fmt.Sprintf("%x.%s", sha, notaryDomain)
}

func isnxdomain(err error) bool {
	if err, ok := err.(*net.DNSError); ok {
		return err.Err == "no such host"
	}
	return false
}

func QueryStatus(hash []byte) (Status, error) {
	ips, err := net.LookupIP(dnsname(hash))
	if err != nil {
		if isnxdomain(err) {
			return Unknown, nil
		}
		return Unknown, err
	}

	if len(ips) != 1 {
		return Unknown, errMultipleRecords
	}
	ip := ips[0].To4()
	if bytes.Equal(ip, ipSeen) {
		return Seen, nil
	}
	if bytes.Equal(ip, ipValidated) {
		return Validated, nil
	}

	return Unknown, nil
}

type Response struct {
	Version   int
	FirstSeen time.Time
	LastSeen  time.Time
	TimesSeen int
	Validated bool
}

func parseDate(s string) (time.Time, error) {
	i, err := strconv.ParseInt(s, 10, 32)
	if err != nil {
		return time.Time{}, err
	}
	return time.Unix(0, 0).UTC().AddDate(0, 0, int(i)), nil
}

func parseResponse(txt string) (*Response, error) {
	var r Response

	tok := strings.Split(txt, " ")
	for _, t := range tok {
		pair := strings.Split(t, "=")
		if len(pair) != 2 {
			return nil, errInvalidResponse
		}
		switch pair[0] {
		case "version":
			i, err := strconv.ParseInt(pair[1], 10, 32)
			if err != nil {
				return nil, errInvalidResponse
			}
			r.Version = int(i)
		case "first_seen":
			t, err := parseDate(pair[1])
			if err != nil {
				return nil, errInvalidResponse
			}
			r.FirstSeen = t
		case "last_seen":
			t, err := parseDate(pair[1])
			if err != nil {
				return nil, errInvalidResponse
			}
			r.LastSeen = t
		case "times_seen":
			i, err := strconv.ParseInt(pair[1], 10, 32)
			if err != nil {
				return nil, errInvalidResponse
			}
			r.TimesSeen = int(i)
		case "validated":
			i, err := strconv.ParseInt(pair[1], 10, 32)
			if err != nil {
				return nil, errInvalidResponse
			}
			r.Validated = i == 1
		}
	}

	if r.Version != 1 {
		return nil, errUnknownVersion
	}

	return &r, nil

}

func Query(hash []byte) (*Response, error) {
	txts, err := net.LookupTXT(dnsname(hash))
	if err != nil {
		if isnxdomain(err) {
			return nil, nil
		}
		return nil, err
	}

	if len(txts) != 1 {
		return nil, errMultipleRecords
	}

	return parseResponse(txts[0])

}

func Hash(cert *x509.Certificate) []byte {
	h := sha1.New()
	h.Write(cert.Raw)
	return h.Sum(nil)
}
<|endoftext|>


<commit_before>package notifier

import (
	"bytes"
	"fmt"
	"os"
	"sort"
	"strings"
	"text/template"
	"time"

	"github.com/jinzhu/gorm"
	"github.com/oinume/lekcije/server/config"
	"github.com/oinume/lekcije/server/errors"
	"github.com/oinume/lekcije/server/fetcher"
	"github.com/oinume/lekcije/server/logger"
	"github.com/oinume/lekcije/server/model"
	"github.com/sendgrid/sendgrid-go"
	"github.com/sendgrid/sendgrid-go/helpers/mail"
	"github.com/uber-go/zap"
)

var lessonFetcher *fetcher.TeacherLessonFetcher

func init() {
	lessonFetcher = fetcher.NewTeacherLessonFetcher(nil, logger.AppLogger)
}

type Notifier struct {
	db            *gorm.DB
	dryRun        bool
	lessonService *model.LessonService
	teachers      map[uint32]*model.Teacher
}

func NewNotifier(db *gorm.DB, dryRun bool) *Notifier {
	return &Notifier{
		db:       db,
		dryRun:   dryRun,
		teachers: make(map[uint32]*model.Teacher, 1000),
	}
}

func (n *Notifier) SendNotification(user *model.User) error {
	followingTeacherService := model.NewFollowingTeacherService(n.db)
	n.lessonService = model.NewLessonService(n.db)

	teacherIDs, err := followingTeacherService.FindTeacherIDsByUserID(user.ID)
	if err != nil {
		return errors.Wrapperf(err, "Failed to FindTeacherIDsByUserID(): userID=%v", user.ID)
	}

	availableLessonsPerTeacher := make(map[uint32][]*model.Lesson, 1000)
	allFetchedLessons := make([]*model.Lesson, 0, 5000)
	for _, teacherID := range teacherIDs {
		teacher, fetchedLessons, newAvailableLessons, err := n.fetchAndExtractNewAvailableLessons(teacherID)
		if err != nil {
			return err
		}

		allFetchedLessons = append(allFetchedLessons, fetchedLessons...)
		n.teachers[teacherID] = teacher
		if len(newAvailableLessons) > 0 {
			availableLessonsPerTeacher[teacherID] = newAvailableLessons
		}
	}

	if err := n.sendNotificationToUser(user, availableLessonsPerTeacher); err != nil {
		return err
	}

	if !n.dryRun {
		n.lessonService.UpdateLessons(allFetchedLessons)
	}

	return nil
}

// Returns teacher, fetchedLessons, newAvailableLessons, error
func (n *Notifier) fetchAndExtractNewAvailableLessons(teacherID uint32) (
	*model.Teacher, []*model.Lesson, []*model.Lesson, error,
) {
	teacher, fetchedLessons, err := lessonFetcher.Fetch(teacherID)
	if err != nil {
		// TODO: log?
		logger.AppLogger.Error(
			"TeacherLessonFetcher.Fetch",
			zap.Uint("teacherID", uint(teacherID)), zap.Error(err),
		)
		return nil, nil, nil, err
	}
	logger.AppLogger.Info(
		"TeacherLessonFetcher.Fetch",
		zap.Uint("teacherID", uint(teacher.ID)),
		zap.String("teacherName", teacher.Name),
		zap.Int("fetchedLessons", len(fetchedLessons)),
	)

	//fmt.Printf("fetchedLessons ---\n")
	//for _, l := range fetchedLessons {
	//	fmt.Printf("teacherID=%v, datetime=%v, status=%v\n", l.TeacherId, l.Datetime, l.Status)
	//}

	now := time.Now()
	fromDate := time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, config.LocalTimezone())
	toDate := fromDate.Add(24 * 6 * time.Hour)
	lastFetchedLessons, err := n.lessonService.FindLessons(teacher.ID, fromDate, toDate)
	if err != nil {
		return nil, nil, nil, err
	}
	//fmt.Printf("lastFetchedLessons ---\n")
	//for _, l := range lastFetchedLessons {
	//	fmt.Printf("teacherID=%v, datetime=%v, status=%v\n", l.TeacherId, l.Datetime, l.Status)
	//}

	newAvailableLessons := n.lessonService.GetNewAvailableLessons(lastFetchedLessons, fetchedLessons)
	//fmt.Printf("newAvailableLessons ---\n")
	//for _, l := range newAvailableLessons {
	//	fmt.Printf("teacherID=%v, datetime=%v, status=%v\n", l.TeacherId, l.Datetime, l.Status)
	//}
	return teacher, fetchedLessons, newAvailableLessons, nil
}

func (n *Notifier) sendNotificationToUser(
	user *model.User,
	lessonsPerTeacher map[uint32][]*model.Lesson,
) error {
	lessonsCount := 0
	var teacherIDs []int
	for teacherID, lessons := range lessonsPerTeacher {
		teacherIDs = append(teacherIDs, int(teacherID))
		lessonsCount += len(lessons)
	}
	if lessonsCount == 0 {
		// Don't send notification
		return nil
	}

	sort.Ints(teacherIDs)
	var teacherIDs2 []uint32
	var teacherNames []string
	for _, id := range teacherIDs {
		teacherIDs2 = append(teacherIDs2, uint32(id))
		teacherNames = append(teacherNames, n.teachers[uint32(id)].Name)
	}

	t := template.New("email")
	t = template.Must(t.Parse(getEmailTemplate()))
	type TemplateData struct {
		TeacherIDs        []uint32
		Teachers          map[uint32]*model.Teacher
		LessonsPerTeacher map[uint32][]*model.Lesson
	}
	data := &TemplateData{
		TeacherIDs:        teacherIDs2,
		Teachers:          n.teachers,
		LessonsPerTeacher: lessonsPerTeacher,
	}

	var body bytes.Buffer
	if err := t.Execute(&body, data); err != nil {
		return errors.InternalWrapf(err, "Failed to execute template.")
	}
	//fmt.Printf("--- mail ---\n%s", body.String())

	subject := "[lekcije] Schedule of teacher " + strings.Join(teacherNames, ", ")
	sender := &EmailNotificationSender{}
	return sender.Send(user, subject, body.String())
}

func getEmailTemplate() string {
	return strings.TrimSpace(`
{{- range $teacherID := .TeacherIDs }}
{{- $teacher := index $.Teachers $teacherID -}}
--- Available lessons of {{ $teacher.Name }} ---
PC: http://eikaiwa.dmm.com/teacher/index/{{ $teacherID }}/
Mobile: http://eikaiwa.dmm.com/teacher/schedule/{{ $teacherID }}/

  {{ $lessons := index $.LessonsPerTeacher $teacherID -}}
  {{- range $lesson := $lessons }}
{{ $lesson.Datetime.Format "2006-01-02 15:04" }}
  {{- end }}

{{ end }}
	`)
}

type NotificationSender interface {
	Send(user *model.User, subject, body string) error
}

type EmailNotificationSender struct{}

func (s *EmailNotificationSender) Send(user *model.User, subject, body string) error {
	from := mail.NewEmail("lekcije", "lekcije@lekcije.com")
	to := mail.NewEmail(user.Name, user.Email.Raw())
	content := mail.NewContent("text/html", strings.Replace(body, "\n", "
", -1))
	m := mail.NewV3MailInit(from, subject, to, content)

	req := sendgrid.GetRequest(
		os.Getenv("SENDGRID_API_KEY"),
		"/v3/mail/send",
		"https://api.sendgrid.com",
	)
	req.Method = "POST"
	req.Body = mail.GetRequestBody(m)
	resp, err := sendgrid.API(req)
	if err != nil {
		return errors.InternalWrapf(err, "Failed to send email by sendgrid")
	}
	if resp.StatusCode >= 300 {
		message := fmt.Sprintf(
			"Failed to send email by sendgrid: statusCode=%v, body=%v",
			resp.StatusCode, strings.Replace(resp.Body, "\n", "\\n", -1),
		)
		logger.AppLogger.Error(message)
		return errors.InternalWrapf(
			err,
			"Failed to send email by sendgrid: statusCode=%v",
			resp.StatusCode,
		)
	}

	return nil
}
<commit_msg>Ignore not exising teacher in notifier<commit_after>package notifier

import (
	"bytes"
	"fmt"
	"os"
	"sort"
	"strings"
	"text/template"
	"time"

	"github.com/jinzhu/gorm"
	"github.com/oinume/lekcije/server/config"
	"github.com/oinume/lekcije/server/errors"
	"github.com/oinume/lekcije/server/fetcher"
	"github.com/oinume/lekcije/server/logger"
	"github.com/oinume/lekcije/server/model"
	"github.com/sendgrid/sendgrid-go"
	"github.com/sendgrid/sendgrid-go/helpers/mail"
	"github.com/uber-go/zap"
)

var lessonFetcher *fetcher.TeacherLessonFetcher

func init() {
	lessonFetcher = fetcher.NewTeacherLessonFetcher(nil, logger.AppLogger)
}

type Notifier struct {
	db            *gorm.DB
	dryRun        bool
	lessonService *model.LessonService
	teachers      map[uint32]*model.Teacher
}

func NewNotifier(db *gorm.DB, dryRun bool) *Notifier {
	return &Notifier{
		db:       db,
		dryRun:   dryRun,
		teachers: make(map[uint32]*model.Teacher, 1000),
	}
}

func (n *Notifier) SendNotification(user *model.User) error {
	followingTeacherService := model.NewFollowingTeacherService(n.db)
	n.lessonService = model.NewLessonService(n.db)

	teacherIDs, err := followingTeacherService.FindTeacherIDsByUserID(user.ID)
	if err != nil {
		return errors.Wrapperf(err, "Failed to FindTeacherIDsByUserID(): userID=%v", user.ID)
	}

	availableLessonsPerTeacher := make(map[uint32][]*model.Lesson, 1000)
	allFetchedLessons := make([]*model.Lesson, 0, 5000)
	for _, teacherID := range teacherIDs {
		teacher, fetchedLessons, newAvailableLessons, err := n.fetchAndExtractNewAvailableLessons(teacherID)
		if err != nil {
			switch err.(type) {
			case *errors.NotFound:
				// TODO: update teacher table flag
				logger.AppLogger.Warn("Cannot fetch teacher", zap.Uint("teacherID", uint(teacherID)))
				continue
			default:
				return err
			}
		}

		allFetchedLessons = append(allFetchedLessons, fetchedLessons...)
		n.teachers[teacherID] = teacher
		if len(newAvailableLessons) > 0 {
			availableLessonsPerTeacher[teacherID] = newAvailableLessons
		}
	}

	if err := n.sendNotificationToUser(user, availableLessonsPerTeacher); err != nil {
		return err
	}

	if !n.dryRun {
		n.lessonService.UpdateLessons(allFetchedLessons)
	}

	return nil
}

// Returns teacher, fetchedLessons, newAvailableLessons, error
func (n *Notifier) fetchAndExtractNewAvailableLessons(teacherID uint32) (
	*model.Teacher, []*model.Lesson, []*model.Lesson, error,
) {
	teacher, fetchedLessons, err := lessonFetcher.Fetch(teacherID)
	if err != nil {
		logger.AppLogger.Error(
			"TeacherLessonFetcher.Fetch",
			zap.Uint("teacherID", uint(teacherID)), zap.Error(err),
		)
		return nil, nil, nil, err
	}
	logger.AppLogger.Info(
		"TeacherLessonFetcher.Fetch",
		zap.Uint("teacherID", uint(teacher.ID)),
		zap.String("teacherName", teacher.Name),
		zap.Int("fetchedLessons", len(fetchedLessons)),
	)

	//fmt.Printf("fetchedLessons ---\n")
	//for _, l := range fetchedLessons {
	//	fmt.Printf("teacherID=%v, datetime=%v, status=%v\n", l.TeacherId, l.Datetime, l.Status)
	//}

	now := time.Now()
	fromDate := time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, config.LocalTimezone())
	toDate := fromDate.Add(24 * 6 * time.Hour)
	lastFetchedLessons, err := n.lessonService.FindLessons(teacher.ID, fromDate, toDate)
	if err != nil {
		return nil, nil, nil, err
	}
	//fmt.Printf("lastFetchedLessons ---\n")
	//for _, l := range lastFetchedLessons {
	//	fmt.Printf("teacherID=%v, datetime=%v, status=%v\n", l.TeacherId, l.Datetime, l.Status)
	//}

	newAvailableLessons := n.lessonService.GetNewAvailableLessons(lastFetchedLessons, fetchedLessons)
	//fmt.Printf("newAvailableLessons ---\n")
	//for _, l := range newAvailableLessons {
	//	fmt.Printf("teacherID=%v, datetime=%v, status=%v\n", l.TeacherId, l.Datetime, l.Status)
	//}
	return teacher, fetchedLessons, newAvailableLessons, nil
}

func (n *Notifier) sendNotificationToUser(
	user *model.User,
	lessonsPerTeacher map[uint32][]*model.Lesson,
) error {
	lessonsCount := 0
	var teacherIDs []int
	for teacherID, lessons := range lessonsPerTeacher {
		teacherIDs = append(teacherIDs, int(teacherID))
		lessonsCount += len(lessons)
	}
	if lessonsCount == 0 {
		// Don't send notification
		return nil
	}

	sort.Ints(teacherIDs)
	var teacherIDs2 []uint32
	var teacherNames []string
	for _, id := range teacherIDs {
		teacherIDs2 = append(teacherIDs2, uint32(id))
		teacherNames = append(teacherNames, n.teachers[uint32(id)].Name)
	}

	t := template.New("email")
	t = template.Must(t.Parse(getEmailTemplate()))
	type TemplateData struct {
		TeacherIDs        []uint32
		Teachers          map[uint32]*model.Teacher
		LessonsPerTeacher map[uint32][]*model.Lesson
	}
	data := &TemplateData{
		TeacherIDs:        teacherIDs2,
		Teachers:          n.teachers,
		LessonsPerTeacher: lessonsPerTeacher,
	}

	var body bytes.Buffer
	if err := t.Execute(&body, data); err != nil {
		return errors.InternalWrapf(err, "Failed to execute template.")
	}
	//fmt.Printf("--- mail ---\n%s", body.String())

	subject := "[lekcije] Schedule of teacher " + strings.Join(teacherNames, ", ")
	sender := &EmailNotificationSender{}
	return sender.Send(user, subject, body.String())
}

func getEmailTemplate() string {
	return strings.TrimSpace(`
{{- range $teacherID := .TeacherIDs }}
{{- $teacher := index $.Teachers $teacherID -}}
--- Available lessons of {{ $teacher.Name }} ---
PC: http://eikaiwa.dmm.com/teacher/index/{{ $teacherID }}/
Mobile: http://eikaiwa.dmm.com/teacher/schedule/{{ $teacherID }}/

  {{ $lessons := index $.LessonsPerTeacher $teacherID -}}
  {{- range $lesson := $lessons }}
{{ $lesson.Datetime.Format "2006-01-02 15:04" }}
  {{- end }}

{{ end }}
	`)
}

type NotificationSender interface {
	Send(user *model.User, subject, body string) error
}

type EmailNotificationSender struct{}

func (s *EmailNotificationSender) Send(user *model.User, subject, body string) error {
	from := mail.NewEmail("lekcije", "lekcije@lekcije.com")
	to := mail.NewEmail(user.Name, user.Email.Raw())
	content := mail.NewContent("text/html", strings.Replace(body, "\n", "
", -1))
	m := mail.NewV3MailInit(from, subject, to, content)

	req := sendgrid.GetRequest(
		os.Getenv("SENDGRID_API_KEY"),
		"/v3/mail/send",
		"https://api.sendgrid.com",
	)
	req.Method = "POST"
	req.Body = mail.GetRequestBody(m)
	resp, err := sendgrid.API(req)
	if err != nil {
		return errors.InternalWrapf(err, "Failed to send email by sendgrid")
	}
	if resp.StatusCode >= 300 {
		message := fmt.Sprintf(
			"Failed to send email by sendgrid: statusCode=%v, body=%v",
			resp.StatusCode, strings.Replace(resp.Body, "\n", "\\n", -1),
		)
		logger.AppLogger.Error(message)
		return errors.InternalWrapf(
			err,
			"Failed to send email by sendgrid: statusCode=%v",
			resp.StatusCode,
		)
	}

	return nil
}
<|endoftext|>


<commit_before>package resizer

import (
	"errors"
	"fmt"
	"image"
	"log"
	"os"

	"github.com/VoycerAG/gridfs-image-server/server/paint"
	"github.com/disintegration/imaging"
	"github.com/lazywei/go-opencv/opencv"
)

const (
	//TypeSmartcrop will use magic to find the center of attention
	TypeSmartcrop paint.ResizeType = "smartcrop"
)

var (
	//ErrNoFacesFound this error will be produced if no face could be found in the image
	ErrNoFacesFound = errors.New("No faces found")
)

type subImager interface {
	SubImage(r image.Rectangle) image.Image
}

type smartcropResizer struct {
	haarcascade     string
	fallbackResizer paint.Resizer
}

var nilFallbackResizer paint.Resizer

func normalizeInput(input image.Image, maxSize int) (image.Image, float64, error) {
	var scale float64
	if input.Bounds().Dx() > maxSize {
		scale = float64(input.Bounds().Dx()) / float64(maxSize)
	} else {
		scale = float64(input.Bounds().Dy()) / float64(maxSize)
	}

	log.Printf("Normalizing to %dx%d\n", int(float64(input.Bounds().Dx())/scale), int(float64(input.Bounds().Dy())/scale))
	resized := imaging.Resize(input, int(float64(input.Bounds().Dx())/scale), int(float64(input.Bounds().Dy())/scale), imaging.Lanczos)

	return resized, scale, nil
}

//NewSmartcrop returns a new resizer for the `TypeSmartcrop`
//it needs opencv internally so this resizer
//Warning: will not allow cross compilation
func NewSmartcrop(haarcascade string, fallbackResizer paint.Resizer) paint.Resizer {
	return &smartcropResizer{haarcascade: haarcascade, fallbackResizer: fallbackResizer}
}

//Resize will try to resize via face detection, if no face got found, it will use the fallback resizer
func (s smartcropResizer) Resize(input image.Image, dstWidth, dstHeight int) (image.Image, error) {
	res, err := s.smartResize(input, dstWidth, dstHeight)
	if err != nil {
		if err == ErrNoFacesFound {
			return s.fallbackResizer.Resize(input, dstWidth, dstHeight)
		}

		return nil, err
	}

	return res, err
}

func (s smartcropResizer) smartResize(input image.Image, dstWidth, dstHeight int) (image.Image, error) {
	if dstWidth < 0 || dstHeight < 0 {
		return nil, fmt.Errorf("Please specify both width and height for your target image")
	}

	scaledInput, scale, err := normalizeInput(input, 1024)
	if err != nil {
		return input, err
	}

	cvImage := opencv.FromImage(scaledInput)
	_, err = os.Stat(s.haarcascade)
	if err != nil {
		return input, err
	}

	cascade := opencv.LoadHaarClassifierCascade(s.haarcascade)
	faces := cascade.DetectObjects(cvImage)

	if len(faces) == 0 {
		return nil, ErrNoFacesFound
	}

	var biggestFace *opencv.Rect

	for _, f := range faces {
		if biggestFace == nil {
			biggestFace = f
			continue
		}

		biggestArea := biggestFace.Width() * biggestFace.Height()
		currentArea := f.Width() * f.Height()
		if biggestArea < currentArea {
			biggestFace = f
		}
	}

	log.Printf("Faces found %d\n", len(faces))

	if biggestFace == nil {
		return nil, ErrNoFacesFound
	}

	if sub, ok := input.(subImager); ok {
		x := int(float64(biggestFace.X()) * scale)
		y := int(float64(biggestFace.Y()) * scale)
		width := int(float64(biggestFace.Width()) * scale)
		height := int(float64(biggestFace.Height()) * scale)

		facePoint := image.Pt(x, y)
		target := image.Rect(0, 0, int(float64(dstWidth)*scale), int(float64(dstHeight)*scale))
		r := image.Rect(x, y, x+width, y+height).Add(facePoint)
		for !r.In(target) && r.Min.X > 0 && r.Min.Y > 0 {
			r = image.Rect(r.Min.X-1, r.Min.Y-1, r.Max.X+1, r.Max.Y+1)
		}

		cropImage := sub.SubImage(r)
		return imaging.Thumbnail(cropImage, dstWidth, dstHeight, imaging.Lanczos), nil
	}

	return input, err
}
<commit_msg>Always use fallback on error case<commit_after>package resizer

import (
	"errors"
	"fmt"
	"image"
	"log"
	"os"

	"github.com/VoycerAG/gridfs-image-server/server/paint"
	"github.com/disintegration/imaging"
	"github.com/lazywei/go-opencv/opencv"
)

const (
	//TypeSmartcrop will use magic to find the center of attention
	TypeSmartcrop paint.ResizeType = "smartcrop"
)

var (
	//ErrNoFacesFound this error will be produced if no face could be found in the image
	ErrNoFacesFound = errors.New("No faces found")
)

type subImager interface {
	SubImage(r image.Rectangle) image.Image
}

type smartcropResizer struct {
	haarcascade     string
	fallbackResizer paint.Resizer
}

var nilFallbackResizer paint.Resizer

func normalizeInput(input image.Image, maxSize int) (image.Image, float64, error) {
	var scale float64
	if input.Bounds().Dx() > maxSize {
		scale = float64(input.Bounds().Dx()) / float64(maxSize)
	} else {
		scale = float64(input.Bounds().Dy()) / float64(maxSize)
	}

	log.Printf("Normalizing to %dx%d\n", int(float64(input.Bounds().Dx())/scale), int(float64(input.Bounds().Dy())/scale))
	resized := imaging.Resize(input, int(float64(input.Bounds().Dx())/scale), int(float64(input.Bounds().Dy())/scale), imaging.Lanczos)

	return resized, scale, nil
}

//NewSmartcrop returns a new resizer for the `TypeSmartcrop`
//it needs opencv internally so this resizer
//Warning: will not allow cross compilation
func NewSmartcrop(haarcascade string, fallbackResizer paint.Resizer) paint.Resizer {
	return &smartcropResizer{haarcascade: haarcascade, fallbackResizer: fallbackResizer}
}

//Resize will try to resize via face detection, if no face got found, it will use the fallback resizer
func (s smartcropResizer) Resize(input image.Image, dstWidth, dstHeight int) (image.Image, error) {
	res, err := s.smartResize(input, dstWidth, dstHeight)
	if err != nil {
		if err != ErrNoFacesFound {
			log.Printf("Unexpected error %s\n", err.Error())
		}

		return s.fallbackResizer.Resize(input, dstWidth, dstHeight)
	}

	return res, err
}

func (s smartcropResizer) smartResize(input image.Image, dstWidth, dstHeight int) (image.Image, error) {
	if dstWidth < 0 || dstHeight < 0 {
		return nil, fmt.Errorf("Please specify both width and height for your target image")
	}

	scaledInput, scale, err := normalizeInput(input, 1024)
	if err != nil {
		return input, err
	}

	cvImage := opencv.FromImage(scaledInput)
	_, err = os.Stat(s.haarcascade)
	if err != nil {
		return input, err
	}

	cascade := opencv.LoadHaarClassifierCascade(s.haarcascade)
	faces := cascade.DetectObjects(cvImage)

	if len(faces) == 0 {
		return nil, ErrNoFacesFound
	}

	var biggestFace *opencv.Rect

	for _, f := range faces {
		if biggestFace == nil {
			biggestFace = f
			continue
		}

		biggestArea := biggestFace.Width() * biggestFace.Height()
		currentArea := f.Width() * f.Height()
		if biggestArea < currentArea {
			biggestFace = f
		}
	}

	log.Printf("Faces found %d\n", len(faces))

	if biggestFace == nil {
		return nil, ErrNoFacesFound
	}

	if sub, ok := input.(subImager); ok {
		x := int(float64(biggestFace.X()) * scale)
		y := int(float64(biggestFace.Y()) * scale)
		width := int(float64(biggestFace.Width()) * scale)
		height := int(float64(biggestFace.Height()) * scale)

		facePoint := image.Pt(x, y)
		target := image.Rect(0, 0, int(float64(dstWidth)*scale), int(float64(dstHeight)*scale))
		r := image.Rect(x, y, x+width, y+height).Add(facePoint)
		for !r.In(target) && r.Min.X > 0 && r.Min.Y > 0 {
			r = image.Rect(r.Min.X-1, r.Min.Y-1, r.Max.X+1, r.Max.Y+1)
		}

		cropImage := sub.SubImage(r)
		return imaging.Thumbnail(cropImage, dstWidth, dstHeight, imaging.Lanczos), nil
	}

	return input, err
}
<|endoftext|>


<commit_before>package ltsv

import (
	"bytes"
	"io"
	"testing"
)

type readerTest struct {
	value   string
	records []map[string]string
}

var readerTests = []readerTest{
	{
		`host:127.0.0.1	ident:-	user:frank	time:[10/Oct/2000:13:55:36 -0700]	req:GET /apache_pb.gif

HTTP/1.0	status:200	size:2326	referer:http://www.example.com/start.html	ua:Mozilla/4.08 [en] (Win98; I ;Nav)
`,
		[]map[string]string{
			{"host": "127.0.0.1", "ident": "-", "user": "frank", "time": "[10/Oct/2000:13:55:36 -0700]", "req": "GET /apache_pb.gif"},
			{"status": "200", "size": "2326", "referer": "http://www.example.com/start.html", "ua": "Mozilla/4.08 [en] (Win98; I ;Nav)"},
		},
	},
	{
		` trimspace :こんにちは
		 trim space :こんばんは
日本語:ラベル
nolabelnofield
ha,s.p-un_ct: おはよう `,
		[]map[string]string{
			{"trimspace": "こんにちは"},
			{"trim space": "こんばんは"},
			{"日本語": "ラベル"},
			{"ha,s.p-un_ct": " おはよう "},
		},
	},
	{
		`label:こんにちは	こんばんは
label:こんにちは
こんばんは`,
		[]map[string]string{
			{"label": "こんにちは"},
			{"label": "こんにちは"},
		},
	},
}

func TestReaderRead(t *testing.T) {
	for n, test := range readerTests {
		reader := NewReader(bytes.NewBufferString(test.value))
		for i, result := range test.records {
			record, err := reader.Read()
			if err != nil {
				t.Errorf("error %v at test %d, line %d", err, n, i)
			}
			for label, field := range result {
				if record[label] != field {
					t.Errorf("wrong field %v at test %d, line %d, label %s, field %s", record[label], n, i, label, field)
				}
			}
			if len(result) != len(record) {
				t.Errorf("wrong size of record %d at test %d, line %d", len(record), n, i)
			}
		}
		_, err := reader.Read()
		if err == nil || err != io.EOF {
			t.Errorf("expected EOF got %v at test %d", err, n)
		}
	}
}

func TestWriterWrite(t *testing.T) {
	var buf bytes.Buffer
	for n, test := range readerTests {
		buf.Reset()
		writer := NewWriter(&buf)
		for i, record := range test.records {
			err := writer.Write(record)
			if err != nil {
				t.Errorf("error %v at test %d, line %d", err, n, i)
			}
		}
		writer.Flush()

		reader := NewReader(&buf)
		records, err := reader.ReadAll()
		if err != nil {
			t.Errorf("error %v at test %d", err, n)
			continue
		}
		if len(records) != len(test.records) {
			t.Errorf("wrong size of records %d at test %d", len(records), n)
		} else {
			for i := 0; i < len(test.records); i++ {
				record := records[i]
				result := test.records[i]
				for label, field := range result {
					if field != record[label] {
						t.Errorf("wrong field %s at test %d, line %d, label %s, field %s", record[label], n, i, label, field)
					}
				}
			}
		}
	}
}
<commit_msg>add tests for Reader.ReadAll<commit_after>package ltsv

import (
	"bytes"
	"io"
	"testing"
)

type readerTest struct {
	value   string
	records []map[string]string
}

var readerTests = []readerTest{
	{
		`host:127.0.0.1	ident:-	user:frank	time:[10/Oct/2000:13:55:36 -0700]	req:GET /apache_pb.gif

HTTP/1.0	status:200	size:2326	referer:http://www.example.com/start.html	ua:Mozilla/4.08 [en] (Win98; I ;Nav)
`,
		[]map[string]string{
			{"host": "127.0.0.1", "ident": "-", "user": "frank", "time": "[10/Oct/2000:13:55:36 -0700]", "req": "GET /apache_pb.gif"},
			{"status": "200", "size": "2326", "referer": "http://www.example.com/start.html", "ua": "Mozilla/4.08 [en] (Win98; I ;Nav)"},
		},
	},
	{
		` trimspace :こんにちは
		 trim space :こんばんは
日本語:ラベル
nolabelnofield
ha,s.p-un_ct: おはよう `,
		[]map[string]string{
			{"trimspace": "こんにちは"},
			{"trim space": "こんばんは"},
			{"日本語": "ラベル"},
			{"ha,s.p-un_ct": " おはよう "},
		},
	},
	{
		`label:こんにちは	こんばんは
label2:こんばんは
こんにちは`,
		[]map[string]string{
			{"label": "こんにちは"},
			{"label2": "こんばんは"},
		},
	},
}

func TestReaderRead(t *testing.T) {
	for n, test := range readerTests {
		reader := NewReader(bytes.NewBufferString(test.value))
		for i, result := range test.records {
			record, err := reader.Read()
			if err != nil {
				t.Errorf("error %v at test %d, line %d", err, n, i)
			}
			for label, field := range result {
				if record[label] != field {
					t.Errorf("wrong field %v at test %d, line %d, label %s, field %s", record[label], n, i, label, field)
				}
			}
			if len(result) != len(record) {
				t.Errorf("wrong size of record %d at test %d, line %d", len(record), n, i)
			}
		}
		_, err := reader.Read()
		if err == nil || err != io.EOF {
			t.Errorf("expected EOF got %v at test %d", err, n)
		}
	}
}

func TestReaderReadAll(t *testing.T) {
	for n, test := range readerTests {
		reader := NewReader(bytes.NewBufferString(test.value))
		records, err := reader.ReadAll()
		if err != nil {
			t.Errorf("error %v at test %d", err, n)
		}
		if len(test.records) != len(records) {
			t.Errorf("wrong size of records %d at test %d", len(records), n)
		} else {
			for i, result := range test.records {
				record := records[i]
				for label, field := range result {
					if record[label] != field {
						t.Errorf("wrong field %v at test %d, line %d, label %s, field %s", record[label], n, i, label, field)
					}
				}
				if len(result) != len(record) {
					t.Errorf("wrong size of record %d at test %d, line %d", len(record), n, i)
				}
			}
		}
	}
}

func TestWriterWrite(t *testing.T) {
	var buf bytes.Buffer
	for n, test := range readerTests {
		buf.Reset()
		writer := NewWriter(&buf)
		for i, record := range test.records {
			err := writer.Write(record)
			if err != nil {
				t.Errorf("error %v at test %d, line %d", err, n, i)
			}
		}
		writer.Flush()

		reader := NewReader(&buf)
		records, err := reader.ReadAll()
		if err != nil {
			t.Errorf("error %v at test %d", err, n)
			continue
		}
		if len(records) != len(test.records) {
			t.Errorf("wrong size of records %d at test %d", len(records), n)
		} else {
			for i := 0; i < len(test.records); i++ {
				record := records[i]
				result := test.records[i]
				for label, field := range result {
					if field != record[label] {
						t.Errorf("wrong field %s at test %d, line %d, label %s, field %s", record[label], n, i, label, field)
					}
				}
			}
		}
	}
}
<|endoftext|>


<commit_before>package aws

import (
	"fmt"
	"log"

	"github.com/hashicorp/terraform/helper/schema"

	"github.com/hashicorp/aws-sdk-go/aws"
	"github.com/hashicorp/aws-sdk-go/gen/s3"
)

func resourceAwsS3Bucket() *schema.Resource {
	return &schema.Resource{
		Create: resourceAwsS3BucketCreate,
		Read:   resourceAwsS3BucketRead,
		Delete: resourceAwsS3BucketDelete,

		Schema: map[string]*schema.Schema{
			"bucket": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
			},

			"acl": &schema.Schema{
				Type:     schema.TypeString,
				Default:  "private",
				Optional: true,
				ForceNew: true,
			},
		},
	}
}

func resourceAwsS3BucketCreate(d *schema.ResourceData, meta interface{}) error {
	s3conn := meta.(*AWSClient).s3conn
	awsRegion := meta.(*AWSClient).region

	// Get the bucket and acl
	bucket := d.Get("bucket").(string)
	acl := d.Get("acl").(string)

	log.Printf("[DEBUG] S3 bucket create: %s, ACL: %s", bucket, acl)

	req := &s3.CreateBucketRequest{
		Bucket: aws.String(bucket),
		ACL:    aws.String(acl),
		CreateBucketConfiguration: &s3.CreateBucketConfiguration{
			LocationConstraint: aws.String(awsRegion),
		},
	}

	_, err := s3conn.CreateBucket(req)
	if err != nil {
		return fmt.Errorf("Error creating S3 bucket: %s", err)
	}

	// Assign the bucket name as the resource ID
	d.SetId(bucket)

	return nil
}

func resourceAwsS3BucketRead(d *schema.ResourceData, meta interface{}) error {
	s3conn := meta.(*AWSClient).s3conn

	err := s3conn.HeadBucket(&s3.HeadBucketRequest{
		Bucket: aws.String(d.Id()),
	})
	if err != nil {
		return err
	}
	return nil
}

func resourceAwsS3BucketDelete(d *schema.ResourceData, meta interface{}) error {
	s3conn := meta.(*AWSClient).s3conn

	log.Printf("[DEBUG] S3 Delete Bucket: %s", d.Id())
	err := s3conn.DeleteBucket(&s3.DeleteBucketRequest{
		Bucket: aws.String(d.Id()),
	})
	if err != nil {
		return err
	}
	return nil
}
<commit_msg>provider/aws: Special case us-east-1 for S3 bucket creation.<commit_after>package aws

import (
	"fmt"
	"log"

	"github.com/hashicorp/terraform/helper/schema"

	"github.com/hashicorp/aws-sdk-go/aws"
	"github.com/hashicorp/aws-sdk-go/gen/s3"
)

func resourceAwsS3Bucket() *schema.Resource {
	return &schema.Resource{
		Create: resourceAwsS3BucketCreate,
		Read:   resourceAwsS3BucketRead,
		Delete: resourceAwsS3BucketDelete,

		Schema: map[string]*schema.Schema{
			"bucket": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
			},

			"acl": &schema.Schema{
				Type:     schema.TypeString,
				Default:  "private",
				Optional: true,
				ForceNew: true,
			},
		},
	}
}

func resourceAwsS3BucketCreate(d *schema.ResourceData, meta interface{}) error {
	s3conn := meta.(*AWSClient).s3conn
	awsRegion := meta.(*AWSClient).region

	// Get the bucket and acl
	bucket := d.Get("bucket").(string)
	acl := d.Get("acl").(string)

	log.Printf("[DEBUG] S3 bucket create: %s, ACL: %s", bucket, acl)

	req := &s3.CreateBucketRequest{
		Bucket: aws.String(bucket),
		ACL:    aws.String(acl),
	}

	// Special case us-east-1 region and do not set the LocationConstraint.
	// See "Request Elements: http://docs.aws.amazon.com/AmazonS3/latest/API/RESTBucketPUT.html
	if awsRegion != "us-east-1" {
		req.CreateBucketConfiguration = &s3.CreateBucketConfiguration{
			LocationConstraint: aws.String(awsRegion),
		}
	}

	_, err := s3conn.CreateBucket(req)
	if err != nil {
		return fmt.Errorf("Error creating S3 bucket: %s", err)
	}

	// Assign the bucket name as the resource ID
	d.SetId(bucket)

	return nil
}

func resourceAwsS3BucketRead(d *schema.ResourceData, meta interface{}) error {
	s3conn := meta.(*AWSClient).s3conn

	err := s3conn.HeadBucket(&s3.HeadBucketRequest{
		Bucket: aws.String(d.Id()),
	})
	if err != nil {
		return err
	}
	return nil
}

func resourceAwsS3BucketDelete(d *schema.ResourceData, meta interface{}) error {
	s3conn := meta.(*AWSClient).s3conn

	log.Printf("[DEBUG] S3 Delete Bucket: %s", d.Id())
	err := s3conn.DeleteBucket(&s3.DeleteBucketRequest{
		Bucket: aws.String(d.Id()),
	})
	if err != nil {
		return err
	}
	return nil
}
<|endoftext|>


<commit_before>package heroku

import (
	"fmt"
	"log"

	"github.com/cyberdelia/heroku-go/v3"
	"github.com/hashicorp/terraform/helper/multierror"
	"github.com/hashicorp/terraform/helper/schema"
)

// type application is used to store all the details of a heroku app
type application struct {
	Id string // Id of the resource

	App    *heroku.App       // The heroku application
	Client *heroku.Service   // Client to interact with the heroku API
	Vars   map[string]string // The vars on the application
}

// Updates the application to have the latest from remote
func (a *application) Update() error {
	var errs []error
	var err error

	a.App, err = a.Client.AppInfo(a.Id)
	if err != nil {
		errs = append(errs, err)
	}

	a.Vars, err = retrieve_config_vars(a.Id, a.Client)
	if err != nil {
		errs = append(errs, err)
	}

	if len(errs) > 0 {
		return &multierror.Error{Errors: errs}
	}

	return nil
}

func resourceHerokuApp() *schema.Resource {
	return &schema.Resource{
		Create: switchHerokuAppCreate,
		Read:   resourceHerokuAppRead,
		Update: resourceHerokuAppUpdate,
		Delete: resourceHerokuAppDelete,

		Schema: map[string]*schema.Schema{
			"name": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
			},

			"region": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
			},

			"stack": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				Computed: true,
				ForceNew: true,
			},

			"config_vars": &schema.Schema{
				Type:     schema.TypeList,
				Optional: true,
				Elem: &schema.Schema{
					Type: schema.TypeMap,
				},
			},

			"all_config_vars": &schema.Schema{
				Type:     schema.TypeMap,
				Computed: true,
			},

			"git_url": &schema.Schema{
				Type:     schema.TypeString,
				Computed: true,
			},

			"web_url": &schema.Schema{
				Type:     schema.TypeString,
				Computed: true,
			},

			"heroku_hostname": &schema.Schema{
				Type:     schema.TypeString,
				Computed: true,
			},

			"organization": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				ForceNew: true,
			},
		},
	}
}

func switchHerokuAppCreate(d *schema.ResourceData, meta interface{}) error {
	if _, ok := d.GetOk("organization"); ok {
		return resourceHerokuOrgAppCreate(d, meta)
	} else {
		return resourceHerokuAppCreate(d, meta)
	}
}

func resourceHerokuAppCreate(d *schema.ResourceData, meta interface{}) error {
	client := meta.(*heroku.Service)

	// Build up our creation options
	opts := heroku.AppCreateOpts{}

	if v := d.Get("name"); v != nil {
		vs := v.(string)
		log.Printf("[DEBUG] App name: %s", vs)
		opts.Name = &vs
	}
	if v := d.Get("region"); v != nil {
		vs := v.(string)
		log.Printf("[DEBUG] App region: %s", vs)
		opts.Region = &vs
	}
	if v := d.Get("stack"); v != nil {
		vs := v.(string)
		log.Printf("[DEBUG] App stack: %s", vs)
		opts.Stack = &vs
	}

	log.Printf("[DEBUG] Creating Heroku app...")
	a, err := client.AppCreate(opts)
	if err != nil {
		return err
	}

	d.SetId(a.Name)
	log.Printf("[INFO] App ID: %s", d.Id())

	if v := d.Get("config_vars"); v != nil {
		err = update_config_vars(d.Id(), client, nil, v.([]interface{}))
		if err != nil {
			return err
		}
	}

	return resourceHerokuAppRead(d, meta)
}

func resourceHerokuOrgAppCreate(d *schema.ResourceData, meta interface{}) error {
	client := meta.(*heroku.Service)
	// Build up our creation options
	opts := heroku.OrganizationAppCreateOpts{}
	if v := d.Get("organization"); v != nil {
		vs := v.(string)
		log.Printf("[DEBUG] App name: %s", vs)
		opts.Organization = &vs
	}
	if v := d.Get("name"); v != nil {
		vs := v.(string)
		log.Printf("[DEBUG] App name: %s", vs)
		opts.Name = &vs
	}
	if v := d.Get("region"); v != nil {
		vs := v.(string)
		log.Printf("[DEBUG] App region: %s", vs)
		opts.Region = &vs
	}
	if v := d.Get("stack"); v != nil {
		vs := v.(string)
		log.Printf("[DEBUG] App stack: %s", vs)
		opts.Stack = &vs
	}

	log.Printf("[DEBUG] Creating Heroku app...")
	a, err := client.OrganizationAppCreate(opts)
	if err != nil {
		return err
	}

	d.SetId(a.Name)
	log.Printf("[INFO] App ID: %s", d.Id())

	if v := d.Get("config_vars"); v != nil {
		err = update_config_vars(d.Id(), client, nil, v.([]interface{}))
		if err != nil {
			return err
		}
	}

	return resourceHerokuAppRead(d, meta)
}

func resourceHerokuAppRead(d *schema.ResourceData, meta interface{}) error {
	client := meta.(*heroku.Service)
	app, err := resource_heroku_app_retrieve(d.Id(), client)
	if err != nil {
		return err
	}

	// Only set the config_vars that we have set in the configuration.
	// The "all_config_vars" field has all of them.
	configVars := make(map[string]string)
	care := make(map[string]struct{})
	for _, v := range d.Get("config_vars").([]interface{}) {
		for k, _ := range v.(map[string]interface{}) {
			care[k] = struct{}{}
		}
	}
	for k, v := range app.Vars {
		if _, ok := care[k]; ok {
			configVars[k] = v
		}
	}
	var configVarsValue []map[string]string
	if len(configVars) > 0 {
		configVarsValue = []map[string]string{configVars}
	}

	d.Set("name", app.App.Name)
	d.Set("stack", app.App.Stack.Name)
	d.Set("region", app.App.Region.Name)
	d.Set("git_url", app.App.GitURL)
	d.Set("web_url", app.App.WebURL)
	d.Set("config_vars", configVarsValue)
	d.Set("all_config_vars", app.Vars)

	// We know that the hostname on heroku will be the name+herokuapp.com
	// You need this to do things like create DNS CNAME records
	d.Set("heroku_hostname", fmt.Sprintf("%s.herokuapp.com", app.App.Name))

	return nil
}

func resourceHerokuAppUpdate(d *schema.ResourceData, meta interface{}) error {
	client := meta.(*heroku.Service)

	// If name changed, update it
	if d.HasChange("name") {
		v := d.Get("name").(string)
		opts := heroku.AppUpdateOpts{
			Name: &v,
		}

		renamedApp, err := client.AppUpdate(d.Id(), opts)
		if err != nil {
			return err
		}

		// Store the new ID
		d.SetId(renamedApp.Name)
	}

	// If the config vars changed, then recalculate those
	if d.HasChange("config_vars") {
		o, n := d.GetChange("config_vars")
		if o == nil {
			o = []interface{}{}
		}
		if n == nil {
			n = []interface{}{}
		}

		err := update_config_vars(
			d.Id(), client, o.([]interface{}), n.([]interface{}))
		if err != nil {
			return err
		}
	}

	return resourceHerokuAppRead(d, meta)
}

func resourceHerokuAppDelete(d *schema.ResourceData, meta interface{}) error {
	client := meta.(*heroku.Service)

	log.Printf("[INFO] Deleting App: %s", d.Id())
	err := client.AppDelete(d.Id())
	if err != nil {
		return fmt.Errorf("Error deleting App: %s", err)
	}

	d.SetId("")
	return nil
}

func resource_heroku_app_retrieve(id string, client *heroku.Service) (*application, error) {
	app := application{Id: id, Client: client}

	err := app.Update()

	if err != nil {
		return nil, fmt.Errorf("Error retrieving app: %s", err)
	}

	return &app, nil
}

func retrieve_config_vars(id string, client *heroku.Service) (map[string]string, error) {
	vars, err := client.ConfigVarInfo(id)

	if err != nil {
		return nil, err
	}

	return vars, nil
}

// Updates the config vars for from an expanded configuration.
func update_config_vars(
	id string,
	client *heroku.Service,
	o []interface{},
	n []interface{}) error {
	vars := make(map[string]*string)

	for _, v := range o {
		for k, _ := range v.(map[string]interface{}) {
			vars[k] = nil
		}
	}
	for _, v := range n {
		for k, v := range v.(map[string]interface{}) {
			val := v.(string)
			vars[k] = &val
		}
	}

	log.Printf("[INFO] Updating config vars: *%#v", vars)
	if _, err := client.ConfigVarUpdate(id, vars); err != nil {
		return fmt.Errorf("Error updating config vars: %s", err)
	}

	return nil
}
<commit_msg>Document the organization name field<commit_after>package heroku

import (
	"fmt"
	"log"

	"github.com/cyberdelia/heroku-go/v3"
	"github.com/hashicorp/terraform/helper/multierror"
	"github.com/hashicorp/terraform/helper/schema"
)

// type application is used to store all the details of a heroku app
type application struct {
	Id string // Id of the resource

	App    *heroku.App       // The heroku application
	Client *heroku.Service   // Client to interact with the heroku API
	Vars   map[string]string // The vars on the application
}

// Updates the application to have the latest from remote
func (a *application) Update() error {
	var errs []error
	var err error

	a.App, err = a.Client.AppInfo(a.Id)
	if err != nil {
		errs = append(errs, err)
	}

	a.Vars, err = retrieve_config_vars(a.Id, a.Client)
	if err != nil {
		errs = append(errs, err)
	}

	if len(errs) > 0 {
		return &multierror.Error{Errors: errs}
	}

	return nil
}

func resourceHerokuApp() *schema.Resource {
	return &schema.Resource{
		Create: switchHerokuAppCreate,
		Read:   resourceHerokuAppRead,
		Update: resourceHerokuAppUpdate,
		Delete: resourceHerokuAppDelete,

		Schema: map[string]*schema.Schema{
			"name": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
			},

			"region": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
			},

			"stack": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				Computed: true,
				ForceNew: true,
			},

			"config_vars": &schema.Schema{
				Type:     schema.TypeList,
				Optional: true,
				Elem: &schema.Schema{
					Type: schema.TypeMap,
				},
			},

			"all_config_vars": &schema.Schema{
				Type:     schema.TypeMap,
				Computed: true,
			},

			"git_url": &schema.Schema{
				Type:     schema.TypeString,
				Computed: true,
			},

			"web_url": &schema.Schema{
				Type:     schema.TypeString,
				Computed: true,
			},

			"heroku_hostname": &schema.Schema{
				Type:     schema.TypeString,
				Computed: true,
			},

			"organization": &schema.Schema{
				Type:        schema.TypeString,
				Description: "Name of Organization to create application in. Leave blank for personal apps.",
				Optional:    true,
				ForceNew:    true,
			},
		},
	}
}

func switchHerokuAppCreate(d *schema.ResourceData, meta interface{}) error {
	if _, ok := d.GetOk("organization"); ok {
		return resourceHerokuOrgAppCreate(d, meta)
	} else {
		return resourceHerokuAppCreate(d, meta)
	}
}

func resourceHerokuAppCreate(d *schema.ResourceData, meta interface{}) error {
	client := meta.(*heroku.Service)

	// Build up our creation options
	opts := heroku.AppCreateOpts{}

	if v := d.Get("name"); v != nil {
		vs := v.(string)
		log.Printf("[DEBUG] App name: %s", vs)
		opts.Name = &vs
	}
	if v := d.Get("region"); v != nil {
		vs := v.(string)
		log.Printf("[DEBUG] App region: %s", vs)
		opts.Region = &vs
	}
	if v := d.Get("stack"); v != nil {
		vs := v.(string)
		log.Printf("[DEBUG] App stack: %s", vs)
		opts.Stack = &vs
	}

	log.Printf("[DEBUG] Creating Heroku app...")
	a, err := client.AppCreate(opts)
	if err != nil {
		return err
	}

	d.SetId(a.Name)
	log.Printf("[INFO] App ID: %s", d.Id())

	if v := d.Get("config_vars"); v != nil {
		err = update_config_vars(d.Id(), client, nil, v.([]interface{}))
		if err != nil {
			return err
		}
	}

	return resourceHerokuAppRead(d, meta)
}

func resourceHerokuOrgAppCreate(d *schema.ResourceData, meta interface{}) error {
	client := meta.(*heroku.Service)
	// Build up our creation options
	opts := heroku.OrganizationAppCreateOpts{}
	if v := d.Get("organization"); v != nil {
		vs := v.(string)
		log.Printf("[DEBUG] App name: %s", vs)
		opts.Organization = &vs
	}
	if v := d.Get("name"); v != nil {
		vs := v.(string)
		log.Printf("[DEBUG] App name: %s", vs)
		opts.Name = &vs
	}
	if v := d.Get("region"); v != nil {
		vs := v.(string)
		log.Printf("[DEBUG] App region: %s", vs)
		opts.Region = &vs
	}
	if v := d.Get("stack"); v != nil {
		vs := v.(string)
		log.Printf("[DEBUG] App stack: %s", vs)
		opts.Stack = &vs
	}

	log.Printf("[DEBUG] Creating Heroku app...")
	a, err := client.OrganizationAppCreate(opts)
	if err != nil {
		return err
	}

	d.SetId(a.Name)
	log.Printf("[INFO] App ID: %s", d.Id())

	if v := d.Get("config_vars"); v != nil {
		err = update_config_vars(d.Id(), client, nil, v.([]interface{}))
		if err != nil {
			return err
		}
	}

	return resourceHerokuAppRead(d, meta)
}

func resourceHerokuAppRead(d *schema.ResourceData, meta interface{}) error {
	client := meta.(*heroku.Service)
	app, err := resource_heroku_app_retrieve(d.Id(), client)
	if err != nil {
		return err
	}

	// Only set the config_vars that we have set in the configuration.
	// The "all_config_vars" field has all of them.
	configVars := make(map[string]string)
	care := make(map[string]struct{})
	for _, v := range d.Get("config_vars").([]interface{}) {
		for k, _ := range v.(map[string]interface{}) {
			care[k] = struct{}{}
		}
	}
	for k, v := range app.Vars {
		if _, ok := care[k]; ok {
			configVars[k] = v
		}
	}
	var configVarsValue []map[string]string
	if len(configVars) > 0 {
		configVarsValue = []map[string]string{configVars}
	}

	d.Set("name", app.App.Name)
	d.Set("stack", app.App.Stack.Name)
	d.Set("region", app.App.Region.Name)
	d.Set("git_url", app.App.GitURL)
	d.Set("web_url", app.App.WebURL)
	d.Set("config_vars", configVarsValue)
	d.Set("all_config_vars", app.Vars)

	// We know that the hostname on heroku will be the name+herokuapp.com
	// You need this to do things like create DNS CNAME records
	d.Set("heroku_hostname", fmt.Sprintf("%s.herokuapp.com", app.App.Name))

	return nil
}

func resourceHerokuAppUpdate(d *schema.ResourceData, meta interface{}) error {
	client := meta.(*heroku.Service)

	// If name changed, update it
	if d.HasChange("name") {
		v := d.Get("name").(string)
		opts := heroku.AppUpdateOpts{
			Name: &v,
		}

		renamedApp, err := client.AppUpdate(d.Id(), opts)
		if err != nil {
			return err
		}

		// Store the new ID
		d.SetId(renamedApp.Name)
	}

	// If the config vars changed, then recalculate those
	if d.HasChange("config_vars") {
		o, n := d.GetChange("config_vars")
		if o == nil {
			o = []interface{}{}
		}
		if n == nil {
			n = []interface{}{}
		}

		err := update_config_vars(
			d.Id(), client, o.([]interface{}), n.([]interface{}))
		if err != nil {
			return err
		}
	}

	return resourceHerokuAppRead(d, meta)
}

func resourceHerokuAppDelete(d *schema.ResourceData, meta interface{}) error {
	client := meta.(*heroku.Service)

	log.Printf("[INFO] Deleting App: %s", d.Id())
	err := client.AppDelete(d.Id())
	if err != nil {
		return fmt.Errorf("Error deleting App: %s", err)
	}

	d.SetId("")
	return nil
}

func resource_heroku_app_retrieve(id string, client *heroku.Service) (*application, error) {
	app := application{Id: id, Client: client}

	err := app.Update()

	if err != nil {
		return nil, fmt.Errorf("Error retrieving app: %s", err)
	}

	return &app, nil
}

func retrieve_config_vars(id string, client *heroku.Service) (map[string]string, error) {
	vars, err := client.ConfigVarInfo(id)

	if err != nil {
		return nil, err
	}

	return vars, nil
}

// Updates the config vars for from an expanded configuration.
func update_config_vars(
	id string,
	client *heroku.Service,
	o []interface{},
	n []interface{}) error {
	vars := make(map[string]*string)

	for _, v := range o {
		for k, _ := range v.(map[string]interface{}) {
			vars[k] = nil
		}
	}
	for _, v := range n {
		for k, v := range v.(map[string]interface{}) {
			val := v.(string)
			vars[k] = &val
		}
	}

	log.Printf("[INFO] Updating config vars: *%#v", vars)
	if _, err := client.ConfigVarUpdate(id, vars); err != nil {
		return fmt.Errorf("Error updating config vars: %s", err)
	}

	return nil
}
<|endoftext|>


<commit_before>// Package tgff provides a parser for the TGFF (Task Graphs For Free) format,
// which is a format for storing task graphs and accompanying data used in
// scheduling and allocation research.
//
// http://ziyang.eecs.umich.edu/~dickrp/tgff/
package tgff

import (
	"io"
	"os"
)

// Parse reads the content of a TGFF file (*.tgff), generated by the tgff
// command-line tool from a TGFFOPT file (*.tgffopt), and returns its
// representation in a Result struct.
func Parse(reader io.Reader) (Result, error) {
	abort := make(chan bool, 1)

	lexer, stream := newLexer(reader, abort)
	parser, success, failure := newParser(stream, abort)

	go lexer.run()
	go parser.run()

	select {
	case result := <-success:
		return result, nil
	case err := <-failure:
		return Result{}, err
	}
}

// ParseFile works exactly as Parse but takes a path to a TGFF file instead of
// an io.Reader.
func ParseFile(path string) (Result, error) {
	file, err := os.Open(path)

	if err != nil {
		return Result{}, err
	}

	defer file.Close()

	return Parse(file)
}
<commit_msg>A cosmetic change<commit_after>// Package tgff provides a parser for the TGFF (Task Graphs For Free) format,
// which is a format for storing task graphs and accompanying data used in
// scheduling and allocation research.
//
// http://ziyang.eecs.umich.edu/~dickrp/tgff
package tgff

import (
	"io"
	"os"
)

// Parse reads the content of a TGFF file (*.tgff), generated by the tgff
// command-line tool from a TGFFOPT file (*.tgffopt), and returns its
// representation in a Result struct.
func Parse(reader io.Reader) (Result, error) {
	abort := make(chan bool, 1)

	lexer, stream := newLexer(reader, abort)
	parser, success, failure := newParser(stream, abort)

	go lexer.run()
	go parser.run()

	select {
	case result := <-success:
		return result, nil
	case err := <-failure:
		return Result{}, err
	}
}

// ParseFile works exactly as Parse but takes a path to a TGFF file instead of
// an io.Reader.
func ParseFile(path string) (Result, error) {
	file, err := os.Open(path)

	if err != nil {
		return Result{}, err
	}

	defer file.Close()

	return Parse(file)
}
<|endoftext|>


<commit_before>package main

/*
 * A shiny status page.
 *
 * Want it to combine my existing idle page and tiny-care-terminal.
 *
 * Things to include:
 *  - some twitter accounts
 *      - @tinycarebot, @selfcare_bot and @magicrealismbot. Maybe that boat one instead of magic realism.
 *  - weather
 *  - recent git commits
 *  - system status:
 *      - User/hostname
 *      - Kerberos ticket status
 *      - Current time
 *      - Uptime
 *      - Battery and time left
 *      - Audio status and volume
 *      - Network
 *          - Local, docker, wireless
 *      - Disk
 *          - Mounts, free/used/total/percentage w/ color
 *      - CPU
 *          - Load average w/ color
 *          - Percentage
 *          - Top processes?
 *      - Status of git repos
 *
 * Minimum terminal size to support:
 *  - 189x77 (half monitor with some stacks)
 *  - 104x56ish? (half the laptop screen with some stacks)
 *  - 100x50? (nice and round)
 *  - 80x40? (my default putty)
 *
 */

import (
	"io/ioutil"
	"log"
	"os"
	"time"

	ui "github.com/gizak/termui"
)

//
// Rendering loop
//

func loop(widgets []CAHWidget, header *HeaderWidget) {
	render := func() {
		ui.Body.Align()
		ui.Clear()
		ui.Render(header.widget, ui.Body)
	}

	//
	//  Activate
	//

	render()
	firstTimeResize := false
	ticker := time.NewTicker(5 * time.Second)

	for {
		// Call all resize funcs (only the first time)
		if !firstTimeResize {
			firstTimeResize = true
			for _, w := range widgets {
				w.resize()
				w.update()
			}

			render()
		}

		select {
		case e := <-ui.PollEvent():
			switch e.ID {
			case "q", "<C-c>":
				return
			case "<Resize>":
				payload := e.Payload.(ui.Resize)

				// Re-layout on resize
				ui.Body.Width = payload.Width - 2

				// Call all resize funcs
				for _, w := range widgets {
					w.resize()
				}

				// Re-render
				render()
			}
		case <-ticker.C:
			for _, w := range widgets {
				w.update()
			}

			render()
		}
	}
}

////////////////////////////////////////////
// Where the real stuff happens
////////////////////////////////////////////

func main() {
	// Set up logging?
	if LogToFile() {
		logFile, logErr := os.OpenFile("go.log", os.O_RDWR|os.O_CREATE|os.O_APPEND, 0660)
		if logErr != nil {
			panic(logErr)
		}
		defer logFile.Close()

		log.SetOutput(logFile)
	} else {
		// Disable logging
		log.SetFlags(0)
		log.SetOutput(ioutil.Discard)
	}

	// Set up the console UI
	uiErr := ui.Init()
	if uiErr != nil {
		panic(uiErr)
	}
	defer ui.Close()

	//
	// Create the widgets
	//
	widgets := make([]CAHWidget, 0)

	header := NewHeaderWidget()
	widgets = append(widgets, header)

	hostInfo := NewHostInfoWidget()
	widgets = append(widgets, hostInfo)

	network := NewNetworkWidget()
	widgets = append(widgets, network)

	battery := NewBatteryWidget()
	widgets = append(widgets, battery)

	audio := NewAudioWidget()
	widgets = append(widgets, audio)

	disk := NewDiskColumn(6, 0)
	widgets = append(widgets, disk)

	cpu := NewCPUWidget()
	widgets = append(widgets, cpu)

	repo := NewGitRepoWidget()
	widgets = append(widgets, repo)

	twitter1 := NewTwitterWidget(GetTwitterAccount1(), ui.ColorBlue|ui.AttrBold)
	widgets = append(widgets, twitter1)

	twitter2 := NewTwitterWidget(GetTwitterAccount2(), ui.ColorCyan)
	widgets = append(widgets, twitter2)

	twitter3 := NewTwitterWidget(GetTwitterAccount3(), ui.ColorMagenta)
	widgets = append(widgets, twitter3)

	weather := NewWeatherWidget(GetWeatherLocation())
	widgets = append(widgets, weather)

	//
	// Create the layout
	//

	// Give space around the ui.Body for the header box to wrap all around
	ui.Body.Width = ui.TermWidth() - 2
	ui.Body.X = 1
	ui.Body.Y = 1

	ui.Body.AddRows(
		ui.NewRow(
			ui.NewCol(6, 0, hostInfo.getGridWidget(), battery.getGridWidget(), audio.getGridWidget(), weather.getGridWidget()),
			ui.NewCol(6, 0, cpu.getGridWidget())),
		ui.NewRow(
			disk.getColumn(),
			ui.NewCol(6, 0, network.getGridWidget())),
		ui.NewRow(
			ui.NewCol(12, 0, repo.getGridWidget())),
		ui.NewRow(
			ui.NewCol(4, 0, twitter1.getGridWidget()),
			ui.NewCol(4, 0, twitter2.getGridWidget()),
			ui.NewCol(4, 0, twitter3.getGridWidget())))

	ui.Body.Align()

	loop(widgets, header)
}
<commit_msg>They renamed this class...<commit_after>package main

/*
 * A shiny status page.
 *
 * Want it to combine my existing idle page and tiny-care-terminal.
 *
 * Things to include:
 *  - some twitter accounts
 *      - @tinycarebot, @selfcare_bot and @magicrealismbot. Maybe that boat one instead of magic realism.
 *  - weather
 *  - recent git commits
 *  - system status:
 *      - User/hostname
 *      - Kerberos ticket status
 *      - Current time
 *      - Uptime
 *      - Battery and time left
 *      - Audio status and volume
 *      - Network
 *          - Local, docker, wireless
 *      - Disk
 *          - Mounts, free/used/total/percentage w/ color
 *      - CPU
 *          - Load average w/ color
 *          - Percentage
 *          - Top processes?
 *      - Status of git repos
 *
 * Minimum terminal size to support:
 *  - 189x77 (half monitor with some stacks)
 *  - 104x56ish? (half the laptop screen with some stacks)
 *  - 100x50? (nice and round)
 *  - 80x40? (my default putty)
 *
 */

import (
	"io/ioutil"
	"log"
	"os"
	"time"

	ui "github.com/gizak/termui"
)

//
// Rendering loop
//

func loop(widgets []CAHWidget, header *HeaderWidget) {
	render := func() {
		ui.Body.Align()
		ui.Clear()
		ui.Render(header.widget, ui.Body)
	}

	//
	//  Activate
	//

	render()
	firstTimeResize := false
	ticker := time.NewTicker(5 * time.Second)

	for {
		// Call all resize funcs (only the first time)
		if !firstTimeResize {
			firstTimeResize = true
			for _, w := range widgets {
				w.resize()
				w.update()
			}

			render()
		}

		select {
		case e := <-ui.PollEvents():
			switch e.ID {
			case "q", "<C-c>":
				return
			case "<Resize>":
				payload := e.Payload.(ui.Resize)

				// Re-layout on resize
				ui.Body.Width = payload.Width - 2

				// Call all resize funcs
				for _, w := range widgets {
					w.resize()
				}

				// Re-render
				render()
			}
		case <-ticker.C:
			for _, w := range widgets {
				w.update()
			}

			render()
		}
	}
}

////////////////////////////////////////////
// Where the real stuff happens
////////////////////////////////////////////

func main() {
	// Set up logging?
	if LogToFile() {
		logFile, logErr := os.OpenFile("go.log", os.O_RDWR|os.O_CREATE|os.O_APPEND, 0660)
		if logErr != nil {
			panic(logErr)
		}
		defer logFile.Close()

		log.SetOutput(logFile)
	} else {
		// Disable logging
		log.SetFlags(0)
		log.SetOutput(ioutil.Discard)
	}

	// Set up the console UI
	uiErr := ui.Init()
	if uiErr != nil {
		panic(uiErr)
	}
	defer ui.Close()

	//
	// Create the widgets
	//
	widgets := make([]CAHWidget, 0)

	header := NewHeaderWidget()
	widgets = append(widgets, header)

	hostInfo := NewHostInfoWidget()
	widgets = append(widgets, hostInfo)

	network := NewNetworkWidget()
	widgets = append(widgets, network)

	battery := NewBatteryWidget()
	widgets = append(widgets, battery)

	audio := NewAudioWidget()
	widgets = append(widgets, audio)

	disk := NewDiskColumn(6, 0)
	widgets = append(widgets, disk)

	cpu := NewCPUWidget()
	widgets = append(widgets, cpu)

	repo := NewGitRepoWidget()
	widgets = append(widgets, repo)

	twitter1 := NewTwitterWidget(GetTwitterAccount1(), ui.ColorBlue|ui.AttrBold)
	widgets = append(widgets, twitter1)

	twitter2 := NewTwitterWidget(GetTwitterAccount2(), ui.ColorCyan)
	widgets = append(widgets, twitter2)

	twitter3 := NewTwitterWidget(GetTwitterAccount3(), ui.ColorMagenta)
	widgets = append(widgets, twitter3)

	weather := NewWeatherWidget(GetWeatherLocation())
	widgets = append(widgets, weather)

	//
	// Create the layout
	//

	// Give space around the ui.Body for the header box to wrap all around
	ui.Body.Width = ui.TermWidth() - 2
	ui.Body.X = 1
	ui.Body.Y = 1

	ui.Body.AddRows(
		ui.NewRow(
			ui.NewCol(6, 0, hostInfo.getGridWidget(), battery.getGridWidget(), audio.getGridWidget(), weather.getGridWidget()),
			ui.NewCol(6, 0, cpu.getGridWidget())),
		ui.NewRow(
			disk.getColumn(),
			ui.NewCol(6, 0, network.getGridWidget())),
		ui.NewRow(
			ui.NewCol(12, 0, repo.getGridWidget())),
		ui.NewRow(
			ui.NewCol(4, 0, twitter1.getGridWidget()),
			ui.NewCol(4, 0, twitter2.getGridWidget()),
			ui.NewCol(4, 0, twitter3.getGridWidget())))

	ui.Body.Align()

	loop(widgets, header)
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"flag"
	"fmt"
	"net/url"
	"os"
	"strconv"

	"github.com/ChimeraCoder/anaconda"
)

var (
	limit   int
	minfav  int
	minrt   int
	dbgflag bool
)

func getLines(fname string) ([]string, error) {
	fp, err := os.Open(fname)
	if err != nil {
		panic(err)
	}
	defer fp.Close()
	scanner := bufio.NewScanner(fp)
	var lines []string
	for scanner.Scan() {
		line := scanner.Text()
		lines = append(lines, line)
	}
	return lines, nil
}

func getApi() *anaconda.TwitterApi {
	info, err := getLines("oauth.txt")
	if err != nil {
		panic(err)
	}
	anaconda.SetConsumerKey(info[0])
	anaconda.SetConsumerSecret(info[1])
	return anaconda.NewTwitterApi(info[2], info[3])
}

func authenticate() {
	info, err := getLines("oauth.txt")
	if err != nil {
		panic(err)
	}
	anaconda.SetConsumerKey(info[0])
	anaconda.SetConsumerSecret(info[1])
	url, token, err := anaconda.AuthorizationURL("")
	if err != nil {
		panic(err)
	}
	fmt.Println(url)
	fmt.Println(token.Token, token.Secret)

	var verifier string
	fmt.Print("Input PIN Code: ")
	fmt.Scan(&verifier)
	token, val, err := anaconda.GetCredentials(token, verifier)
	fmt.Println(token)
	fmt.Println(val)
	if err != nil {
		panic(err)
	}
	//api := anaconda.NewTwitterApi(token.Token, token.Secret)
}

func test() {
	fmt.Println(limit, minfav, minrt, dbgflag)
}

func init() {
	// Set flags
	INF := 114514
	flag.IntVar(&limit, "limit", 3200, "Limit of number to delete tweets")
	flag.IntVar(&minfav, "minfav", INF, "Delete tweet less than minfav")
	flag.IntVar(&minrt, "minrt", INF, "Delete tweet less than minrt")
	flag.BoolVar(&dbgflag, "dbg", false, "Debug mode on if dbg=true")

	flag.Parse()
}

func main() {
	if dbgflag {
		fmt.Println("Debug mode ON!")
		test()
		return
	}

	api := getApi()

	// Delete user's tweets (up to 3200)
	LIM := limit / 200
	v := url.Values{}
	v.Set("count", "200")
	for page := 1; page <= LIM; page++ {
		if page == LIM {
			v.Set("count", strconv.Itoa(limit%200))
		}
		v.Set("page", strconv.Itoa(page))
		timeline, err := api.GetUserTimeline(v)
		if err != nil {
			panic(err)
		}
		if dbgflag {
			fmt.Println("Len: ", len(timeline))
		}
		if len(timeline) == 0 {
			break
		}

		for _, tweet := range timeline {
			if tweet.FavoriteCount >= minfav || tweet.RetweetCount >= minrt {
				continue
			}
			t, err := api.DeleteTweet(tweet.Id, false)
			if err != nil {
				panic(err)
			}
			if dbgflag {
				fmt.Println(t.Text)
			}
		}
	}

	fmt.Println("Done")
}
<commit_msg>Use deleted counter<commit_after>package main

import (
	"bufio"
	"flag"
	"fmt"
	"net/url"
	"os"
	"strconv"

	"github.com/ChimeraCoder/anaconda"
)

var (
	limit   int
	minfav  int
	minrt   int
	dbgflag bool
)

func getLines(fname string) ([]string, error) {
	fp, err := os.Open(fname)
	if err != nil {
		panic(err)
	}
	defer fp.Close()
	scanner := bufio.NewScanner(fp)
	var lines []string
	for scanner.Scan() {
		line := scanner.Text()
		lines = append(lines, line)
	}
	return lines, nil
}

func getApi() *anaconda.TwitterApi {
	info, err := getLines("oauth.txt")
	if err != nil {
		panic(err)
	}
	anaconda.SetConsumerKey(info[0])
	anaconda.SetConsumerSecret(info[1])
	return anaconda.NewTwitterApi(info[2], info[3])
}

func authenticate() {
	info, err := getLines("oauth.txt")
	if err != nil {
		panic(err)
	}
	anaconda.SetConsumerKey(info[0])
	anaconda.SetConsumerSecret(info[1])
	url, token, err := anaconda.AuthorizationURL("")
	if err != nil {
		panic(err)
	}
	fmt.Println(url)
	fmt.Println(token.Token, token.Secret)

	var verifier string
	fmt.Print("Input PIN Code: ")
	fmt.Scan(&verifier)
	token, val, err := anaconda.GetCredentials(token, verifier)
	fmt.Println(token)
	fmt.Println(val)
	if err != nil {
		panic(err)
	}
	//api := anaconda.NewTwitterApi(token.Token, token.Secret)
}

func test() {
	fmt.Printf("%v", 114514)
}

func init() {
	// Set flags
	INF := 114514
	flag.IntVar(&limit, "limit", 3200, "Limit of number to delete tweets")
	flag.IntVar(&minfav, "minfav", INF, "Delete tweet less than minfav")
	flag.IntVar(&minrt, "minrt", INF, "Delete tweet less than minrt")
	flag.BoolVar(&dbgflag, "dbg", false, "Debug mode on if dbg=true")

	flag.Parse()
}

func main() {
	if dbgflag {
		fmt.Println("Debug mode ON!")
		test()
		return
	}

	api := getApi()

	// Delete user's tweets (up to 3200)
	deleted := 0
	LIM := limit / 200
	v := url.Values{}
	v.Set("count", "200")
	for page := 1; page <= LIM; page++ {
		if page == LIM {
			v.Set("count", strconv.Itoa(limit%200))
		}
		v.Set("page", strconv.Itoa(page))
		timeline, err := api.GetUserTimeline(v)
		if err != nil {
			panic(err)
		}
		if dbgflag {
			fmt.Println("Len: ", len(timeline))
		}
		if len(timeline) == 0 {
			break
		}

		for _, tweet := range timeline {
			if tweet.FavoriteCount >= minfav || tweet.RetweetCount >= minrt {
				continue
			}
			t, err := api.DeleteTweet(tweet.Id, false)
			if err != nil {
				panic(err)
			}
			if dbgflag {
				fmt.Println(t.Text)
			}
			deleted++
		}
	}

	fmt.Printf("Deleted %v tweets\n", deleted)
	fmt.Println("Done")
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"github.com/leocassarani/pew/command"
	"os"
)

func main() {
	args := os.Args
	if len(args) < 2 {
		printUsage(args)
		os.Exit(1)
	}

	cmd := args[1]
	cmdArgs := args[2:]

	switch cmd {
	case "run":
		err := command.Run(cmdArgs)
		exit(err)
	case "help":
		fallthrough
	case "--help":
		printUsage(args)
		os.Exit(0)
	}

}

func exit(err error) {
	if err != nil {
		log(err)
		os.Exit(1)
	}
	os.Exit(0)
}

func log(err error) {
	fmt.Fprintf(os.Stderr, "pew: %v\n", err)
}

func printUsage(args []string) {
	fmt.Printf("usage: %s <command>\n", args[0])
}
<commit_msg>Handle unrecognised CLI commands in a git-like fashion<commit_after>package main

import (
	"fmt"
	"github.com/leocassarani/pew/command"
	"os"
)

func main() {
	args := os.Args
	if len(args) < 2 {
		printUsage(args)
		os.Exit(1)
	}

	cmd := args[1]
	cmdArgs := args[2:]

	switch cmd {
	case "run":
		err := command.Run(cmdArgs)
		exit(err)
	case "help":
		fallthrough
	case "--help":
		printUsage(args)
		exit(nil)
	default:
		err := fmt.Errorf("'%s' is not a command. See '%s --help'.", cmd, args[0])
		exit(err)
	}

}

func exit(err error) {
	if err != nil {
		log(err)
		os.Exit(1)
	}
	os.Exit(0)
}

func log(err error) {
	fmt.Fprintf(os.Stderr, "pew: %v\n", err)
}

func printUsage(args []string) {
	fmt.Printf("usage: %s <command>\n", args[0])
}
<|endoftext|>


<commit_before>package main

import (
	"context"
	"flag"
	"fmt"
	"log"
	"net/http"
	"os"
	"os/signal"
	"syscall"

	"github.com/douglasmakey/ursho/config"
	"github.com/douglasmakey/ursho/handler"
	"github.com/douglasmakey/ursho/storage/postgres"
)

func main() {
	configPath := flag.String("config", "./config/config.json", "path of the config file")

	flag.Parse()

	// Read config
	config, err := config.FromFile(*configPath)
	if err != nil {
		log.Fatal(err)
	}

	// Set use storage, select [Postgres, Filesystem, Redis ...]
	svc, err := postgres.New(config.Postgres.Host, config.Postgres.Port, config.Postgres.User, config.Postgres.Password, config.Postgres.DB)
	if err != nil {
		log.Fatal(err)
	}
	defer svc.Close()

	// Create a server
	server := &http.Server{
		Addr:    fmt.Sprintf("%s:%s", config.Server.Host, config.Server.Port),
		Handler: handler.New(config.Options.Prefix, svc),
	}

	// Check for a closing signal
	go func() {
		// Graceful shutdown
		sigquit := make(chan os.Signal, 1)
		signal.Notify(sigquit, os.Interrupt, syscall.SIGTERM)

		sig := <-sigquit
		log.Printf("caught sig: %+v", sig)
		log.Printf("Gracefully shutting down server...")

		if err := server.Shutdown(context.Background()); err != nil {
			log.Printf("Unable to shut down server: %v", err)
		} else {
			log.Println("Server stopped")
		}
	}()

	// Start server
	log.Printf("Starting HTTP Server. Listening at %q", server.Addr)
	if err := server.ListenAndServe(); err != http.ErrServerClosed {
		log.Printf("%v", err)
	} else {
		log.Println("Server closed!")
	}
}
<commit_msg>fix(server): Fix gracefull shutdown.<commit_after>package main

import (
	"context"
	"flag"
	"fmt"
	"log"
	"net/http"
	"os"
	"os/signal"
	"syscall"

	"github.com/douglasmakey/ursho/config"
	"github.com/douglasmakey/ursho/handler"
	"github.com/douglasmakey/ursho/storage/postgres"
)

func main() {
	configPath := flag.String("config", "./config/config.json", "path of the config file")

	flag.Parse()

	// Read config
	config, err := config.FromFile(*configPath)
	if err != nil {
		log.Fatal(err)
	}

	// Set use storage, select [Postgres, Filesystem, Redis ...]
	svc, err := postgres.New(config.Postgres.Host, config.Postgres.Port, config.Postgres.User, config.Postgres.Password, config.Postgres.DB)
	if err != nil {
		log.Fatal(err)
	}
	defer svc.Close()

	// Create a server
	server := &http.Server{
		Addr:    fmt.Sprintf("%s:%s", config.Server.Host, config.Server.Port),
		Handler: handler.New(config.Options.Prefix, svc),
	}

	go func() {
		// Start server
		log.Printf("Starting HTTP Server. Listening at %q", server.Addr)
		if err := server.ListenAndServe(); err != http.ErrServerClosed {
			log.Printf("%v", err)
		} else {
			log.Println("Server closed!")
		}
	}()

	// Check for a closing signal
	// Graceful shutdown
	sigquit := make(chan os.Signal, 1)
	signal.Notify(sigquit, os.Interrupt, syscall.SIGTERM)

	sig := <-sigquit
	log.Printf("caught sig: %+v", sig)
	log.Printf("Gracefully shutting down server...")

	if err := server.Shutdown(context.Background()); err != nil {
		log.Printf("Unable to shut down server: %v", err)
	} else {
		log.Println("Server stopped")
	}
}
<|endoftext|>


<commit_before>package main

import (
	"context"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"os"
	"strings"
	"sync"

	"github.com/docker/docker/api/types"
	"github.com/docker/docker/api/types/container"
	"github.com/docker/docker/api/types/network"
	"github.com/docker/docker/client"

	"github.com/pkg/errors"
	"gopkg.in/yaml.v2"
)

/*
version: '3'
services:
  redis:
    image: 'redis:3.0-alpine'

  busybox:
    image: busybox
*/
type serviceConfig struct {
	Build string `yaml:"build,omitempty"`
	//Command        yaml.Command         `yaml:"command,flow,omitempty"`
	Dockerfile string `yaml:"dockerfile,omitempty"`
	//Environment    yaml.MaporEqualSlice `yaml:"environment,omitempty"`
	Image string `yaml:"image,omitempty"`
	//Links          yaml.MaporColonSlice `yaml:"links,omitempty"`
	Name        string   `yaml:"name,omitempty"`
	Ports       []string `yaml:"ports,omitempty"`
	Restart     string   `yaml:"restart,omitempty"`
	Volumes     []string `yaml:"volumes,omitempty"`
	VolumesFrom []string `yaml:"volumes_from,omitempty"`
	Expose      []string `yaml:"expose,omitempty"`
	Labels      []string `yaml:"labels,omitempty"`
}

type dockerComposeConfig struct {
	Version  string                   `yaml:"version,omitempty"`
	Services map[string]serviceConfig `yaml:"services"`
	//networks map[string]     `yaml:"networks,omitempty"`
	//volumes map[string]                  `yaml:"volumes,omitempty"`
}

func (dcy *dockerComposeConfig) Parse(data []byte) error {
	return yaml.Unmarshal(data, dcy)
}

func main() {
	data, err := ioutil.ReadFile("docker-compose.yml")
	if err != nil {
		log.Fatal(errors.Wrap(err, "unable to read docker-compose file"))
	}
	networkID, err := getNetwork()
	if err != nil {
		log.Fatal(err)
	}

	var dockerCyaml dockerComposeConfig
	if err := dockerCyaml.Parse(data); err != nil {
		log.Fatal(errors.Wrap(err, "unable to parse docker-compose file contents"))
	}

	var wg sync.WaitGroup

	for _, v := range dockerCyaml.Services {
		wg.Add(1)
		fmt.Println("image, labels", v.Image, v.Labels)
		go fakepullImage(v.Image, networkID, &wg)
		//go pullImage(v.Image, networkID, &wg)
	}
	wg.Wait()

}

func fakepullImage(imagename, networkID string, wg *sync.WaitGroup) {
	defer wg.Done()
}
func pullImage(imagename, networkID string, wg *sync.WaitGroup) {
	defer wg.Done()
	formattedImageName := fomatImageName(imagename)
	fmt.Println()
	fmt.Println("dockerImage, networkID, name:", imagename, networkID, formattedImageName)
	fmt.Println()
	ctx := context.Background()
	cli, err := client.NewEnvClient()
	if err != nil {
		panic(errors.Wrap(err, "unable to intialize docker client"))
	}

	imagePullResp, err := cli.ImagePull(
		ctx,
		imagename,
		types.ImagePullOptions{})
	if err != nil {
		panic(errors.Wrap(err, "unable to pull image"))
	}
	defer imagePullResp.Close()
	_, err = io.Copy(os.Stdout, imagePullResp)
	if err != nil {
		log.Println(errors.Wrap(err, "unable to write to stdout"))
	}

	containerCreateResp, err := cli.ContainerCreate(
		ctx,
		&container.Config{Image: imagename},
		&container.HostConfig{PublishAllPorts: true},
		nil,
		formattedImageName)
	if err != nil {
		log.Fatal(errors.Wrap(err, "unable to create container"))
	}

	err = cli.NetworkConnect(
		ctx,
		networkID,
		containerCreateResp.ID,
		&network.EndpointSettings{})
	if err != nil {
		log.Fatal(errors.Wrap(err, "unable to connect container to network"))
	}

	err = cli.ContainerStart(
		ctx,
		containerCreateResp.ID,
		types.ContainerStartOptions{})
	if err != nil {
		panic(errors.Wrap(err, "unable to start container"))
	}

	containerLogResp, err := cli.ContainerLogs(
		ctx,
		containerCreateResp.ID,
		types.ContainerLogsOptions{
			ShowStdout: true,
			ShowStderr: true,
			Timestamps: true})
	if err != nil {
		panic(errors.Wrap(err, "unable to get container logs"))
	}
	defer containerLogResp.Close()

	_, err = io.Copy(os.Stdout, containerLogResp)
	if err != nil {
		log.Println(errors.Wrap(err, "unable to write to stdout"))
	}
}

func fomatImageName(imagename string) string {
	f := func(c rune) bool {
		if c == 58 {
			// 58 is the ':' character
			return true
		}
		return false
	}
	return strings.FieldsFunc(imagename, f)[0]
}
<commit_msg>stuff<commit_after>package main

import (
	"context"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"os"
	"strings"
	"sync"

	"github.com/docker/docker/api/types"
	"github.com/docker/docker/api/types/container"
	"github.com/docker/docker/api/types/network"
	"github.com/docker/docker/client"

	"github.com/pkg/errors"
	"gopkg.in/yaml.v2"
)

/*
version: '3'
services:
  redis:
    image: 'redis:3.0-alpine'

  busybox:
    image: busybox
*/
type serviceConfig struct {
	Build string `yaml:"build,omitempty"`
	//Command        yaml.Command         `yaml:"command,flow,omitempty"`
	Dockerfile string `yaml:"dockerfile,omitempty"`
	//Environment    yaml.MaporEqualSlice `yaml:"environment,omitempty"`
	Image string `yaml:"image,omitempty"`
	//Links          yaml.MaporColonSlice `yaml:"links,omitempty"`
	Name        string   `yaml:"name,omitempty"`
	Ports       []string `yaml:"ports,omitempty"`
	Restart     string   `yaml:"restart,omitempty"`
	Volumes     []string `yaml:"volumes,omitempty"`
	VolumesFrom []string `yaml:"volumes_from,omitempty"`
	Expose      []string `yaml:"expose,omitempty"`
	Labels      []string `yaml:"labels,omitempty"`
}

type dockerComposeConfig struct {
	Version  string                   `yaml:"version,omitempty"`
	Services map[string]serviceConfig `yaml:"services"`
	//networks map[string]     `yaml:"networks,omitempty"`
	//volumes map[string]                  `yaml:"volumes,omitempty"`
}

func (dcy *dockerComposeConfig) Parse(data []byte) error {
	return yaml.Unmarshal(data, dcy)
}

func main() {
	data, err := ioutil.ReadFile("docker-compose.yml")
	if err != nil {
		log.Fatal(errors.Wrap(err, "unable to read docker-compose file"))
	}
	networkID, err := getNetwork()
	if err != nil {
		log.Fatal(err)
	}

	var dockerCyaml dockerComposeConfig
	if err := dockerCyaml.Parse(data); err != nil {
		log.Fatal(errors.Wrap(err, "unable to parse docker-compose file contents"))
	}

	var wg sync.WaitGroup

	for _, v := range dockerCyaml.Services {
		wg.Add(1)
		//fmt.Println("image, labels, v", v.Image, v.Labels, v)
		go fakepullImage(v, networkID, &wg)
		//go pullImage(v, networkID, &wg)
	}
	wg.Wait()

}

func fakepullImage(s serviceConfig, networkID string, wg *sync.WaitGroup) {
	defer wg.Done()
	myMap := make(map[string]string)

	if len(s.Labels) > 0 {
		for _, v := range s.Labels {

			fmt.Println("z::", fomatLabels(v))
			yo := fomatLabels(v)
			myMap[yo[0]] = yo[1]
			fmt.Println("map", myMap)
		}

		// fmt.Printf("labels: %#+v\n", s.Labels[0])
		// fmt.Printf("labels: %#+v\n", s.Labels[1])
	}

}
func pullImage(s serviceConfig, networkID string, wg *sync.WaitGroup) {
	defer wg.Done()
	formattedImageName := fomatImageName(s.Image)
	fmt.Println()
	fmt.Println("dockerImage, networkID, name:", s.Image, networkID, formattedImageName)
	fmt.Println()
	ctx := context.Background()
	cli, err := client.NewEnvClient()
	if err != nil {
		panic(errors.Wrap(err, "unable to intialize docker client"))
	}

	imagePullResp, err := cli.ImagePull(
		ctx,
		s.Image,
		types.ImagePullOptions{})
	if err != nil {
		panic(errors.Wrap(err, "unable to pull image"))
	}
	defer imagePullResp.Close()
	_, err = io.Copy(os.Stdout, imagePullResp)
	if err != nil {
		log.Println(errors.Wrap(err, "unable to write to stdout"))
	}

	containerCreateResp, err := cli.ContainerCreate(
		ctx,
		&container.Config{Image: s.Image},
		&container.HostConfig{PublishAllPorts: true},
		nil,
		formattedImageName)
	if err != nil {
		log.Fatal(errors.Wrap(err, "unable to create container"))
	}

	err = cli.NetworkConnect(
		ctx,
		networkID,
		containerCreateResp.ID,
		&network.EndpointSettings{})
	if err != nil {
		log.Fatal(errors.Wrap(err, "unable to connect container to network"))
	}

	err = cli.ContainerStart(
		ctx,
		containerCreateResp.ID,
		types.ContainerStartOptions{})
	if err != nil {
		panic(errors.Wrap(err, "unable to start container"))
	}

	containerLogResp, err := cli.ContainerLogs(
		ctx,
		containerCreateResp.ID,
		types.ContainerLogsOptions{
			ShowStdout: true,
			ShowStderr: true,
			Timestamps: true})
	if err != nil {
		panic(errors.Wrap(err, "unable to get container logs"))
	}
	defer containerLogResp.Close()

	_, err = io.Copy(os.Stdout, containerLogResp)
	if err != nil {
		log.Println(errors.Wrap(err, "unable to write to stdout"))
	}
}

func fomatImageName(imagename string) string {
	f := func(c rune) bool {
		if c == 58 {
			// 58 is the ':' character
			return true
		}
		return false
	}
	return strings.FieldsFunc(imagename, f)[0]
}

func fomatLabels(label string) []string {
	f := func(c rune) bool {
		if c == 58 {
			// 58 is the ':' character
			return true
		} else if c == 61 {
			//61 is '=' char
			return true
		}
		return false
	}
	return strings.FieldsFunc(label, f)
}
<|endoftext|>


<commit_before>package signature

import ".."

// Arguments represents a structured set of arguments passed to a predicate.
type Arguments struct {
	positionals   []*vm.Thunk
	expandedList  *vm.Thunk
	keywords      []KeywordArgument
	expandedDicts []*vm.Thunk
}

// NewArguments creates a new Arguments.
func NewArguments(
	ps []PositionalArgument,
	ks []KeywordArgument,
	expandedDicts []*vm.Thunk) Arguments {
	ts := make([]*vm.Thunk, 0, len(ps))

	l := (*vm.Thunk)(nil)

	for i, p := range ps {
		if p.expanded {
			l = mergeRestPositionalArgs(ps[i:]...)
			break
		}

		ts = append(ts, p.value)
	}

	return Arguments{
		positionals:   ts,
		expandedList:  l,
		keywords:      ks,
		expandedDicts: expandedDicts,
	}
}

func mergeRestPositionalArgs(ps ...PositionalArgument) *vm.Thunk {
	if !ps[0].expanded {
		panic("First PositionalArgument must be a list.")
	}

	t := ps[0].value

	for _, p := range ps[1:] {
		if p.expanded {
			t = vm.App(vm.Merge, t, p.value)
		} else {
			t = vm.App(vm.Append, t, p.value)
		}
	}

	return t
}

func (args *Arguments) nextPositional() *vm.Thunk {
	if len(args.positionals) != 0 {
		defer func() { args.positionals = args.positionals[1:] }()
		return args.positionals[0]
	}

	if args.expandedList == nil {
		return nil
	}

	defer func() { args.expandedList = vm.App(vm.Rest, args.expandedList) }()
	return vm.App(vm.First, args.expandedList)
}

func (args Arguments) restPositionals() *vm.Thunk {
	if args.expandedList == nil {
		return vm.NewList(args.positionals...)
	}

	if len(args.positionals) == 0 {
		return args.expandedList
	}

	return vm.App(vm.Merge, vm.NewList(args.positionals...), args.expandedList)
}

func (args *Arguments) searchKeyword(s string) *vm.Thunk {
	for i, k := range args.keywords {
		if s == k.name {
			args.keywords = append(args.keywords[:i], args.keywords[i+1:]...)
			return k.value
		}
	}

	for i, t := range args.expandedDicts {
		o := t.Eval()
		d, ok := o.(vm.DictionaryType)

		if !ok {
			return vm.NotDictionaryError(o)
		}

		k := vm.StringType(s)

		if v, ok := d.Search(k); ok {
			args.expandedDicts[i] = vm.Normal(d.Remove(k))
			return v.(*vm.Thunk)
		}
	}

	return nil
}

func (args Arguments) restKeywords() *vm.Thunk {
	t := vm.EmptyDictionary

	for _, k := range args.keywords {
		t = vm.App(vm.Set, t, vm.NewString(k.name), k.value)
	}

	for _, tt := range args.expandedDicts {
		t = vm.App(vm.Merge, t, tt)
	}

	return t
}
<commit_msg>Implement Arguments.Merge()<commit_after>package signature

import ".."

// Arguments represents a structured set of arguments passed to a predicate.
type Arguments struct {
	positionals   []*vm.Thunk
	expandedList  *vm.Thunk
	keywords      []KeywordArgument
	expandedDicts []*vm.Thunk
}

// NewArguments creates a new Arguments.
func NewArguments(
	ps []PositionalArgument,
	ks []KeywordArgument,
	expandedDicts []*vm.Thunk) Arguments {
	ts := make([]*vm.Thunk, 0, len(ps))

	l := (*vm.Thunk)(nil)

	for i, p := range ps {
		if p.expanded {
			l = mergeRestPositionalArgs(ps[i:]...)
			break
		}

		ts = append(ts, p.value)
	}

	return Arguments{
		positionals:   ts,
		expandedList:  l,
		keywords:      ks,
		expandedDicts: expandedDicts,
	}
}

func mergeRestPositionalArgs(ps ...PositionalArgument) *vm.Thunk {
	if !ps[0].expanded {
		panic("First PositionalArgument must be a list.")
	}

	t := ps[0].value

	for _, p := range ps[1:] {
		if p.expanded {
			t = vm.App(vm.Merge, t, p.value)
		} else {
			t = vm.App(vm.Append, t, p.value)
		}
	}

	return t
}

func (args *Arguments) nextPositional() *vm.Thunk {
	if len(args.positionals) != 0 {
		defer func() { args.positionals = args.positionals[1:] }()
		return args.positionals[0]
	}

	if args.expandedList == nil {
		return nil
	}

	defer func() { args.expandedList = vm.App(vm.Rest, args.expandedList) }()
	return vm.App(vm.First, args.expandedList)
}

func (args Arguments) restPositionals() *vm.Thunk {
	if args.expandedList == nil {
		return vm.NewList(args.positionals...)
	}

	if len(args.positionals) == 0 {
		return args.expandedList
	}

	return vm.App(vm.Merge, vm.NewList(args.positionals...), args.expandedList)
}

func (args *Arguments) searchKeyword(s string) *vm.Thunk {
	for i, k := range args.keywords {
		if s == k.name {
			args.keywords = append(args.keywords[:i], args.keywords[i+1:]...)
			return k.value
		}
	}

	for i, t := range args.expandedDicts {
		o := t.Eval()
		d, ok := o.(vm.DictionaryType)

		if !ok {
			return vm.NotDictionaryError(o)
		}

		k := vm.StringType(s)

		if v, ok := d.Search(k); ok {
			args.expandedDicts[i] = vm.Normal(d.Remove(k))
			return v.(*vm.Thunk)
		}
	}

	return nil
}

func (args Arguments) restKeywords() *vm.Thunk {
	t := vm.EmptyDictionary

	for _, k := range args.keywords {
		t = vm.App(vm.Set, t, vm.NewString(k.name), k.value)
	}

	for _, tt := range args.expandedDicts {
		t = vm.App(vm.Merge, t, tt)
	}

	return t
}

func (original Arguments) Merge(merged Arguments) Arguments {
	var new Arguments

	if new.expandedList == nil {
		new.positionals = append(original.positionals, merged.positionals...)
		new.expandedList = merged.expandedList
	} else {
		new.positionals = original.positionals
		new.expandedList = vm.App(
			vm.Append,
			append([]*vm.Thunk{original.expandedList}, merged.positionals...)...)

		if merged.expandedList != nil {
			new.expandedList = vm.App(vm.Merge, new.expandedList, merged.expandedList)
		}
	}

	new.keywords = append(original.keywords, merged.keywords...)
	new.expandedDicts = append(original.expandedDicts, merged.expandedDicts...)

	return new
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"flag"
	"io"
	"log"
	"math"
	"os"
	"strings"
)

var (
	input_file = flag.String("input", "", "Input file with transactions")
	output_dir = flag.String("output", "", "A dir to store created clusters to")
)

type Cluster struct {
	id        int
	n         float64
	w         float64
	s         float64
	instances map[string]bool
	occ       map[string]int
}

type Transaction struct {
	cluster  *Cluster
	instance string
	items    []string
}

func getProfit(s, w, r float64) float64 {
	return s / math.Pow(w, r)
}

func newCluster(id int) *Cluster {
	return &Cluster{id: id, n: 0, w: 0, s: 0, instances: make(map[string]bool, 0), occ: make(map[string]int, 0)}
}

func (c *Cluster) addItem(item string) {
	val, found := c.occ[item]
	if !found {
		c.occ[item] = 1
	} else {
		c.occ[item] = val + 1
	}
}

func (c *Cluster) getProfit(items []string, r float64) float64 {
	sNew := c.s + float64(len(items))
	wNew := c.w
	for _, item := range items {
		if _, found := c.occ[item]; !found {
			wNew++
		}
	}
	if c.n == 0 {
		return getProfit(sNew, wNew, r)
	} else {
		profit := getProfit(c.s*c.n, c.w, r)
		profitNew := getProfit(sNew*(c.n+1), wNew, r)
		return profitNew - profit
	}
}

func (c *Cluster) removeItem(item string) {
	val, found := c.occ[item]
	if !found {
		return
	}
	if val == 1 {
		delete(c.occ, item)
	}
	c.occ[item] -= 1
}

func (c *Cluster) addTransaction(trans *Transaction) {
	for _, item := range trans.items {
		c.addItem(item)
	}
	c.w = float64(len(c.occ))
	c.n++
	c.instances[trans.instance] = true
	trans.cluster = c
}

func (c *Cluster) removeTransaction(trans *Transaction) {
	for _, item := range trans.items {
		c.removeItem(item)
	}
	c.w = float64(len(c.occ))
	c.n--
	delete(c.instances, trans.instance)
	trans.cluster = nil
}

func clusterize(data []*Transaction, repulsion float64) []*Cluster {
	log.Print(data)
	if repulsion == 0 {
		repulsion = 4.0 // default value
	}
	var clusters []*Cluster
	for _, transaction := range data {
		clusters = addTransactionToBestCluster(clusters, transaction, repulsion)
	}
	log.Print(clusters)
	for {
		moved := false
		for _, transaction := range data {
			originalClusterId := transaction.cluster.id
			transaction.cluster.removeTransaction(transaction)
			clusters = addTransactionToBestCluster(clusters, transaction, repulsion)
			if transaction.cluster.id != originalClusterId {
				moved = true
			}
		}
		if !moved {
			break
		}
	}
	log.Printf("Finished %v", clusters)
	return clusters
}

func addTransactionToBestCluster(clusters []*Cluster, transaction *Transaction, repulsion float64) []*Cluster {
	if len(clusters) > 0 {
		tempS := float64(len(transaction.items))
		tempW := tempS
		profitMax := getProfit(tempS, tempW, repulsion)
		log.Printf("Profit max %f", profitMax)
		for _, cluster := range clusters {
			clusterProfit := cluster.getProfit(transaction.items, repulsion)
			log.Printf("Cluster profit %f", clusterProfit)
			if clusterProfit >= profitMax {
				cluster.addTransaction(transaction)
				return clusters
			}
		}
	}

	cluster := newCluster(len(clusters))
	cluster.addTransaction(transaction)
	return append(clusters, cluster)
}

func main() {
	flag.Parse()
	if *input_file == "" {
		log.Fatal("You must provide input file")
	}
	// if output_dir == ""{
	// 	log.Fail("You must provide output dir")
	// }
	file, err := os.Open(*input_file)
	if err != nil {
		log.Fatalf("Cannot open config file at [%s]: [%s]\n", *input_file, err)
	}
	defer file.Close()
	r := bufio.NewReader(file)
	var transactions []*Transaction
	for {
		line, err := r.ReadString('\n')

		if err != nil && line == "" {
			if err == io.EOF {
				break
			}
			log.Fatalf("Error when reading file [%s]: [%s]\n", *input_file, err)
		}
		instance := strings.TrimSuffix(line, "\n")
		items := make([]string, 0)
		visited := make(map[string]bool)
		for _, item := range strings.Split(instance, " ") {
			if _, found := visited[item]; !found {
				items = append(items, item)
				visited[item] = true
			}
		}
		transactions = append(transactions, &Transaction{instance: instance, items: items})
	}
	clusterize(transactions, 4.0)

}
<commit_msg>implemented writing to cluster<commit_after>package main

import (
	"bufio"
	"flag"
	"fmt"
	"io"
	"log"
	"math"
	"os"
	"strings"
)

var (
	input_file = flag.String("input", "", "Input file with transactions")
	output_dir = flag.String("output", "", "A dir to store created clusters to")
)

type Cluster struct {
	id        int
	n         float64
	w         float64
	s         float64
	instances map[string]bool
	occ       map[string]int
}

type Transaction struct {
	cluster  *Cluster
	instance string
	items    []string
}

func getProfit(s, w, r float64) float64 {
	return s / math.Pow(w, r)
}

func newCluster(id int) *Cluster {
	return &Cluster{id: id, n: 0, w: 0, s: 0, instances: make(map[string]bool, 0), occ: make(map[string]int, 0)}
}

func (c *Cluster) addItem(item string) {
	val, found := c.occ[item]
	if !found {
		c.occ[item] = 1
	} else {
		c.occ[item] = val + 1
	}
}

func (c *Cluster) getProfit(items []string, r float64) float64 {
	sNew := c.s + float64(len(items))
	wNew := c.w
	for _, item := range items {
		if _, found := c.occ[item]; !found {
			wNew++
		}
	}
	if c.n == 0 {
		return getProfit(sNew, wNew, r)
	} else {
		profit := getProfit(c.s*c.n, c.w, r)
		profitNew := getProfit(sNew*(c.n+1), wNew, r)
		return profitNew - profit
	}
}

func (c *Cluster) removeItem(item string) {
	val, found := c.occ[item]
	if !found {
		return
	}
	if val == 1 {
		delete(c.occ, item)
	}
	c.occ[item] -= 1
}

func (c *Cluster) addTransaction(trans *Transaction) {
	for _, item := range trans.items {
		c.addItem(item)
	}
	c.w = float64(len(c.occ))
	c.n++
	c.instances[trans.instance] = true
	trans.cluster = c
}

func (c *Cluster) removeTransaction(trans *Transaction) {
	for _, item := range trans.items {
		c.removeItem(item)
	}
	c.w = float64(len(c.occ))
	c.n--
	delete(c.instances, trans.instance)
	trans.cluster = nil
}

func clusterize(data []*Transaction, repulsion float64) []*Cluster {
	log.Print(data)
	if repulsion == 0 {
		repulsion = 4.0 // default value
	}
	var clusters []*Cluster
	for _, transaction := range data {
		clusters = addTransactionToBestCluster(clusters, transaction, repulsion)
	}
	log.Print(clusters)
	for {
		moved := false
		for _, transaction := range data {
			originalClusterId := transaction.cluster.id
			transaction.cluster.removeTransaction(transaction)
			clusters = addTransactionToBestCluster(clusters, transaction, repulsion)
			if transaction.cluster.id != originalClusterId {
				moved = true
			}
		}
		if !moved {
			break
		}
	}
	log.Printf("Finished %v", clusters)
	return clusters
}

func addTransactionToBestCluster(clusters []*Cluster, transaction *Transaction, repulsion float64) []*Cluster {
	if len(clusters) > 0 {
		tempS := float64(len(transaction.items))
		tempW := tempS
		profitMax := getProfit(tempS, tempW, repulsion)
		log.Printf("Profit max %f", profitMax)
		for _, cluster := range clusters {
			clusterProfit := cluster.getProfit(transaction.items, repulsion)
			log.Printf("Cluster profit %f", clusterProfit)
			if clusterProfit >= profitMax {
				cluster.addTransaction(transaction)
				return clusters
			}
		}
	}

	cluster := newCluster(len(clusters))
	cluster.addTransaction(transaction)
	return append(clusters, cluster)
}

func main() {
	flag.Parse()
	if *input_file == "" {
		log.Fatal("You must provide input file")
	}
	if *output_dir == "" {
		log.Fatal("You must provide output dir")
	}
	file, err := os.Open(*input_file)
	if err != nil {
		log.Fatalf("Cannot open transaction file at [%s]: [%s]\n", *input_file, err)
	}
	defer file.Close()
	r := bufio.NewReader(file)
	var transactions []*Transaction
	for {
		line, err := r.ReadString('\n')

		if err != nil && line == "" {
			if err == io.EOF {
				break
			}
			log.Fatalf("Error when reading file [%s]: [%s]\n", *input_file, err)
		}
		instance := strings.TrimSuffix(line, "\n")
		items := make([]string, 0)
		visited := make(map[string]bool)
		for _, item := range strings.Split(instance, " ") {
			if _, found := visited[item]; !found {
				items = append(items, item)
				visited[item] = true
			}
		}
		transactions = append(transactions, &Transaction{instance: instance, items: items})
	}
	for _, cluster := range clusterize(transactions, 4.0) {
		file, err := os.Create(fmt.Sprintf("%s/cluster_%d.txt", *output_dir, cluster.id))
		if err != nil {
			log.Fatalf("Cannot open cluster file at [%s]: [%s]\n", *input_file, err)
		}
		for instance, _ := range cluster.instances {
			file.WriteString(fmt.Sprintf("%s\n", instance))
		}
		file.Close()
	}
}
<|endoftext|>