<commit_before>// +build windows

package ole

import "testing"

func wrapCOMExecute(t *testing.T, callback func(*testing.T)) {
	defer func() {
		if r := recover(); r != nil {
			t.Error(r)
		}
	}()

	err := CoInitialize(0)
	if err != nil {
		t.Fatal(err)
	}
	defer CoUninitialize()

	callback(t)
}

func wrapDispatch(t *testing.T, ClassID, UnknownInterfaceID, DispatchInterfaceID *GUID, callback func(*testing.T, *IUnknown, *IDispatch)) {
	var unknown *IUnknown
	var dispatch *IDispatch

	unknown, err = CreateInstance(ClassID, UnknownInterfaceID)
	if err != nil {
		t.Error(err)
		return
	}
	defer unknown.Release()

	dispatch, err = unknown.QueryInterface(DispatchInterfaceID)
	if err != nil {
		t.Error(err)
		return
	}
	defer dispatch.Release()

	callback(t, unknown, dispatch)
}

func wrapGoOLETestCOMServer(t *testing.T, callback func(*testing.T, *IUnknown, *IDispatch)) {
	wrapCOMExecute(t, func(t *testing.T) {
		wrapDispatch(t, CLSID_COMEchoTestObject, IID_IUnknown, IID_ICOMEchoTestObject, callback)
	})
}

func TestIDispatch_goolecomserver_echostring(t *testing.T) {
	wrapGoOLETestCOMServer(t, func(t *testing.T, unknown *IUnknown, idispatch *IDispatch) {
		method := "EchoString"
		expected := "Test String"
		variant, err := idispatch.CallMethod(method, expected)
		if err != nil {
			t.Error(err)
		}
		actual := variant.Value().(string)
		if actual != expected {
			t.Errorf("%s() expected %v did not match %v", method, expected, value)
		}
	})
}

func TestIDispatch_goolecomserver_echoint8(t *testing.T) {
	wrapGoOLETestCOMServer(t, func(t *testing.T, unknown *IUnknown, idispatch *IDispatch) {
		method := "EchoInt8"
		expected := int8(1)
		variant, err := idispatch.CallMethod(method, expected)
		if err != nil {
			t.Error(err)
		}
		actual := variant.Value().(int8)
		if actual != expected {
			t.Errorf("%s() expected %v did not match %v", method, expected, value)
		}
	})
}

func TestIDispatch_goolecomserver_echouint8(t *testing.T) {
	wrapGoOLETestCOMServer(t, func(t *testing.T, unknown *IUnknown, idispatch *IDispatch) {
		method := "EchoUInt8"
		expected := uint8(1)
		variant, err := idispatch.CallMethod(method, expected)
		if err != nil {
			t.Error(err)
		}
		actual := variant.Value().(uint8)
		if actual != expected {
			t.Errorf("%s() expected %v did not match %v", method, expected, value)
		}
	})
}

func TestIDispatch_goolecomserver_echoint16(t *testing.T) {
	wrapGoOLETestCOMServer(t, func(t *testing.T, unknown *IUnknown, idispatch *IDispatch) {
		method := "EchoInt16"
		expected := int16(1)
		variant, err := idispatch.CallMethod(method, expected)
		if err != nil {
			t.Error(err)
		}
		actual := variant.Value().(int16)
		if actual != expected {
			t.Errorf("%s() expected %v did not match %v", method, expected, value)
		}
	})
}

func TestIDispatch_goolecomserver_echouint16(t *testing.T) {
	wrapGoOLETestCOMServer(t, func(t *testing.T, unknown *IUnknown, idispatch *IDispatch) {
		method := "EchoUInt16"
		expected := uint16(1)
		variant, err := idispatch.CallMethod(method, expected)
		if err != nil {
			t.Error(err)
		}
		actual := variant.Value().(uint16)
		if actual != expected {
			t.Errorf("%s() expected %v did not match %v", method, expected, value)
		}
	})
}

func TestIDispatch_goolecomserver_echoint32(t *testing.T) {
	wrapGoOLETestCOMServer(t, func(t *testing.T, unknown *IUnknown, idispatch *IDispatch) {
		method := "EchoInt32"
		expected := int32(2)
		variant, err := idispatch.CallMethod(method, expected)
		if err != nil {
			t.Error(err)
		}
		actual := variant.Value().(int32)
		if actual != expected {
			t.Errorf("%s() expected %v did not match %v", method, expected, value)
		}
	})
}

func TestIDispatch_goolecomserver_echouint32(t *testing.T) {
	wrapGoOLETestCOMServer(t, func(t *testing.T, unknown *IUnknown, idispatch *IDispatch) {
		method := "EchoUInt32"
		expected := uint32(4)
		variant, err := idispatch.CallMethod(method, expected)
		if err != nil {
			t.Error(err)
		}
		actual := variant.Value().(uint32)
		if actual != expected {
			t.Errorf("%s() expected %v did not match %v", method, expected, value)
		}
	})
}

func TestIDispatch_goolecomserver_echoint64(t *testing.T) {
	wrapGoOLETestCOMServer(t, func(t *testing.T, unknown *IUnknown, idispatch *IDispatch) {
		method := "EchoInt64"
		expected := int64(1)
		variant, err := idispatch.CallMethod(method, expected)
		if err != nil {
			t.Error(err)
		}
		actual := variant.Value().(int64)
		if actual != expected {
			t.Errorf("%s() expected %v did not match %v", method, expected, value)
		}
	})
}

func TestIDispatch_goolecomserver_echouint64(t *testing.T) {
	wrapGoOLETestCOMServer(t, func(t *testing.T, unknown *IUnknown, idispatch *IDispatch) {
		method := "EchoUInt64"
		expected := uint64(1)
		variant, err := idispatch.CallMethod(method, expected)
		if err != nil {
			t.Error(err)
		}
		actual := variant.Value().(uint64)
		if actual != expected {
			t.Errorf("%s() expected %v did not match %v", method, expected, value)
		}
	})
}

func TestIDispatch_goolecomserver_echofloat32(t *testing.T) {
	wrapGoOLETestCOMServer(t, func(t *testing.T, unknown *IUnknown, idispatch *IDispatch) {
		method := "EchoFloat32"
		expected := float32(2.2)
		variant, err := idispatch.CallMethod(method, expected)
		if err != nil {
			t.Error(err)
		}
		actual := variant.Value().(float32)
		if actual != expected {
			t.Errorf("%s() expected %v did not match %v", method, expected, value)
		}
	})
}

func TestIDispatch_goolecomserver_echofloat64(t *testing.T) {
	wrapGoOLETestCOMServer(t, func(t *testing.T, unknown *IUnknown, idispatch *IDispatch) {
		method := "EchoFloat64"
		expected := float64(2.2)
		variant, err := idispatch.CallMethod(method, expected)
		if err != nil {
			t.Error(err)
		}
		actual := variant.Value().(float64)
		if actual != expected {
			t.Errorf("%s() expected %v did not match %v", method, expected, value)
		}
	})
}
<commit_msg>Copy and paste errors.<commit_after>// +build windows

package ole

import "testing"

func wrapCOMExecute(t *testing.T, callback func(*testing.T)) {
	defer func() {
		if r := recover(); r != nil {
			t.Error(r)
		}
	}()

	err := CoInitialize(0)
	if err != nil {
		t.Fatal(err)
	}
	defer CoUninitialize()

	callback(t)
}

func wrapDispatch(t *testing.T, ClassID, UnknownInterfaceID, DispatchInterfaceID *GUID, callback func(*testing.T, *IUnknown, *IDispatch)) {
	var unknown *IUnknown
	var dispatch *IDispatch
	var err error

	unknown, err = CreateInstance(ClassID, UnknownInterfaceID)
	if err != nil {
		t.Error(err)
		return
	}
	defer unknown.Release()

	dispatch, err = unknown.QueryInterface(DispatchInterfaceID)
	if err != nil {
		t.Error(err)
		return
	}
	defer dispatch.Release()

	callback(t, unknown, dispatch)
}

func wrapGoOLETestCOMServer(t *testing.T, callback func(*testing.T, *IUnknown, *IDispatch)) {
	wrapCOMExecute(t, func(t *testing.T) {
		wrapDispatch(t, CLSID_COMEchoTestObject, IID_IUnknown, IID_ICOMEchoTestObject, callback)
	})
}

func TestIDispatch_goolecomserver_echostring(t *testing.T) {
	wrapGoOLETestCOMServer(t, func(t *testing.T, unknown *IUnknown, idispatch *IDispatch) {
		method := "EchoString"
		expected := "Test String"
		variant, err := idispatch.CallMethod(method, expected)
		if err != nil {
			t.Error(err)
		}
		actual := variant.Value().(string)
		if actual != expected {
			t.Errorf("%s() expected %v did not match %v", method, expected, actual)
		}
	})
}

func TestIDispatch_goolecomserver_echoint8(t *testing.T) {
	wrapGoOLETestCOMServer(t, func(t *testing.T, unknown *IUnknown, idispatch *IDispatch) {
		method := "EchoInt8"
		expected := int8(1)
		variant, err := idispatch.CallMethod(method, expected)
		if err != nil {
			t.Error(err)
		}
		actual := variant.Value().(int8)
		if actual != expected {
			t.Errorf("%s() expected %v did not match %v", method, expected, actual)
		}
	})
}

func TestIDispatch_goolecomserver_echouint8(t *testing.T) {
	wrapGoOLETestCOMServer(t, func(t *testing.T, unknown *IUnknown, idispatch *IDispatch) {
		method := "EchoUInt8"
		expected := uint8(1)
		variant, err := idispatch.CallMethod(method, expected)
		if err != nil {
			t.Error(err)
		}
		actual := variant.Value().(uint8)
		if actual != expected {
			t.Errorf("%s() expected %v did not match %v", method, expected, actual)
		}
	})
}

func TestIDispatch_goolecomserver_echoint16(t *testing.T) {
	wrapGoOLETestCOMServer(t, func(t *testing.T, unknown *IUnknown, idispatch *IDispatch) {
		method := "EchoInt16"
		expected := int16(1)
		variant, err := idispatch.CallMethod(method, expected)
		if err != nil {
			t.Error(err)
		}
		actual := variant.Value().(int16)
		if actual != expected {
			t.Errorf("%s() expected %v did not match %v", method, expected, actual)
		}
	})
}

func TestIDispatch_goolecomserver_echouint16(t *testing.T) {
	wrapGoOLETestCOMServer(t, func(t *testing.T, unknown *IUnknown, idispatch *IDispatch) {
		method := "EchoUInt16"
		expected := uint16(1)
		variant, err := idispatch.CallMethod(method, expected)
		if err != nil {
			t.Error(err)
		}
		actual := variant.Value().(uint16)
		if actual != expected {
			t.Errorf("%s() expected %v did not match %v", method, expected, actual)
		}
	})
}

func TestIDispatch_goolecomserver_echoint32(t *testing.T) {
	wrapGoOLETestCOMServer(t, func(t *testing.T, unknown *IUnknown, idispatch *IDispatch) {
		method := "EchoInt32"
		expected := int32(2)
		variant, err := idispatch.CallMethod(method, expected)
		if err != nil {
			t.Error(err)
		}
		actual := variant.Value().(int32)
		if actual != expected {
			t.Errorf("%s() expected %v did not match %v", method, expected, actual)
		}
	})
}

func TestIDispatch_goolecomserver_echouint32(t *testing.T) {
	wrapGoOLETestCOMServer(t, func(t *testing.T, unknown *IUnknown, idispatch *IDispatch) {
		method := "EchoUInt32"
		expected := uint32(4)
		variant, err := idispatch.CallMethod(method, expected)
		if err != nil {
			t.Error(err)
		}
		actual := variant.Value().(uint32)
		if actual != expected {
			t.Errorf("%s() expected %v did not match %v", method, expected, actual)
		}
	})
}

func TestIDispatch_goolecomserver_echoint64(t *testing.T) {
	wrapGoOLETestCOMServer(t, func(t *testing.T, unknown *IUnknown, idispatch *IDispatch) {
		method := "EchoInt64"
		expected := int64(1)
		variant, err := idispatch.CallMethod(method, expected)
		if err != nil {
			t.Error(err)
		}
		actual := variant.Value().(int64)
		if actual != expected {
			t.Errorf("%s() expected %v did not match %v", method, expected, actual)
		}
	})
}

func TestIDispatch_goolecomserver_echouint64(t *testing.T) {
	wrapGoOLETestCOMServer(t, func(t *testing.T, unknown *IUnknown, idispatch *IDispatch) {
		method := "EchoUInt64"
		expected := uint64(1)
		variant, err := idispatch.CallMethod(method, expected)
		if err != nil {
			t.Error(err)
		}
		actual := variant.Value().(uint64)
		if actual != expected {
			t.Errorf("%s() expected %v did not match %v", method, expected, actual)
		}
	})
}

func TestIDispatch_goolecomserver_echofloat32(t *testing.T) {
	wrapGoOLETestCOMServer(t, func(t *testing.T, unknown *IUnknown, idispatch *IDispatch) {
		method := "EchoFloat32"
		expected := float32(2.2)
		variant, err := idispatch.CallMethod(method, expected)
		if err != nil {
			t.Error(err)
		}
		actual := variant.Value().(float32)
		if actual != expected {
			t.Errorf("%s() expected %v did not match %v", method, expected, actual)
		}
	})
}

func TestIDispatch_goolecomserver_echofloat64(t *testing.T) {
	wrapGoOLETestCOMServer(t, func(t *testing.T, unknown *IUnknown, idispatch *IDispatch) {
		method := "EchoFloat64"
		expected := float64(2.2)
		variant, err := idispatch.CallMethod(method, expected)
		if err != nil {
			t.Error(err)
		}
		actual := variant.Value().(float64)
		if actual != expected {
			t.Errorf("%s() expected %v did not match %v", method, expected, actual)
		}
	})
}
<|endoftext|>


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

package profilescmdline

import (
	"fmt"
	"strings"

	"v.io/jiri/jiri"
	"v.io/jiri/profiles"
	"v.io/jiri/profiles/profilesmanager"
	"v.io/jiri/runutil"
)

// profileManager is implemented for both in-process and sub-command
// implemented profiles.
type profileManager interface {
	install(jirix *jiri.X, cl *installFlagValues, root jiri.RelPath) error
	uninstall(jirix *jiri.X, cl *uninstallFlagValues, root jiri.RelPath) error
	update(jirix *jiri.X, cl *updateFlagValues, root jiri.RelPath) error
	cleanup(jirix *jiri.X, cl *cleanupFlagValues, root jiri.RelPath) error
	mgrName() string
}

func newProfileManager(name string, db *profiles.DB) profileManager {
	installer, profile := profiles.SplitProfileName(name)
	installer = strings.TrimSpace(installer)
	if len(installer) == 0 || installer == profileInstaller {
		return &inproc{installer, profile, name, db}
	}
	return &subcommand{installer, profile, name, db}
}

type inproc struct {
	installer, name, qname string
	db                     *profiles.DB
}

func (ip *inproc) mgrName() string {
	return ip.qname
}

func (ip *inproc) install(jirix *jiri.X, cl *installFlagValues, root jiri.RelPath) error {
	mgr := profilesmanager.LookupManager(ip.qname)
	if mgr == nil {
		return fmt.Errorf("profile %v is not available via this installer %q", ip.qname, ip.installer)
	}
	def, err := targetAtDefaultVersion(mgr, cl.target)
	if err != nil {
		return err
	}
	err = mgr.Install(jirix, ip.db, root, def)
	logResult(jirix, "Install", mgr, def, err)
	return err
}

func (ip *inproc) uninstall(jirix *jiri.X, cl *uninstallFlagValues, root jiri.RelPath) error {
	profile := ip.db.LookupProfile(ip.installer, ip.name)
	if profile == nil {
		fmt.Fprintf(jirix.Stdout(), "%s is not installed\n", ip.qname)
		return nil
	}
	mgr := profilesmanager.LookupManager(ip.qname)
	var targets []*profiles.Target
	if cl.allTargets {
		targets = profile.Targets()
	} else {
		def, err := targetAtDefaultVersion(mgr, cl.target)
		if err != nil {
			return err
		}
		targets = []*profiles.Target{&def}
	}
	for _, target := range targets {
		if err := mgr.Uninstall(jirix, ip.db, root, *target); err != nil {
			logResult(jirix, "Uninstall", mgr, *target, err)
			return err
		}
		logResult(jirix, "Uninstall", mgr, *target, nil)
	}
	return nil
}

func (ip *inproc) update(jirix *jiri.X, cl *updateFlagValues, root jiri.RelPath) error {
	profile := ip.db.LookupProfile(ip.installer, ip.name)
	if profile == nil {
		// silently ignore uninstalled profile.
		return nil
	}
	mgr := profilesmanager.LookupManager(ip.qname)
	vi := mgr.VersionInfo()
	for _, target := range profile.Targets() {
		if vi.IsTargetOlderThanDefault(target.Version()) {
			if cl.verbose {
				fmt.Fprintf(jirix.Stdout(), "Updating %s %s from %q to %s\n", ip.qname, target, target.Version(), vi)
			}
			target.SetVersion(vi.Default())
			err := mgr.Install(jirix, ip.db, root, *target)
			logResult(jirix, "Update", mgr, *target, err)
			if err != nil {
				return err
			}
		} else {
			if cl.verbose {
				fmt.Fprintf(jirix.Stdout(), "%s %s at %q is up to date(%s)\n", ip.qname, target, target.Version(), vi)
			}
		}
	}
	return nil
}

func cleanupGC(jirix *jiri.X, db *profiles.DB, root jiri.RelPath, verbose bool, name string) error {
	mgr := profilesmanager.LookupManager(name)
	if mgr == nil {
		fmt.Fprintf(jirix.Stderr(), "%s is not linked into this binary\n", name)
		return nil
	}
	vi := mgr.VersionInfo()
	installer, profileName := profiles.SplitProfileName(name)
	profile := db.LookupProfile(installer, profileName)
	for _, target := range profile.Targets() {
		if vi.IsTargetOlderThanDefault(target.Version()) {
			err := mgr.Uninstall(jirix, db, root, *target)
			logResult(jirix, "Cleanup: -gc", mgr, *target, err)
			if err != nil {
				return err
			}
		}
	}
	return nil
}

func cleanupRmAll(jirix *jiri.X, db *profiles.DB, root jiri.RelPath) error {
	s := jirix.NewSeq()
	if err := s.AssertFileExists(db.Path()).Remove(db.Path()).Done(); err != nil && !runutil.IsNotExist(err) {
		return err
	}
	d := root.Abs(jirix)
	err := s.AssertDirExists(d).
		Run("chmod", "-R", "u+w", d).
		RemoveAll(d).
		Done()
	fmt.Fprintf(jirix.Stdout(), "Cleanup: -rm-all: ")
	if err == nil || runutil.IsNotExist(err) {
		fmt.Fprintf(jirix.Stdout(), "success\n")
		return nil
	} else {
		fmt.Fprintf(jirix.Stdout(), "%v\n", err)
	}
	return err
}

func (ip *inproc) cleanup(jirix *jiri.X, cl *cleanupFlagValues, root jiri.RelPath) error {
	if cl.gc {
		if cl.verbose {
			fmt.Fprintf(jirix.Stdout(), "Removing targets older than the default version for %s\n", ip.qname)
		}
		if err := cleanupGC(jirix, ip.db, root, cl.verbose, ip.qname); err != nil {
			return fmt.Errorf("gc: %v", err)
		}
	}
	if cl.rmAll {
		if cl.verbose {
			fmt.Fprintf(jirix.Stdout(), "Removing profile manifest and all profile output files\n")
		}
		if err := cleanupRmAll(jirix, ip.db, root); err != nil {
			return err
		}
	}
	return nil
}

type subcommand struct {
	installer, profile, qname string
	db                        *profiles.DB
}

func (sc *subcommand) mgrName() string {
	return sc.qname
}

func (sc *subcommand) run(jirix *jiri.X, verb string, args []string) error {
	cl := []string{"profile-" + sc.installer, verb}
	cl = append(cl, args...)
	cl = append(cl, sc.qname)
	return jirix.NewSeq().Capture(jirix.Stdout(), jirix.Stderr()).Last("jiri", cl...)
}

func (sc *subcommand) install(jirix *jiri.X, cl *installFlagValues, root jiri.RelPath) error {
	return sc.run(jirix, "install", cl.args())
}

func (sc *subcommand) uninstall(jirix *jiri.X, cl *uninstallFlagValues, root jiri.RelPath) error {
	return sc.run(jirix, "uninstall", cl.args())
}

func (sc *subcommand) update(jirix *jiri.X, cl *updateFlagValues, root jiri.RelPath) error {
	return sc.run(jirix, "update", cl.args())
}

func (sc *subcommand) cleanup(jirix *jiri.X, cl *cleanupFlagValues, root jiri.RelPath) error {
	return sc.run(jirix, "cleanup", cl.args())
}

func logResult(jirix *jiri.X, action string, mgr profiles.Manager, target profiles.Target, err error) {
	fmt.Fprintf(jirix.Stdout(), "%s: %s %s: ", action, profiles.QualifiedProfileName(mgr.Installer(), mgr.Name()), target)
	if err == nil {
		fmt.Fprintf(jirix.Stdout(), "success\n")
	} else {
		fmt.Fprintf(jirix.Stdout(), "%v\n", err)
	}
}
<commit_msg>TBR: jiri: Don't try to upgrade a profile target if the default version is already installed.<commit_after>// Copyright 2015 The Vanadium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package profilescmdline

import (
	"fmt"
	"strings"

	"v.io/jiri/jiri"
	"v.io/jiri/profiles"
	"v.io/jiri/profiles/profilesmanager"
	"v.io/jiri/runutil"
)

// profileManager is implemented for both in-process and sub-command
// implemented profiles.
type profileManager interface {
	install(jirix *jiri.X, cl *installFlagValues, root jiri.RelPath) error
	uninstall(jirix *jiri.X, cl *uninstallFlagValues, root jiri.RelPath) error
	update(jirix *jiri.X, cl *updateFlagValues, root jiri.RelPath) error
	cleanup(jirix *jiri.X, cl *cleanupFlagValues, root jiri.RelPath) error
	mgrName() string
}

func newProfileManager(name string, db *profiles.DB) profileManager {
	installer, profile := profiles.SplitProfileName(name)
	installer = strings.TrimSpace(installer)
	if len(installer) == 0 || installer == profileInstaller {
		return &inproc{installer, profile, name, db}
	}
	return &subcommand{installer, profile, name, db}
}

type inproc struct {
	installer, name, qname string
	db                     *profiles.DB
}

func (ip *inproc) mgrName() string {
	return ip.qname
}

func (ip *inproc) install(jirix *jiri.X, cl *installFlagValues, root jiri.RelPath) error {
	mgr := profilesmanager.LookupManager(ip.qname)
	if mgr == nil {
		return fmt.Errorf("profile %v is not available via this installer %q", ip.qname, ip.installer)
	}
	def, err := targetAtDefaultVersion(mgr, cl.target)
	if err != nil {
		return err
	}
	err = mgr.Install(jirix, ip.db, root, def)
	logResult(jirix, "Install", mgr, def, err)
	return err
}

func (ip *inproc) uninstall(jirix *jiri.X, cl *uninstallFlagValues, root jiri.RelPath) error {
	profile := ip.db.LookupProfile(ip.installer, ip.name)
	if profile == nil {
		fmt.Fprintf(jirix.Stdout(), "%s is not installed\n", ip.qname)
		return nil
	}
	mgr := profilesmanager.LookupManager(ip.qname)
	var targets []*profiles.Target
	if cl.allTargets {
		targets = profile.Targets()
	} else {
		def, err := targetAtDefaultVersion(mgr, cl.target)
		if err != nil {
			return err
		}
		targets = []*profiles.Target{&def}
	}
	for _, target := range targets {
		if err := mgr.Uninstall(jirix, ip.db, root, *target); err != nil {
			logResult(jirix, "Uninstall", mgr, *target, err)
			return err
		}
		logResult(jirix, "Uninstall", mgr, *target, nil)
	}
	return nil
}

func (ip *inproc) update(jirix *jiri.X, cl *updateFlagValues, root jiri.RelPath) error {
	profile := ip.db.LookupProfile(ip.installer, ip.name)
	if profile == nil {
		// silently ignore uninstalled profile.
		return nil
	}
	mgr := profilesmanager.LookupManager(ip.qname)
	vi := mgr.VersionInfo()
	for _, target := range profile.Targets() {
		if vi.IsTargetOlderThanDefault(target.Version()) {
			if _, err := targetAtDefaultVersion(mgr, *target); err == nil {
				// Target with default version is already installed.
				continue
			}
			if cl.verbose {
				fmt.Fprintf(jirix.Stdout(), "Updating %s %s from %q to %s\n", ip.qname, target, target.Version(), vi)
			}
			target.SetVersion(vi.Default())
			err := mgr.Install(jirix, ip.db, root, *target)
			logResult(jirix, "Update", mgr, *target, err)
			if err != nil {
				return err
			}
		} else {
			if cl.verbose {
				fmt.Fprintf(jirix.Stdout(), "%s %s at %q is up to date(%s)\n", ip.qname, target, target.Version(), vi)
			}
		}
	}
	return nil
}

func cleanupGC(jirix *jiri.X, db *profiles.DB, root jiri.RelPath, verbose bool, name string) error {
	mgr := profilesmanager.LookupManager(name)
	if mgr == nil {
		fmt.Fprintf(jirix.Stderr(), "%s is not linked into this binary\n", name)
		return nil
	}
	vi := mgr.VersionInfo()
	installer, profileName := profiles.SplitProfileName(name)
	profile := db.LookupProfile(installer, profileName)
	for _, target := range profile.Targets() {
		if vi.IsTargetOlderThanDefault(target.Version()) {
			err := mgr.Uninstall(jirix, db, root, *target)
			logResult(jirix, "Cleanup: -gc", mgr, *target, err)
			if err != nil {
				return err
			}
		}
	}
	return nil
}

func cleanupRmAll(jirix *jiri.X, db *profiles.DB, root jiri.RelPath) error {
	s := jirix.NewSeq()
	if err := s.AssertFileExists(db.Path()).Remove(db.Path()).Done(); err != nil && !runutil.IsNotExist(err) {
		return err
	}
	d := root.Abs(jirix)
	err := s.AssertDirExists(d).
		Run("chmod", "-R", "u+w", d).
		RemoveAll(d).
		Done()
	fmt.Fprintf(jirix.Stdout(), "Cleanup: -rm-all: ")
	if err == nil || runutil.IsNotExist(err) {
		fmt.Fprintf(jirix.Stdout(), "success\n")
		return nil
	} else {
		fmt.Fprintf(jirix.Stdout(), "%v\n", err)
	}
	return err
}

func (ip *inproc) cleanup(jirix *jiri.X, cl *cleanupFlagValues, root jiri.RelPath) error {
	if cl.gc {
		if cl.verbose {
			fmt.Fprintf(jirix.Stdout(), "Removing targets older than the default version for %s\n", ip.qname)
		}
		if err := cleanupGC(jirix, ip.db, root, cl.verbose, ip.qname); err != nil {
			return fmt.Errorf("gc: %v", err)
		}
	}
	if cl.rmAll {
		if cl.verbose {
			fmt.Fprintf(jirix.Stdout(), "Removing profile manifest and all profile output files\n")
		}
		if err := cleanupRmAll(jirix, ip.db, root); err != nil {
			return err
		}
	}
	return nil
}

type subcommand struct {
	installer, profile, qname string
	db                        *profiles.DB
}

func (sc *subcommand) mgrName() string {
	return sc.qname
}

func (sc *subcommand) run(jirix *jiri.X, verb string, args []string) error {
	cl := []string{"profile-" + sc.installer, verb}
	cl = append(cl, args...)
	cl = append(cl, sc.qname)
	return jirix.NewSeq().Capture(jirix.Stdout(), jirix.Stderr()).Last("jiri", cl...)
}

func (sc *subcommand) install(jirix *jiri.X, cl *installFlagValues, root jiri.RelPath) error {
	return sc.run(jirix, "install", cl.args())
}

func (sc *subcommand) uninstall(jirix *jiri.X, cl *uninstallFlagValues, root jiri.RelPath) error {
	return sc.run(jirix, "uninstall", cl.args())
}

func (sc *subcommand) update(jirix *jiri.X, cl *updateFlagValues, root jiri.RelPath) error {
	return sc.run(jirix, "update", cl.args())
}

func (sc *subcommand) cleanup(jirix *jiri.X, cl *cleanupFlagValues, root jiri.RelPath) error {
	return sc.run(jirix, "cleanup", cl.args())
}

func logResult(jirix *jiri.X, action string, mgr profiles.Manager, target profiles.Target, err error) {
	fmt.Fprintf(jirix.Stdout(), "%s: %s %s: ", action, profiles.QualifiedProfileName(mgr.Installer(), mgr.Name()), target)
	if err == nil {
		fmt.Fprintf(jirix.Stdout(), "success\n")
	} else {
		fmt.Fprintf(jirix.Stdout(), "%v\n", err)
	}
}
<|endoftext|>


<commit_before>package examples

import (
	"fmt"
	"github.com/nerdzeu/nerdz-api/nerdz"
)

var (
	// Retrieves all the information about the user with ID 1
	// the second parameter, an error, is suppressed
	user, _ = nerdz.NewUser(1)
)

// prints all the friends informations
func findFriends() {
	// gets friends' information
	if friendsList := user.Friends(); friendsList != nil {
		fmt.Println("#### Friends ######")
		// Dereference the friendsList pointer
		for _, otherUser := range *friendsList {
			fmt.Printf("%+v", otherUser)
		}

		fmt.Println("##################")
	} else {
		fmt.Printf("User(%d) hasn't any friends", user.Counter)
	}

}
<commit_msg>Update find_friends.go<commit_after>package examples

import (
	"fmt"
	"github.com/nerdzeu/nerdz-api/nerdz"
)

var (
	// Retrieves all the information about the user with ID 1
	// the second parameter, an error, is suppressed
	user, _ = nerdz.NewUser(1)
)

// prints all the friends information
func findFriends() {
	// user.Friends() returns a pointer to an array whose elements are User
	if friendsList := user.Friends(); friendsList != nil {
		fmt.Println("#### Friends ######")
		// Dereference the pointer
		for _, otherUser := range *friendsList {
			fmt.Printf("%+v", otherUser)
		}

		fmt.Println("##################")
	} else {
		fmt.Printf("User(%d) hasn't any friends", user.Counter)
	}

}
<|endoftext|>


<commit_before>// Request package provides the request structure
// The package provides access to Headers, Cookies
// Query Params, Post Body and Upload Files
package request

import (
	"log"
	"net/http"
	"mime/multipart"
	"io"
	"net/url"
	"strings"
	"encoding/json"
	cookie "github.com/DronRathore/goexpress/cookie"
)

type Url struct{
	Username string
	Password string
	Url string
	Path string
	Fragment string
}

// Contains the reader to read the buffer content of
// uploading file
type File struct{
	Name string
	FormName string
	Reader *multipart.Part
}

// Request Structure
type Request struct{
	ref *http.Request
	fileReader *multipart.Reader
	Header map[string]string
	Method string
	URL string
	_url *url.URL
	Params map[string]string // a map to be filled by router
	Query map[string][]string
	Body map[string][]string
	Cookies *cookie.Cookie
	JSON *json.Decoder
}

func (req *Request) Init(request *http.Request) *Request{
	req.Header = make(map[string]string)
	req.Body = make(map[string][]string)
	req.Body = request.Form
	req.Cookies = &cookie.Cookie{}
	req.Cookies.InitReadOnly(request)
	req.Query = make(map[string][]string)
	req.Query = request.URL.Query()
	req.Method = strings.ToLower(request.Method)
	req.URL = request.URL.Path
	req.Params = make(map[string]string)
	req._url = request.URL
	req.fileReader = nil
	for key, value := range request.Header {
		req.Header[key] = value[0]
	}

	if req.Header["Content-Type"] == "application/json" {
		req.JSON = json.NewDecoder(request.Body)
	} else {
		request.ParseForm()
	}
	for key, value := range request.PostForm {
		req.Body[key] = value
	}
	return req
}

// todo: Parser for Array and interface
// func (req *Request) parseQuery(){
// 	req._url.RawQuery

// Returns the URL structure
func(req *Request) GetUrl() *url.URL {
	return req._url
}

// Helper that returns original raw http.Request object
func (req *Request) GetRaw() *http.Request{
	return req.ref
}

// In case of file upload request, this function returns a file struct to read
func (req *Request) GetFile() *File {
	if req.fileReader == nil {
		reader, err := req.ref.MultipartReader()
		if err != nil {
			panic("Couldn't get the reader attached")
		}
		req.fileReader = reader
	}
	part, err := req.fileReader.NextPart()
	if err == io.EOF {
		return nil
	}
	var file = &File{}
	file.Name = part.FileName()
	file.FormName = part.FormName()
	file.Reader = part
	return file
}
<commit_msg>lowercase header names<commit_after>// Request package provides the request structure
// The package provides access to Headers, Cookies
// Query Params, Post Body and Upload Files
package request

import (
	"net/http"
	"mime/multipart"
	"io"
	"net/url"
	"strings"
	"encoding/json"
	cookie "github.com/DronRathore/goexpress/cookie"
)

type Url struct{
	Username string
	Password string
	Url string
	Path string
	Fragment string
}

// Contains the reader to read the buffer content of
// uploading file
type File struct{
	Name string
	FormName string
	Reader *multipart.Part
}

// Request Structure
type Request struct{
	ref *http.Request
	fileReader *multipart.Reader
	Header map[string]string
	Method string
	URL string
	_url *url.URL
	Params map[string]string // a map to be filled by router
	Query map[string][]string
	Body map[string][]string
	Cookies *cookie.Cookie
	JSON *json.Decoder
}

func (req *Request) Init(request *http.Request) *Request{
	req.Header = make(map[string]string)
	req.Body = make(map[string][]string)
	req.Body = request.Form
	req.Cookies = &cookie.Cookie{}
	req.Cookies.InitReadOnly(request)
	req.Query = make(map[string][]string)
	req.Query = request.URL.Query()
	req.Method = strings.ToLower(request.Method)
	req.URL = request.URL.Path
	req.Params = make(map[string]string)
	req._url = request.URL
	req.fileReader = nil
	for key, value := range request.Header {
		// lowercase the header key names
		req.Header[strings.ToLower(key)] = value[0]
	}

	if req.Header["Content-Type"] == "application/json" {
		req.JSON = json.NewDecoder(request.Body)
	} else {
		request.ParseForm()
	}
	for key, value := range request.PostForm {
		req.Body[key] = value
	}
	return req
}

// todo: Parser for Array and interface
// func (req *Request) parseQuery(){
// 	req._url.RawQuery

// Returns the URL structure
func(req *Request) GetUrl() *url.URL {
	return req._url
}

// Helper that returns original raw http.Request object
func (req *Request) GetRaw() *http.Request{
	return req.ref
}

// In case of file upload request, this function returns a file struct to read
func (req *Request) GetFile() *File {
	if req.fileReader == nil {
		reader, err := req.ref.MultipartReader()
		if err != nil {
			panic("Couldn't get the reader attached")
		}
		req.fileReader = reader
	}
	part, err := req.fileReader.NextPart()
	if err == io.EOF {
		return nil
	}
	var file = &File{}
	file.Name = part.FileName()
	file.FormName = part.FormName()
	file.Reader = part
	return file
}
<|endoftext|>


<commit_before>package fcm

import "errors"

var (
	// ErrInvalidMessage occurs if push notitication message is nil.
	ErrInvalidMessage = errors.New("message is invalid")
	// ErrInvalidToken occurs if device token is empty.
	ErrInvalidToken = errors.New("device token is invalid")
	// ErrToManyRegIDs occurs when registration ids more then 1000.
	ErrToManyRegIDs = errors.New("too many registrations ids")
	// ErrInvalidTimeToLive occurs if TimeToLive more then 2419200.
	ErrInvalidTimeToLive = errors.New("messages time-to-live is invalid")
)

// Message represents list of targets, options, and payload for HTTP JSON messages.
type Message struct {
	Token                    string        `json:"to"`
	RegistrationIDs          []string      `json:"registration_ids,omitempty"`
	Condition                string        `json:"condition,omitempty"`
	CollapseKey              string        `json:"collapse_key,omitempty"`
	Priority                 string        `json:"priority,omitempty"`
	ContentAvailable         bool          `json:"content_available,omitempty"`
	DelayWhileIdle           bool          `json:"delay_while_idle,omitempty"`
	TimeToLive               int           `json:"time_to_live,omitempty"`
	DeliveryReceiptRequested bool          `json:"delivery_receipt_requested,omitempty"`
	DryRun                   bool          `json:"dry_run,omitempty"`
	Notification             *Notification `json:"notification,omitempty"`
	Data                     *Data         `json:"data,omitempty"`
}

// Notification specifies the predefined, user-visible key-value pairs
// of the notification payload
type Notification struct {
	Title        string `json:"title,omitempty"`
	Body         string `json:"body,omitempty"`
	Icon         string `json:"icon,omitempty"`
	Sound        string `json:"sound,omitempty"`
	Badge        string `json:"badge,omitempty"`
	Tag          string `json:"tag,omitempty"`
	Color        string `json:"color,omitempty"`
	ClickAction  string `json:"click_action,omitempty"`
	BodyLocKey   string `json:"body_loc_key,omitempty"`
	BodyLocArgs  string `json:"body_loc_args,omitempty"`
	TitleLocKey  string `json:"title_loc_key,omitempty"`
	TitleLocArgs string `json:"title_loc_args,omitempty"`
}

// Data specifies the custom key-value pairs of the message's payload.
type Data map[string]interface{}

// Validate returns an error if the message is not well-formed.
func (msg *Message) Validate() error {
	switch {
	case msg == nil:
		return ErrInvalidMessage
	case msg.Token == "":
		return ErrInvalidToken
	case len(msg.RegistrationIDs) > 1000:
		return ErrToManyRegIDs
	case msg.TimeToLive > 2419200:
		return ErrInvalidTimeToLive
	default:
		return nil
	}
}
<commit_msg>Send to list of tokens fix<commit_after>package fcm

import "errors"

var (
	// ErrInvalidMessage occurs if push notitication message is nil.
	ErrInvalidMessage = errors.New("message is invalid")
	// ErrInvalidToken occurs if device token is empty.
	ErrInvalidToken = errors.New("device token is invalid")
	// ErrToManyRegIDs occurs when registration ids more then 1000.
	ErrToManyRegIDs = errors.New("too many registrations ids")
	// ErrInvalidTimeToLive occurs if TimeToLive more then 2419200.
	ErrInvalidTimeToLive = errors.New("messages time-to-live is invalid")
)

// Message represents list of targets, options, and payload for HTTP JSON messages.
type Message struct {
	Token                    string        `json:"to,omitempty"`
	RegistrationIDs          []string      `json:"registration_ids,omitempty"`
	Condition                string        `json:"condition,omitempty"`
	CollapseKey              string        `json:"collapse_key,omitempty"`
	Priority                 string        `json:"priority,omitempty"`
	ContentAvailable         bool          `json:"content_available,omitempty"`
	DelayWhileIdle           bool          `json:"delay_while_idle,omitempty"`
	TimeToLive               int           `json:"time_to_live,omitempty"`
	DeliveryReceiptRequested bool          `json:"delivery_receipt_requested,omitempty"`
	DryRun                   bool          `json:"dry_run,omitempty"`
	Notification             *Notification `json:"notification,omitempty"`
	Data                     *Data         `json:"data,omitempty"`
}

// Notification specifies the predefined, user-visible key-value pairs
// of the notification payload
type Notification struct {
	Title        string `json:"title,omitempty"`
	Body         string `json:"body,omitempty"`
	Icon         string `json:"icon,omitempty"`
	Sound        string `json:"sound,omitempty"`
	Badge        string `json:"badge,omitempty"`
	Tag          string `json:"tag,omitempty"`
	Color        string `json:"color,omitempty"`
	ClickAction  string `json:"click_action,omitempty"`
	BodyLocKey   string `json:"body_loc_key,omitempty"`
	BodyLocArgs  string `json:"body_loc_args,omitempty"`
	TitleLocKey  string `json:"title_loc_key,omitempty"`
	TitleLocArgs string `json:"title_loc_args,omitempty"`
}

// Data specifies the custom key-value pairs of the message's payload.
type Data map[string]interface{}

// Validate returns an error if the message is not well-formed.
func (msg *Message) Validate() error {
	switch {
	case msg == nil:
		return ErrInvalidMessage
	case msg.Token == "" && len(msg.RegistrationIDs) == 0:
		return ErrInvalidToken
	case len(msg.RegistrationIDs) > 1000:
		return ErrToManyRegIDs
	case msg.TimeToLive > 2419200:
		return ErrInvalidTimeToLive
	default:
		return nil
	}
}
<|endoftext|>


<commit_before>// Discordgo - Discord bindings for Go
// Available at https://github.com/bwmarrin/discordgo

// Copyright 2015-2016 Bruce Marriner <bruce@sqls.net>.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// This file contains code related to the Message struct

package discordgo

import (
	"fmt"
	"strings"
)

// A Message stores all data related to a specific Discord message.
type Message struct {
	ID              string        `json:"id"`
	Author          *User         `json:"author"`
	Content         string        `json:"content"`
	Attachments     []*Attachment `json:"attachments"`
	Tts             bool          `json:"tts"`
	Embeds          []*Embed      `json:"embeds"`
	Timestamp       string        `json:"timestamp"`
	MentionEveryone bool          `json:"mention_everyone"`
	EditedTimestamp string        `json:"edited_timestamp"`
	Mentions        []*User       `json:"mentions"`
	ChannelID       string        `json:"channel_id"`
}

// An Attachment stores data for message attachments.
type Attachment struct {
	Width    int    `json:"width"`
	URL      string `json:"url"`
	Size     int    `json:"size"`
	ProxyURL string `json:"proxy_url"`
	ID       string `json:"id"`
	Height   int    `json:"height"`
	Filename string `json:"filename"`
}

// An Embed stores data for message embeds.
type Embed struct { // TODO figure this out
}

// ContentWithMentionsReplaced will replace all @<id> mentions with the
// username of the mention.
func (m *Message) ContentWithMentionsReplaced() string {
	content := m.Content
	for _, user := range m.Mentions {
		content = strings.Replace(content, fmt.Sprintf("<@%s>", user.ID),
			fmt.Sprintf("@%s", user.Username), -1)
	}
	return content
}
<commit_msg>Embeds.<commit_after>// Discordgo - Discord bindings for Go
// Available at https://github.com/bwmarrin/discordgo

// Copyright 2015-2016 Bruce Marriner <bruce@sqls.net>.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// This file contains code related to the Message struct

package discordgo

import (
	"fmt"
	"strings"
)

// A Message stores all data related to a specific Discord message.
type Message struct {
	ID              string        `json:"id"`
	Author          *User         `json:"author"`
	Content         string        `json:"content"`
	Attachments     []*Attachment `json:"attachments"`
	Tts             bool          `json:"tts"`
	Embeds          []*Embed      `json:"embeds"`
	Timestamp       string        `json:"timestamp"`
	MentionEveryone bool          `json:"mention_everyone"`
	EditedTimestamp string        `json:"edited_timestamp"`
	Mentions        []*User       `json:"mentions"`
	ChannelID       string        `json:"channel_id"`
}

// An Attachment stores data for message attachments.
type Attachment struct {
	ID       string `json:"id"`
	URL      string `json:"url"`
	ProxyURL string `json:"proxy_url"`
	Width    int    `json:"width"`
	Height   int    `json:"height"`
	Filename string `json:"filename"`
	Size     int    `json:"size"`
}

// An Embed stores data for message embeds.
type Embed struct {
	URL         string `json:"url"`
	Type        string `json:"type"`
	Title       string `json:"title"`
	Description string `json:"description"`
	Thumbnail   *struct {
		URL      string `json:"url"`
		ProxyURL string `json:"proxy_url"`
		Width    int    `json:"width"`
		Height   int    `json:"height"`
	} `json:"thumbnail"`
	Provider *struct {
		URL  string `json:"url"`
		Name string `json:"name"`
	} `json:"provider"`
	Author *struct {
		URL  string `json:"url"`
		Name string `json:"name"`
	} `json:"author"`
	Video *struct {
		URL    string `json:"url"`
		Width  int    `json:"width"`
		Height int    `json:"height"`
	} `json:"video"`
}

// ContentWithMentionsReplaced will replace all @<id> mentions with the
// username of the mention.
func (m *Message) ContentWithMentionsReplaced() string {
	content := m.Content
	for _, user := range m.Mentions {
		content = strings.Replace(content, fmt.Sprintf("<@%s>", user.ID),
			fmt.Sprintf("@%s", user.Username), -1)
	}
	return content
}
<|endoftext|>


<commit_before>package go_mailchimp

import(
	"github.com/jordan-wright/email"
//	"net/smtp"
	"encoding/json"
	"strings"
	"time"
	"strconv"
)

type Flag string
const(
	Autotext Flag      = "Autotext"
	AutoHtml           = "AutoHtml"
	URLStripQS         = "URLStripQS"
	PreserveRecipients = "PreserveRecipients"
	InlineCSS          = "InlineCSS"
	ViewContentLink    = "ViewContentLink"
	Important          = "Important"
)

const(
	Host string = "smtp.mandrillapp.com"
	Port        = "587"
)

type MergeLang string
const(
	Mailchimp MergeLang    = "mailchimp"
	Handlebars             = "handlebars"
)

type Google struct {
	Domains  []string
	Campaign string
}

type Template struct {
	Name               string
	MergeLanguage      MergeLang
	Tracks             string
	TrackingDomain     string
	GoogleAnalytics    *Google
	SigningDomain      string
	ReturnPathDomain   string
	Subaccount         string
	BccAddress         string
	IpPool             string
	Flags              map[Flag]bool
	//	MergeVars          interface{}
	//	Metadata           *map[string]string
	//	Tags               *[]string
	//	SendAt             *time.Time
}

func NewTemplate(name string, lang MergeLang) *Template {
	return &Template{
		Name: name,
		MergeLanguage: lang,
		Flags: make(map[Flag]bool),
	}
}

func (p *Template) AddGoogleAnalytics(campaign string, domains []string) *Template {
	p.GoogleAnalytics = &Google{
		Campaign: campaign,
		Domains: domains,
	}
	return p
}

func (p *Template) Track(opens, htmlClicks, textClicks bool) *Template {
	tracks := make([]string, 0, 0)
	if opens {
		tracks = append(tracks, "opens")
	}
	if htmlClicks && textClicks {
		tracks = append(tracks, "clicks_all")
	} else if htmlClicks {
		tracks = append(tracks, "clicks_htmlonly")
	} else if textClicks {
		tracks = append(tracks, "clicks_textonly")
	}
	p.Tracks = strings.Join(tracks, ",")
	return p
}

func (p *Template) Render(data interface{}, tags []string, meta map[string]string, at *time.Time) (*email.Email, error) {
	out := email.NewEmail()
	out.Headers.Set("X-MC-Template", p.Name)

	j, err := json.Marshal(data)
	if err != nil {
		return out, err
	}
	out.Headers.Set("X-MC-MergeVars", string(j))

	if tags != nil && len(tags) > 0 {
		out.Headers.Set("X-MC-Tags", strings.Join(tags, ","))
	}

	if meta != nil {
		j, err := json.Marshal(meta)
		if err == nil {
			out.Headers.Set("X-MC-Meta", string(j))
		}
	}

	if at != nil {
		// handle time
	}

	// common

	if p.Tracks != "" {
		out.Headers.Set("X-MC-Tracks", p.Tracks)
	}

	if p.TrackingDomain != "" {
		out.Headers.Set("X-MC-TrackingDomain", p.TrackingDomain)
	}

	if p.GoogleAnalytics != nil {
		if p.GoogleAnalytics.Campaign != "" {
			out.Headers.Set("X-MC-.GoogleAnalyticsCampaign", p.GoogleAnalytics.Campaign)
		}
		if len(p.GoogleAnalytics.Domains) > 0 {
			out.Headers.Set("X-MC-GoogleAnalytics", strings.Join(p.GoogleAnalytics.Domains, ","))
		}
	}

	if p.SigningDomain != "" {
		out.Headers.Set("X-MC-SigningDomain", p.SigningDomain)
	}

	if p.ReturnPathDomain != "" {
		out.Headers.Set("X-MC-ReturnPathDomain", p.ReturnPathDomain)
	}

	if p.Subaccount != "" {
		out.Headers.Set("X-MC-Subaccount", p.Subaccount)
	}

	if p.BccAddress != "" {
		out.Headers.Set("X-MC-BccAddress", p.BccAddress)
	}

	if p.IpPool != "" {
		out.Headers.Set("X-MC-IpPool", p.IpPool)
	}

	for flag, val := range p.Flags {
		out.Headers.Set("X-MC-" + string(flag), strconv.FormatBool(val))
	}

	return out, nil
}
<commit_msg>Fixed Google Analytics typo.<commit_after>package go_mailchimp

import(
	"github.com/jordan-wright/email"
//	"net/smtp"
	"encoding/json"
	"strings"
	"time"
	"strconv"
)

type Flag string
const(
	Autotext Flag      = "Autotext"
	AutoHtml           = "AutoHtml"
	URLStripQS         = "URLStripQS"
	PreserveRecipients = "PreserveRecipients"
	InlineCSS          = "InlineCSS"
	ViewContentLink    = "ViewContentLink"
	Important          = "Important"
)

const(
	Host string = "smtp.mandrillapp.com"
	Port        = "587"
)

type MergeLang string
const(
	Mailchimp MergeLang    = "mailchimp"
	Handlebars             = "handlebars"
)

type Google struct {
	Domains  []string
	Campaign string
}

type Template struct {
	Name               string
	MergeLanguage      MergeLang
	Tracks             string
	TrackingDomain     string
	GoogleAnalytics    *Google
	SigningDomain      string
	ReturnPathDomain   string
	Subaccount         string
	BccAddress         string
	IpPool             string
	Flags              map[Flag]bool
	//	MergeVars          interface{}
	//	Metadata           *map[string]string
	//	Tags               *[]string
	//	SendAt             *time.Time
}

func NewTemplate(name string, lang MergeLang) *Template {
	return &Template{
		Name: name,
		MergeLanguage: lang,
		Flags: make(map[Flag]bool),
	}
}

func (p *Template) AddGoogleAnalytics(campaign string, domains []string) *Template {
	p.GoogleAnalytics = &Google{
		Campaign: campaign,
		Domains: domains,
	}
	return p
}

func (p *Template) Track(opens, htmlClicks, textClicks bool) *Template {
	tracks := make([]string, 0, 0)
	if opens {
		tracks = append(tracks, "opens")
	}
	if htmlClicks && textClicks {
		tracks = append(tracks, "clicks_all")
	} else if htmlClicks {
		tracks = append(tracks, "clicks_htmlonly")
	} else if textClicks {
		tracks = append(tracks, "clicks_textonly")
	}
	p.Tracks = strings.Join(tracks, ",")
	return p
}

func (p *Template) Render(data interface{}, tags []string, meta map[string]string, at *time.Time) (*email.Email, error) {
	out := email.NewEmail()
	out.Headers.Set("X-MC-Template", p.Name)

	j, err := json.Marshal(data)
	if err != nil {
		return out, err
	}
	out.Headers.Set("X-MC-MergeVars", string(j))

	if tags != nil && len(tags) > 0 {
		out.Headers.Set("X-MC-Tags", strings.Join(tags, ","))
	}

	if meta != nil {
		j, err := json.Marshal(meta)
		if err == nil {
			out.Headers.Set("X-MC-Meta", string(j))
		}
	}

	if at != nil {
		// handle time
	}

	// common

	if p.Tracks != "" {
		out.Headers.Set("X-MC-Tracks", p.Tracks)
	}

	if p.TrackingDomain != "" {
		out.Headers.Set("X-MC-TrackingDomain", p.TrackingDomain)
	}

	if p.GoogleAnalytics != nil {
		if p.GoogleAnalytics.Campaign != "" {
			out.Headers.Set("X-MC-GoogleAnalyticsCampaign", p.GoogleAnalytics.Campaign)
		}
		if len(p.GoogleAnalytics.Domains) > 0 {
			out.Headers.Set("X-MC-GoogleAnalytics", strings.Join(p.GoogleAnalytics.Domains, ","))
		}
	}

	if p.SigningDomain != "" {
		out.Headers.Set("X-MC-SigningDomain", p.SigningDomain)
	}

	if p.ReturnPathDomain != "" {
		out.Headers.Set("X-MC-ReturnPathDomain", p.ReturnPathDomain)
	}

	if p.Subaccount != "" {
		out.Headers.Set("X-MC-Subaccount", p.Subaccount)
	}

	if p.BccAddress != "" {
		out.Headers.Set("X-MC-BccAddress", p.BccAddress)
	}

	if p.IpPool != "" {
		out.Headers.Set("X-MC-IpPool", p.IpPool)
	}

	for flag, val := range p.Flags {
		out.Headers.Set("X-MC-" + string(flag), strconv.FormatBool(val))
	}

	return out, nil
}
<|endoftext|>


<commit_before>// Discordgo - Discord bindings for Go
// Available at https://github.com/bwmarrin/discordgo

// Copyright 2015-2016 Bruce Marriner <bruce@sqls.net>.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// This file contains code related to the Message struct

package discordgo

import (
	"encoding/json"
	"io"
	"regexp"
	"strconv"
	"strings"
)

// MessageType is the type of Message
type MessageType int

// Block contains the valid known MessageType values
const (
	MessageTypeDefault MessageType = iota
	MessageTypeRecipientAdd
	MessageTypeRecipientRemove
	MessageTypeCall
	MessageTypeChannelNameChange
	MessageTypeChannelIconChange
	MessageTypeChannelPinnedMessage
	MessageTypeGuildMemberJoin
)

// A Message stores all data related to a specific Discord message.
type Message struct {
	// The ID of the message.
	ID int64 `json:"id,string"`

	// The ID of the channel in which the message was sent.
	ChannelID int64 `json:"channel_id,string"`

	// The ID of the guild in which the message was sent.
	GuildID int64 `json:"guild_id,string,omitempty"`

	// The content of the message.
	Content string `json:"content"`

	// The time at which the messsage was sent.
	// CAUTION: this field may be removed in a
	// future API version; it is safer to calculate
	// the creation time via the ID.
	Timestamp Timestamp `json:"timestamp"`

	// The time at which the last edit of the message
	// occurred, if it has been edited.
	EditedTimestamp Timestamp `json:"edited_timestamp"`

	// The roles mentioned in the message.
	MentionRoles IDSlice `json:"mention_roles,string"`

	// Whether the message is text-to-speech.
	Tts bool `json:"tts"`

	// Whether the message mentions everyone.
	MentionEveryone bool `json:"mention_everyone"`

	// The author of the message. This is not guaranteed to be a
	// valid user (webhook-sent messages do not possess a full author).
	Author *User `json:"author"`

	// A list of attachments present in the message.
	Attachments []*MessageAttachment `json:"attachments"`

	// A list of embeds present in the message. Multiple
	// embeds can currently only be sent by webhooks.
	Embeds []*MessageEmbed `json:"embeds"`

	// A list of users mentioned in the message.
	Mentions []*User `json:"mentions"`

	// Whether the message is pinned or not.
	Pinned bool `json:"pinned"`

	// A list of reactions to the message.
	Reactions []*MessageReactions `json:"reactions"`

	// The type of the message.
	Type MessageType `json:"type"`

	WebhookID int64 `json:"webhook_id,string"`

	Member *Member `json:"member"`
}

func (m *Message) GetGuildID() int64 {
	return m.GuildID
}

func (m *Message) GetChannelID() int64 {
	return m.ChannelID
}

// File stores info about files you e.g. send in messages.
type File struct {
	Name        string
	ContentType string
	Reader      io.Reader
}

// MessageSend stores all parameters you can send with ChannelMessageSendComplex.
type MessageSend struct {
	Content string        `json:"content,omitempty"`
	Embed   *MessageEmbed `json:"embed,omitempty"`
	Tts     bool          `json:"tts"`
	Files   []*File       `json:"-"`

	// TODO: Remove this when compatibility is not required.
	File *File `json:"-"`
}

// MessageEdit is used to chain parameters via ChannelMessageEditComplex, which
// is also where you should get the instance from.
type MessageEdit struct {
	Content *string       `json:"content,omitempty"`
	Embed   *MessageEmbed `json:"embed,omitempty"`

	ID      int64
	Channel int64
}

// NewMessageEdit returns a MessageEdit struct, initialized
// with the Channel and ID.
func NewMessageEdit(channelID int64, messageID int64) *MessageEdit {
	return &MessageEdit{
		Channel: channelID,
		ID:      messageID,
	}
}

// SetContent is the same as setting the variable Content,
// except it doesn't take a pointer.
func (m *MessageEdit) SetContent(str string) *MessageEdit {
	m.Content = &str
	return m
}

// SetEmbed is a convenience function for setting the embed,
// so you can chain commands.
func (m *MessageEdit) SetEmbed(embed *MessageEmbed) *MessageEdit {
	m.Embed = embed
	return m
}

// A MessageAttachment stores data for message attachments.
type MessageAttachment struct {
	ID       string `json:"id"`
	URL      string `json:"url"`
	ProxyURL string `json:"proxy_url"`
	Filename string `json:"filename"`
	Width    int    `json:"width"`
	Height   int    `json:"height"`
	Size     int    `json:"size"`
}

// MessageEmbedFooter is a part of a MessageEmbed struct.
type MessageEmbedFooter struct {
	Text         string `json:"text,omitempty"`
	IconURL      string `json:"icon_url,omitempty"`
	ProxyIconURL string `json:"proxy_icon_url,omitempty"`
}

// MessageEmbedImage is a part of a MessageEmbed struct.
type MessageEmbedImage struct {
	URL      string `json:"url,omitempty"`
	ProxyURL string `json:"proxy_url,omitempty"`
	Width    int    `json:"width,omitempty"`
	Height   int    `json:"height,omitempty"`
}

// MessageEmbedThumbnail is a part of a MessageEmbed struct.
type MessageEmbedThumbnail struct {
	URL      string `json:"url,omitempty"`
	ProxyURL string `json:"proxy_url,omitempty"`
	Width    int    `json:"width,omitempty"`
	Height   int    `json:"height,omitempty"`
}

// MessageEmbedVideo is a part of a MessageEmbed struct.
type MessageEmbedVideo struct {
	URL      string `json:"url,omitempty"`
	ProxyURL string `json:"proxy_url,omitempty"`
	Width    int    `json:"width,omitempty"`
	Height   int    `json:"height,omitempty"`
}

// MessageEmbedProvider is a part of a MessageEmbed struct.
type MessageEmbedProvider struct {
	URL  string `json:"url,omitempty"`
	Name string `json:"name,omitempty"`
}

// MessageEmbedAuthor is a part of a MessageEmbed struct.
type MessageEmbedAuthor struct {
	URL          string `json:"url,omitempty"`
	Name         string `json:"name,omitempty"`
	IconURL      string `json:"icon_url,omitempty"`
	ProxyIconURL string `json:"proxy_icon_url,omitempty"`
}

// MessageEmbedField is a part of a MessageEmbed struct.
type MessageEmbedField struct {
	Name   string `json:"name,omitempty"`
	Value  string `json:"value,omitempty"`
	Inline bool   `json:"inline,omitempty"`
}

// An MessageEmbed stores data for message embeds.
type MessageEmbed struct {
	URL         string                 `json:"url,omitempty"`
	Type        string                 `json:"type,omitempty"`
	Title       string                 `json:"title,omitempty"`
	Description string                 `json:"description,omitempty"`
	Timestamp   string                 `json:"timestamp,omitempty"`
	Color       int                    `json:"color,omitempty"`
	Footer      *MessageEmbedFooter    `json:"footer,omitempty"`
	Image       *MessageEmbedImage     `json:"image,omitempty"`
	Thumbnail   *MessageEmbedThumbnail `json:"thumbnail,omitempty"`
	Video       *MessageEmbedVideo     `json:"video,omitempty"`
	Provider    *MessageEmbedProvider  `json:"provider,omitempty"`
	Author      *MessageEmbedAuthor    `json:"author,omitempty"`
	Fields      []*MessageEmbedField   `json:"fields,omitempty"`

	//flag that tells the marshaller to marshal struct as nil
	marshalnil  bool		   `json:"-"`
}

func (e *MessageEmbed) MarshalNil(flag bool) *MessageEmbed {
	e.marshalnil = flag
	return e

}

func (e *MessageEmbed) GetMarshalNil() bool {
	return e.marshalnil
}

func (e *MessageEmbed) MarshalJSON() ([]byte, error) {
	if e.marshalnil == true {
		return json.Marshal(nil)
	}
	type EmbedAlias MessageEmbed
	return json.Marshal(&struct{*EmbedAlias}{EmbedAlias: (*EmbedAlias)(e),})
}
// MessageReactions holds a reactions object for a message.
type MessageReactions struct {
	Count int    `json:"count"`
	Me    bool   `json:"me"`
	Emoji *Emoji `json:"emoji"`
}

// ContentWithMentionsReplaced will replace all @<id> mentions with the
// username of the mention.
func (m *Message) ContentWithMentionsReplaced() (content string) {
	content = m.Content

	for _, user := range m.Mentions {
		content = strings.NewReplacer(
			"<@"+StrID(user.ID)+">", "@"+user.Username,
			"<@!"+StrID(user.ID)+">", "@"+user.Username,
		).Replace(content)
	}
	return
}

var patternChannels = regexp.MustCompile("<#[^>]*>")

// ContentWithMoreMentionsReplaced will replace all @<id> mentions with the
// username of the mention, but also role IDs and more.
func (m *Message) ContentWithMoreMentionsReplaced(s *Session) (content string, err error) {
	content = m.Content

	if !s.StateEnabled {
		content = m.ContentWithMentionsReplaced()
		return
	}

	channel, err := s.State.Channel(m.ChannelID)
	if err != nil {
		content = m.ContentWithMentionsReplaced()
		return
	}

	for _, user := range m.Mentions {
		nick := user.Username

		member, err := s.State.Member(channel.GuildID, user.ID)
		if err == nil && member.Nick != "" {
			nick = member.Nick
		}

		content = strings.NewReplacer(
			"<@"+StrID(user.ID)+">", "@"+user.Username,
			"<@!"+StrID(user.ID)+">", "@"+nick,
		).Replace(content)
	}
	for _, roleID := range m.MentionRoles {
		role, err := s.State.Role(channel.GuildID, roleID)
		if err != nil || !role.Mentionable {
			continue
		}

		content = strings.Replace(content, "<@&"+StrID(role.ID)+">", "@"+role.Name, -1)
	}

	content = patternChannels.ReplaceAllStringFunc(content, func(mention string) string {
		id, err := strconv.ParseInt(mention[2:len(mention)-1], 10, 64)
		if err != nil {
			return mention
		}

		channel, err := s.State.Channel(id)
		if err != nil || channel.Type == ChannelTypeGuildVoice {
			return mention
		}

		return "#" + channel.Name
	})
	return
}
<commit_msg>added allowed_mentions<commit_after>// Discordgo - Discord bindings for Go
// Available at https://github.com/bwmarrin/discordgo

// Copyright 2015-2016 Bruce Marriner <bruce@sqls.net>.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// This file contains code related to the Message struct

package discordgo

import (
	"encoding/json"
	"io"
	"regexp"
	"strconv"
	"strings"
)

// MessageType is the type of Message
type MessageType int

// Block contains the valid known MessageType values
const (
	MessageTypeDefault MessageType = iota
	MessageTypeRecipientAdd
	MessageTypeRecipientRemove
	MessageTypeCall
	MessageTypeChannelNameChange
	MessageTypeChannelIconChange
	MessageTypeChannelPinnedMessage
	MessageTypeGuildMemberJoin
)

// A Message stores all data related to a specific Discord message.
type Message struct {
	// The ID of the message.
	ID int64 `json:"id,string"`

	// The ID of the channel in which the message was sent.
	ChannelID int64 `json:"channel_id,string"`

	// The ID of the guild in which the message was sent.
	GuildID int64 `json:"guild_id,string,omitempty"`

	// The content of the message.
	Content string `json:"content"`

	// The time at which the messsage was sent.
	// CAUTION: this field may be removed in a
	// future API version; it is safer to calculate
	// the creation time via the ID.
	Timestamp Timestamp `json:"timestamp"`

	// The time at which the last edit of the message
	// occurred, if it has been edited.
	EditedTimestamp Timestamp `json:"edited_timestamp"`

	// The roles mentioned in the message.
	MentionRoles IDSlice `json:"mention_roles,string"`

	// Whether the message is text-to-speech.
	Tts bool `json:"tts"`

	// Whether the message mentions everyone.
	MentionEveryone bool `json:"mention_everyone"`

	// The author of the message. This is not guaranteed to be a
	// valid user (webhook-sent messages do not possess a full author).
	Author *User `json:"author"`

	// A list of attachments present in the message.
	Attachments []*MessageAttachment `json:"attachments"`

	// A list of embeds present in the message. Multiple
	// embeds can currently only be sent by webhooks.
	Embeds []*MessageEmbed `json:"embeds"`

	// A list of users mentioned in the message.
	Mentions []*User `json:"mentions"`

	// Whether the message is pinned or not.
	Pinned bool `json:"pinned"`

	// A list of reactions to the message.
	Reactions []*MessageReactions `json:"reactions"`

	// The type of the message.
	Type MessageType `json:"type"`

	WebhookID int64 `json:"webhook_id,string"`

	Member *Member `json:"member"`

	AllowedMentions AllowedMentionType `json:"allowed_mentions"`
}

func (m *Message) GetGuildID() int64 {
	return m.GuildID
}

func (m *Message) GetChannelID() int64 {
	return m.ChannelID
}

// File stores info about files you e.g. send in messages.
type File struct {
	Name        string
	ContentType string
	Reader      io.Reader
}

// MessageSend stores all parameters you can send with ChannelMessageSendComplex.
type MessageSend struct {
	Content         string          `json:"content,omitempty"`
	Embed           *MessageEmbed   `json:"embed,omitempty"`
	Tts             bool            `json:"tts"`
	Files           []*File         `json:"-"`
	AllowedMentions AllowedMentions `json:"allowed_mentions"`

	// TODO: Remove this when compatibility is not required.
	File *File `json:"-"`
}

// MessageEdit is used to chain parameters via ChannelMessageEditComplex, which
// is also where you should get the instance from.
type MessageEdit struct {
	Content         *string          `json:"content,omitempty"`
	Embed           *MessageEmbed    `json:"embed,omitempty"`
	AllowedMentions *AllowedMentions `json:"allowed_mentions,omitempty"`

	ID      int64
	Channel int64
}

// NewMessageEdit returns a MessageEdit struct, initialized
// with the Channel and ID.
func NewMessageEdit(channelID int64, messageID int64) *MessageEdit {
	return &MessageEdit{
		Channel: channelID,
		ID:      messageID,
	}
}

// SetContent is the same as setting the variable Content,
// except it doesn't take a pointer.
func (m *MessageEdit) SetContent(str string) *MessageEdit {
	m.Content = &str
	return m
}

// SetEmbed is a convenience function for setting the embed,
// so you can chain commands.
func (m *MessageEdit) SetEmbed(embed *MessageEmbed) *MessageEdit {
	m.Embed = embed
	return m
}

// A MessageAttachment stores data for message attachments.
type MessageAttachment struct {
	ID       string `json:"id"`
	URL      string `json:"url"`
	ProxyURL string `json:"proxy_url"`
	Filename string `json:"filename"`
	Width    int    `json:"width"`
	Height   int    `json:"height"`
	Size     int    `json:"size"`
}

// MessageEmbedFooter is a part of a MessageEmbed struct.
type MessageEmbedFooter struct {
	Text         string `json:"text,omitempty"`
	IconURL      string `json:"icon_url,omitempty"`
	ProxyIconURL string `json:"proxy_icon_url,omitempty"`
}

// MessageEmbedImage is a part of a MessageEmbed struct.
type MessageEmbedImage struct {
	URL      string `json:"url,omitempty"`
	ProxyURL string `json:"proxy_url,omitempty"`
	Width    int    `json:"width,omitempty"`
	Height   int    `json:"height,omitempty"`
}

// MessageEmbedThumbnail is a part of a MessageEmbed struct.
type MessageEmbedThumbnail struct {
	URL      string `json:"url,omitempty"`
	ProxyURL string `json:"proxy_url,omitempty"`
	Width    int    `json:"width,omitempty"`
	Height   int    `json:"height,omitempty"`
}

// MessageEmbedVideo is a part of a MessageEmbed struct.
type MessageEmbedVideo struct {
	URL      string `json:"url,omitempty"`
	ProxyURL string `json:"proxy_url,omitempty"`
	Width    int    `json:"width,omitempty"`
	Height   int    `json:"height,omitempty"`
}

// MessageEmbedProvider is a part of a MessageEmbed struct.
type MessageEmbedProvider struct {
	URL  string `json:"url,omitempty"`
	Name string `json:"name,omitempty"`
}

// MessageEmbedAuthor is a part of a MessageEmbed struct.
type MessageEmbedAuthor struct {
	URL          string `json:"url,omitempty"`
	Name         string `json:"name,omitempty"`
	IconURL      string `json:"icon_url,omitempty"`
	ProxyIconURL string `json:"proxy_icon_url,omitempty"`
}

// MessageEmbedField is a part of a MessageEmbed struct.
type MessageEmbedField struct {
	Name   string `json:"name,omitempty"`
	Value  string `json:"value,omitempty"`
	Inline bool   `json:"inline,omitempty"`
}

// An MessageEmbed stores data for message embeds.
type MessageEmbed struct {
	URL         string                 `json:"url,omitempty"`
	Type        string                 `json:"type,omitempty"`
	Title       string                 `json:"title,omitempty"`
	Description string                 `json:"description,omitempty"`
	Timestamp   string                 `json:"timestamp,omitempty"`
	Color       int                    `json:"color,omitempty"`
	Footer      *MessageEmbedFooter    `json:"footer,omitempty"`
	Image       *MessageEmbedImage     `json:"image,omitempty"`
	Thumbnail   *MessageEmbedThumbnail `json:"thumbnail,omitempty"`
	Video       *MessageEmbedVideo     `json:"video,omitempty"`
	Provider    *MessageEmbedProvider  `json:"provider,omitempty"`
	Author      *MessageEmbedAuthor    `json:"author,omitempty"`
	Fields      []*MessageEmbedField   `json:"fields,omitempty"`

	//flag that tells the marshaller to marshal struct as nil
	marshalnil bool `json:"-"`
}

func (e *MessageEmbed) MarshalNil(flag bool) *MessageEmbed {
	e.marshalnil = flag
	return e

}

func (e *MessageEmbed) GetMarshalNil() bool {
	return e.marshalnil
}

func (e *MessageEmbed) MarshalJSON() ([]byte, error) {
	if e.marshalnil == true {
		return json.Marshal(nil)
	}
	type EmbedAlias MessageEmbed
	return json.Marshal(&struct{ *EmbedAlias }{EmbedAlias: (*EmbedAlias)(e)})
}

// MessageReactions holds a reactions object for a message.
type MessageReactions struct {
	Count int    `json:"count"`
	Me    bool   `json:"me"`
	Emoji *Emoji `json:"emoji"`
}

// ContentWithMentionsReplaced will replace all @<id> mentions with the
// username of the mention.
func (m *Message) ContentWithMentionsReplaced() (content string) {
	content = m.Content

	for _, user := range m.Mentions {
		content = strings.NewReplacer(
			"<@"+StrID(user.ID)+">", "@"+user.Username,
			"<@!"+StrID(user.ID)+">", "@"+user.Username,
		).Replace(content)
	}
	return
}

var patternChannels = regexp.MustCompile("<#[^>]*>")

// ContentWithMoreMentionsReplaced will replace all @<id> mentions with the
// username of the mention, but also role IDs and more.
func (m *Message) ContentWithMoreMentionsReplaced(s *Session) (content string, err error) {
	content = m.Content

	if !s.StateEnabled {
		content = m.ContentWithMentionsReplaced()
		return
	}

	channel, err := s.State.Channel(m.ChannelID)
	if err != nil {
		content = m.ContentWithMentionsReplaced()
		return
	}

	for _, user := range m.Mentions {
		nick := user.Username

		member, err := s.State.Member(channel.GuildID, user.ID)
		if err == nil && member.Nick != "" {
			nick = member.Nick
		}

		content = strings.NewReplacer(
			"<@"+StrID(user.ID)+">", "@"+user.Username,
			"<@!"+StrID(user.ID)+">", "@"+nick,
		).Replace(content)
	}
	for _, roleID := range m.MentionRoles {
		role, err := s.State.Role(channel.GuildID, roleID)
		if err != nil || !role.Mentionable {
			continue
		}

		content = strings.Replace(content, "<@&"+StrID(role.ID)+">", "@"+role.Name, -1)
	}

	content = patternChannels.ReplaceAllStringFunc(content, func(mention string) string {
		id, err := strconv.ParseInt(mention[2:len(mention)-1], 10, 64)
		if err != nil {
			return mention
		}

		channel, err := s.State.Channel(id)
		if err != nil || channel.Type == ChannelTypeGuildVoice {
			return mention
		}

		return "#" + channel.Name
	})
	return
}

type AllowedMentionType string

const (
	AllowedMentionTypeRoles   AllowedMentionType = "roles"
	AllowedMentionTypeUsers   AllowedMentionType = "users"
	AllowedMentionTyeEveryone AllowedMentionType = "everyone"
)

type AllowedMentions struct {
	// Allowed mention types to parse from message content
	Parse []AllowedMentionType `json:"parse"`

	// Slice of role ids to mention
	Roles IDSlice `json:"roles,string"`

	// Slice of users to mention
	Users IDSlice `json:"users,string"`
}
<|endoftext|>


<commit_before>// Copyright 2014 Vic Demuzere
//
// Use of this source code is governed by the MIT license.

package irc

import (
	"bytes"
	"strings"
)

// Various constants used for formatting IRC messages.
const (
	tags          byte = 0x40 // Tag start indicator
	tagsEquals    byte = 0x3D
	tagsSeparator byte = 0x3B // Separator between multiple tags
	prefix        byte = 0x3A // Prefix or last argument
	prefixUser    byte = 0x21 // Username
	prefixHost    byte = 0x40 // Hostname
	space         byte = 0x20 // Separator

	maxLength = 510 // Maximum length is 512 - 2 for the line endings.
)

func cutsetFunc(r rune) bool {
	// Characters to trim from prefixes/messages.
	return r == '\r' || r == '\n'
}

// Objects implementing the Sender interface are able to send messages to an IRC server.
//
// As there might be a message queue, it is possible that Send returns a nil
// error, but the message is not sent (yet). The error value is only used when
// it is certain that sending the message is impossible.
//
// This interface is not used inside this package, and shouldn't have been
// defined here in the first place. For backwards compatibility only.
type Sender interface {
	Send(*Message) error
}

// Tags represents (optional) tags added to the start of each message
// See IRCv3.2 Message Tags (http://ircv3.net/specs/core/message-tags-3.2.html)
//
// <message>       ::= ['@' <tags> <SPACE>] [':' <prefix> <SPACE> ] <command> <params> <crlf>
// <tags>          ::= <tag> [';' <tag>]*
// <tag>           ::= <key> ['=' <escaped value>]
// <key>           ::= [ <vendor> '/' ] <sequence of letters, digits, hyphens (`-`)>
// <escaped value> ::= <sequence of any characters except NUL, CR, LF, semicolon (`;`) and SPACE>
// <vendor>        ::= <host>
type Tags struct {
	values map[string]string
}

// ParseTags takes a string and attempts to create a Tags struct
func ParseTags(raw string) (t *Tags) {
	t = &Tags{
		values: make(map[string]string),
	}

	tags := strings.Split(raw, string(tagsSeparator))

	for _, val := range tags {
		tagParts := strings.Split(val, string(tagsEquals))
		// Tag must at least contain a key
		if len(tagParts) < 1 {
			continue
		}

		// Tag only contains key, set empty value
		if len(tagParts) == 1 {
			t.values[tagParts[0]] = ""
			continue
		}

		unescaped := strings.Replace(tagParts[1], "\\:", ";", -1)
		unescaped = strings.Replace(unescaped, "\\s", " ", -1)
		unescaped = strings.Replace(unescaped, "\\s", "\\", -1)
		unescaped = strings.Replace(unescaped, "CR", "\r", -1)
		unescaped = strings.Replace(unescaped, "LF", "\n", -1)

		t.values[tagParts[0]] = unescaped
	}

	return t
}

// GetTag checks whether a tag with the given key exists. The boolean return value indicates whether a value was found
func (t *Tags) GetTag(key string) (string, bool) {
	if val, ok := t.values[key]; ok {
		return val, true
	}

	return "", false
}

// Prefix represents the prefix (sender) of an IRC message.
// See RFC1459 section 2.3.1.
//
//    <servername> | <nick> [ '!' <user> ] [ '@' <host> ]
//
type Prefix struct {
	Name string // Nick- or servername
	User string // Username
	Host string // Hostname
}

// ParsePrefix takes a string and attempts to create a Prefix struct.
func ParsePrefix(raw string) (p *Prefix) {

	p = new(Prefix)

	user := indexByte(raw, prefixUser)
	host := indexByte(raw, prefixHost)

	switch {

	case user > 0 && host > user:
		p.Name = raw[:user]
		p.User = raw[user+1 : host]
		p.Host = raw[host+1:]

	case user > 0:
		p.Name = raw[:user]
		p.User = raw[user+1:]

	case host > 0:
		p.Name = raw[:host]
		p.Host = raw[host+1:]

	default:
		p.Name = raw

	}

	return p
}

// Len calculates the length of the string representation of this prefix.
func (p *Prefix) Len() (length int) {
	length = len(p.Name)
	if len(p.User) > 0 {
		length = length + len(p.User) + 1
	}
	if len(p.Host) > 0 {
		length = length + len(p.Host) + 1
	}
	return
}

// Bytes returns a []byte representation of this prefix.
func (p *Prefix) Bytes() []byte {
	buffer := new(bytes.Buffer)
	p.writeTo(buffer)
	return buffer.Bytes()
}

// String returns a string representation of this prefix.
func (p *Prefix) String() (s string) {
	// Benchmarks revealed that in this case simple string concatenation
	// is actually faster than using a ByteBuffer as in (*Message).String()
	s = p.Name
	if len(p.User) > 0 {
		s = s + string(prefixUser) + p.User
	}
	if len(p.Host) > 0 {
		s = s + string(prefixHost) + p.Host
	}
	return
}

// IsHostmask returns true if this prefix looks like a user hostmask.
func (p *Prefix) IsHostmask() bool {
	return len(p.User) > 0 && len(p.Host) > 0
}

// IsServer returns true if this prefix looks like a server name.
func (p *Prefix) IsServer() bool {
	return len(p.User) <= 0 && len(p.Host) <= 0 // && indexByte(p.Name, '.') > 0
}

// writeTo is an utility function to write the prefix to the bytes.Buffer in Message.String().
func (p *Prefix) writeTo(buffer *bytes.Buffer) {
	buffer.WriteString(p.Name)
	if len(p.User) > 0 {
		buffer.WriteByte(prefixUser)
		buffer.WriteString(p.User)
	}
	if len(p.Host) > 0 {
		buffer.WriteByte(prefixHost)
		buffer.WriteString(p.Host)
	}
	return
}

// Message represents an IRC protocol message.
// See RFC1459 section 2.3.1.
//
//    <message>  ::= [':' <prefix> <SPACE> ] <command> <params> <crlf>
//    <prefix>   ::= <servername> | <nick> [ '!' <user> ] [ '@' <host> ]
//    <command>  ::= <letter> { <letter> } | <number> <number> <number>
//    <SPACE>    ::= ' ' { ' ' }
//    <params>   ::= <SPACE> [ ':' <trailing> | <middle> <params> ]
//
//    <middle>   ::= <Any *non-empty* sequence of octets not including SPACE
//                   or NUL or CR or LF, the first of which may not be ':'>
//    <trailing> ::= <Any, possibly *empty*, sequence of octets not including
//                   NUL or CR or LF>
//
//    <crlf>     ::= CR LF
type Message struct {
	*Tags
	*Prefix
	Command  string
	Params   []string
	Trailing string

	// When set to true, the trailing prefix (:) will be added even if the trailing message is empty.
	EmptyTrailing bool
}

// ParseMessage takes a string and attempts to create a Message struct.
// Returns nil if the Message is invalid.
func ParseMessage(raw string) (m *Message) {

	// Ignore empty messages.
	if raw = strings.TrimFunc(raw, cutsetFunc); len(raw) < 2 {
		return nil
	}

	i, j, k := 0, 0, 0

	m = new(Message)

	if raw[k] == tags {
		// Tags end with a space
		k = indexByte(raw, space)

		// Tags must not be empty if the indicator is present
		if k < 2 {
			return nil
		}

		m.Tags = ParseTags(raw[1:k])
		// Skip space at the end of the tags
		k++
	}

	if raw[k] == prefix {
		// Prefix ends with a space.
		i = k + indexByte(raw[k:], space)

		// Prefix string must not be empty if the indicator is present.
		if i < 2 {
			return nil
		}

		m.Prefix = ParsePrefix(raw[k+1 : i])

		// Skip space at the end of the prefix
		i++
	}

	// Find end of command
	j = i + indexByte(raw[i:], space)

	// Extract command
	if j > i {
		m.Command = raw[i:j]
	} else {
		m.Command = raw[i:]

		// We're done here!
		return m
	}

	// Skip space after command
	j++

	// Find prefix for trailer
	i = indexByte(raw[j:], prefix)

	if i < 0 {

		// There is no trailing argument!
		m.Params = strings.Split(raw[j:], string(space))

		// We're done here!
		return m
	}

	// Compensate for index on substring
	i = i + j

	// Check if we need to parse arguments.
	if i > j {
		m.Params = strings.Split(raw[j:i-1], string(space))
	}

	m.Trailing = raw[i+1:]

	// We need to re-encode the trailing argument even if it was empty.
	if len(m.Trailing) <= 0 {
		m.EmptyTrailing = true
	}

	return m

}

// Len calculates the length of the string representation of this message.
func (m *Message) Len() (length int) {

	if m.Prefix != nil {
		length = m.Prefix.Len() + 2 // Include prefix and trailing space
	}

	length = length + len(m.Command)

	if len(m.Params) > 0 {
		length = length + len(m.Params)
		for _, param := range m.Params {
			length = length + len(param)
		}
	}

	if len(m.Trailing) > 0 || m.EmptyTrailing {
		length = length + len(m.Trailing) + 2 // Include prefix and space
	}

	return
}

// Bytes returns a []byte representation of this message.
//
// As noted in rfc2812 section 2.3, messages should not exceed 512 characters
// in length. This method forces that limit by discarding any characters
// exceeding the length limit.
func (m *Message) Bytes() []byte {

	buffer := new(bytes.Buffer)

	// Message prefix
	if m.Prefix != nil {
		buffer.WriteByte(prefix)
		m.Prefix.writeTo(buffer)
		buffer.WriteByte(space)
	}

	// Command is required
	buffer.WriteString(m.Command)

	// Space separated list of arguments
	if len(m.Params) > 0 {
		buffer.WriteByte(space)
		buffer.WriteString(strings.Join(m.Params, string(space)))
	}

	if len(m.Trailing) > 0 || m.EmptyTrailing {
		buffer.WriteByte(space)
		buffer.WriteByte(prefix)
		buffer.WriteString(m.Trailing)
	}

	// We need the limit the buffer length.
	if buffer.Len() > (maxLength) {
		buffer.Truncate(maxLength)
	}

	return buffer.Bytes()
}

// String returns a string representation of this message.
//
// As noted in rfc2812 section 2.3, messages should not exceed 512 characters
// in length. This method forces that limit by discarding any characters
// exceeding the length limit.
func (m *Message) String() string {
	return string(m.Bytes())
}
<commit_msg>Added String method for Tags struct, concatenating all tags to a single string<commit_after>// Copyright 2014 Vic Demuzere
//
// Use of this source code is governed by the MIT license.

package irc

import (
	"bytes"
	"strings"
)

// Various constants used for formatting IRC messages.
const (
	tags          byte = 0x40 // Tag start indicator
	tagsEquals    byte = 0x3D // Keys and values are separated using equal signs
	tagsSeparator byte = 0x3B // Separator between multiple tags
	prefix        byte = 0x3A // Prefix or last argument
	prefixUser    byte = 0x21 // Username
	prefixHost    byte = 0x40 // Hostname
	space         byte = 0x20 // Separator

	maxLength = 510 // Maximum length is 512 - 2 for the line endings.
)

func cutsetFunc(r rune) bool {
	// Characters to trim from prefixes/messages.
	return r == '\r' || r == '\n'
}

// Objects implementing the Sender interface are able to send messages to an IRC server.
//
// As there might be a message queue, it is possible that Send returns a nil
// error, but the message is not sent (yet). The error value is only used when
// it is certain that sending the message is impossible.
//
// This interface is not used inside this package, and shouldn't have been
// defined here in the first place. For backwards compatibility only.
type Sender interface {
	Send(*Message) error
}

// Tags represents (optional) tags added to the start of each message
// See IRCv3.2 Message Tags (http://ircv3.net/specs/core/message-tags-3.2.html)
//
// <message>       ::= ['@' <tags> <SPACE>] [':' <prefix> <SPACE> ] <command> <params> <crlf>
// <tags>          ::= <tag> [';' <tag>]*
// <tag>           ::= <key> ['=' <escaped value>]
// <key>           ::= [ <vendor> '/' ] <sequence of letters, digits, hyphens (`-`)>
// <escaped value> ::= <sequence of any characters except NUL, CR, LF, semicolon (`;`) and SPACE>
// <vendor>        ::= <host>
type Tags struct {
	values map[string]string
}

// ParseTags takes a string and attempts to create a Tags struct
func ParseTags(raw string) (t *Tags) {
	t = &Tags{
		values: make(map[string]string),
	}

	tags := strings.Split(raw, string(tagsSeparator))

	for _, val := range tags {
		tagParts := strings.Split(val, string(tagsEquals))
		// Tag must at least contain a key
		if len(tagParts) < 1 {
			continue
		}

		// Tag only contains key, set empty value
		if len(tagParts) == 1 {
			t.values[tagParts[0]] = ""
			continue
		}

		unescaped := strings.Replace(tagParts[1], "\\:", ";", -1)
		unescaped = strings.Replace(unescaped, "\\s", " ", -1)
		unescaped = strings.Replace(unescaped, "\\s", "\\", -1)
		unescaped = strings.Replace(unescaped, "CR", "\r", -1)
		unescaped = strings.Replace(unescaped, "LF", "\n", -1)

		t.values[tagParts[0]] = unescaped
	}

	return t
}

// GetTag checks whether a tag with the given key exists. The boolean return value indicates whether a value was found
func (t *Tags) GetTag(key string) (string, bool) {
	if val, ok := t.values[key]; ok {
		return val, true
	}

	return "", false
}

// String returns the string representation of all set message tags
func (t *Tags) String() (s string) {
	var buf bytes.Buffer

	for key, val := range t.values {
		buf.WriteString(key)

		if len(val) > 0 {
			buf.WriteString("=")
			buf.WriteString(val)
		}

		buf.WriteString(";")
	}

	s = strings.TrimRight(buf.String(), ";")

	return s
}

// Prefix represents the prefix (sender) of an IRC message.
// See RFC1459 section 2.3.1.
//
//    <servername> | <nick> [ '!' <user> ] [ '@' <host> ]
//
type Prefix struct {
	Name string // Nick- or servername
	User string // Username
	Host string // Hostname
}

// ParsePrefix takes a string and attempts to create a Prefix struct.
func ParsePrefix(raw string) (p *Prefix) {

	p = new(Prefix)

	user := indexByte(raw, prefixUser)
	host := indexByte(raw, prefixHost)

	switch {

	case user > 0 && host > user:
		p.Name = raw[:user]
		p.User = raw[user+1 : host]
		p.Host = raw[host+1:]

	case user > 0:
		p.Name = raw[:user]
		p.User = raw[user+1:]

	case host > 0:
		p.Name = raw[:host]
		p.Host = raw[host+1:]

	default:
		p.Name = raw

	}

	return p
}

// Len calculates the length of the string representation of this prefix.
func (p *Prefix) Len() (length int) {
	length = len(p.Name)
	if len(p.User) > 0 {
		length = length + len(p.User) + 1
	}
	if len(p.Host) > 0 {
		length = length + len(p.Host) + 1
	}
	return
}

// Bytes returns a []byte representation of this prefix.
func (p *Prefix) Bytes() []byte {
	buffer := new(bytes.Buffer)
	p.writeTo(buffer)
	return buffer.Bytes()
}

// String returns a string representation of this prefix.
func (p *Prefix) String() (s string) {
	// Benchmarks revealed that in this case simple string concatenation
	// is actually faster than using a ByteBuffer as in (*Message).String()
	s = p.Name
	if len(p.User) > 0 {
		s = s + string(prefixUser) + p.User
	}
	if len(p.Host) > 0 {
		s = s + string(prefixHost) + p.Host
	}
	return
}

// IsHostmask returns true if this prefix looks like a user hostmask.
func (p *Prefix) IsHostmask() bool {
	return len(p.User) > 0 && len(p.Host) > 0
}

// IsServer returns true if this prefix looks like a server name.
func (p *Prefix) IsServer() bool {
	return len(p.User) <= 0 && len(p.Host) <= 0 // && indexByte(p.Name, '.') > 0
}

// writeTo is an utility function to write the prefix to the bytes.Buffer in Message.String().
func (p *Prefix) writeTo(buffer *bytes.Buffer) {
	buffer.WriteString(p.Name)
	if len(p.User) > 0 {
		buffer.WriteByte(prefixUser)
		buffer.WriteString(p.User)
	}
	if len(p.Host) > 0 {
		buffer.WriteByte(prefixHost)
		buffer.WriteString(p.Host)
	}
	return
}

// Message represents an IRC protocol message.
// See RFC1459 section 2.3.1.
//
//    <message>  ::= [':' <prefix> <SPACE> ] <command> <params> <crlf>
//    <prefix>   ::= <servername> | <nick> [ '!' <user> ] [ '@' <host> ]
//    <command>  ::= <letter> { <letter> } | <number> <number> <number>
//    <SPACE>    ::= ' ' { ' ' }
//    <params>   ::= <SPACE> [ ':' <trailing> | <middle> <params> ]
//
//    <middle>   ::= <Any *non-empty* sequence of octets not including SPACE
//                   or NUL or CR or LF, the first of which may not be ':'>
//    <trailing> ::= <Any, possibly *empty*, sequence of octets not including
//                   NUL or CR or LF>
//
//    <crlf>     ::= CR LF
type Message struct {
	*Tags
	*Prefix
	Command  string
	Params   []string
	Trailing string

	// When set to true, the trailing prefix (:) will be added even if the trailing message is empty.
	EmptyTrailing bool
}

// ParseMessage takes a string and attempts to create a Message struct.
// Returns nil if the Message is invalid.
func ParseMessage(raw string) (m *Message) {

	// Ignore empty messages.
	if raw = strings.TrimFunc(raw, cutsetFunc); len(raw) < 2 {
		return nil
	}

	i, j, k := 0, 0, 0

	m = new(Message)

	if raw[k] == tags {
		// Tags end with a space
		k = indexByte(raw, space)

		// Tags must not be empty if the indicator is present
		if k < 2 {
			return nil
		}

		m.Tags = ParseTags(raw[1:k])
		// Skip space at the end of the tags
		k++
	}

	if raw[k] == prefix {
		// Prefix ends with a space.
		i = k + indexByte(raw[k:], space)

		// Prefix string must not be empty if the indicator is present.
		if i < 2 {
			return nil
		}

		m.Prefix = ParsePrefix(raw[k+1 : i])

		// Skip space at the end of the prefix
		i++
	}

	// Find end of command
	j = i + indexByte(raw[i:], space)

	// Extract command
	if j > i {
		m.Command = raw[i:j]
	} else {
		m.Command = raw[i:]

		// We're done here!
		return m
	}

	// Skip space after command
	j++

	// Find prefix for trailer
	i = indexByte(raw[j:], prefix)

	if i < 0 {

		// There is no trailing argument!
		m.Params = strings.Split(raw[j:], string(space))

		// We're done here!
		return m
	}

	// Compensate for index on substring
	i = i + j

	// Check if we need to parse arguments.
	if i > j {
		m.Params = strings.Split(raw[j:i-1], string(space))
	}

	m.Trailing = raw[i+1:]

	// We need to re-encode the trailing argument even if it was empty.
	if len(m.Trailing) <= 0 {
		m.EmptyTrailing = true
	}

	return m

}

// Len calculates the length of the string representation of this message.
func (m *Message) Len() (length int) {

	if m.Prefix != nil {
		length = m.Prefix.Len() + 2 // Include prefix and trailing space
	}

	length = length + len(m.Command)

	if len(m.Params) > 0 {
		length = length + len(m.Params)
		for _, param := range m.Params {
			length = length + len(param)
		}
	}

	if len(m.Trailing) > 0 || m.EmptyTrailing {
		length = length + len(m.Trailing) + 2 // Include prefix and space
	}

	return
}

// Bytes returns a []byte representation of this message.
//
// As noted in rfc2812 section 2.3, messages should not exceed 512 characters
// in length. This method forces that limit by discarding any characters
// exceeding the length limit.
func (m *Message) Bytes() []byte {

	buffer := new(bytes.Buffer)

	// Message prefix
	if m.Prefix != nil {
		buffer.WriteByte(prefix)
		m.Prefix.writeTo(buffer)
		buffer.WriteByte(space)
	}

	// Command is required
	buffer.WriteString(m.Command)

	// Space separated list of arguments
	if len(m.Params) > 0 {
		buffer.WriteByte(space)
		buffer.WriteString(strings.Join(m.Params, string(space)))
	}

	if len(m.Trailing) > 0 || m.EmptyTrailing {
		buffer.WriteByte(space)
		buffer.WriteByte(prefix)
		buffer.WriteString(m.Trailing)
	}

	// We need the limit the buffer length.
	if buffer.Len() > (maxLength) {
		buffer.Truncate(maxLength)
	}

	return buffer.Bytes()
}

// String returns a string representation of this message.
//
// As noted in rfc2812 section 2.3, messages should not exceed 512 characters
// in length. This method forces that limit by discarding any characters
// exceeding the length limit.
func (m *Message) String() string {
	return string(m.Bytes())
}
<|endoftext|>


<commit_before>package main

import (
	"strconv"
	"time"

	"github.com/luizbranco/eventsource"
	"github.com/peterbourgon/g2s"
)

const sampleRate = 0.25
const roundUpMs = 1e3

type StatdsD struct {
	prefix string
	statsd g2s.Statter
}

func NewMetrics(addr string, prefix string) (StatdsD, error) {
	stats := StatdsD{prefix: prefix + "."}
	statsd, err := g2s.Dial("udp", addr)
	if err != nil {
		return stats, err
	}
	stats.statsd = statsd
	return stats, nil
}

func (s StatdsD) ClientCount(count int) {
	n := strconv.Itoa(count)
	s.statsd.Gauge(1, s.prefix+"connections", n)
}

func (s StatdsD) EventDone(e eventsource.Event, d time.Duration, c []time.Duration) {
	s.statsd.Counter(1, s.prefix+"publish.count", 1)
	s.statsd.Timing(sampleRate, s.prefix+"publish.timing", d*roundUpMs)
	for _, t := range c {
		if t > 0 {
			s.statsd.Timing(sampleRate, s.prefix+"publish.connection_write.timing", t*roundUpMs)
		}
	}
}
<commit_msg>Reimplements the metrics module in terms of Google cloud monitoring, WIP<commit_after>package main

import (
	"log"
	"time"

	"github.com/luizbranco/eventsource"

	"golang.org/x/net/context"
	"golang.org/x/oauth2/google"
	"google.golang.org/api/cloudmonitoring/v2beta2"
)

//const sampleRate = 0.25
//const roundUpMs = 1e3

type GoogleCloudMonitoring struct {
	base_url string
	remote   cloudmonitoring.Service
}

func NewMetrics(prefix string) (GoogleCloudMonitoring, error) {
	monitor := GoogleCloudMonitoring{base_url: "custom.cloudmonitoring.googleapis.com/" + prefix + "/"}

	// Use oauth2.NoContext if there isn't a good context to pass in.
	ctx := context.Background()

	client, err := google.DefaultClient(
		ctx,
		cloudmonitoring.MonitoringScope,
	)
	if err != nil {
		log.Fatal(err)
	}

	cloudmonitoringService, err := cloudmonitoring.New(client)
	if err != nil {
		log.Fatal(err)
	}

	monitor.remote = *cloudmonitoringService
	return monitor, nil
}

func (monitor GoogleCloudMonitoring) ClientCount(count int) {
	// n := strconv.Itoa(count)
	// s.statsd.Gauge(1, s.prefix+"connections", n)
}

func (monitor GoogleCloudMonitoring) EventDone(event eventsource.Event, duration time.Duration, eventdurations []time.Duration) {
	// s.statsd.Counter(1, s.prefix+"publish.count", 1)
	// s.statsd.Timing(sampleRate, s.prefix+"publish.timing", d*roundUpMs)
	// for _, t := range c {
	// 	if t > 0 {
	// 		s.statsd.Timing(sampleRate, s.prefix+"publish.connection_write.timing", t*roundUpMs)
	// 	}
	// }

	var sum float64
	var count float64
	var avg float64
	for _, d := range eventdurations {
		if d > 0 {
			sum += float64(d)
			count++
		}
	}
	if count > 0 {
		avg = sum / count
	}
	log.Printf("Event completed - clients %.f, avg time %.2f\n", count, avg)
}

//// If you need a oauth2.TokenSource, use the DefaultTokenSource function:

//ts, err := google.DefaultTokenSource(ctx, scope1, scope2, ...)
//if err != nil {
//  // Handle error.
//}
//httpClient := oauth2.NewClient(ctx, ts)
<|endoftext|>