<commit_before>package format

import (
	"testing"
	"fmt"
)

func TestNilParseStrings(t *testing.T) {
	const expected = ""

	if got := (*ParseStrings)(nil).String(); got != expected {
		t.Errorf("Got: %q; Expected: %q", got, expected)
	}
}

func TestParseStrings(t *testing.T) {
	cases := []struct {
		label    string
		input    string
		ok       bool
		expected string
	}{
		{
			label: "Empty_Input",
			input: "",
		}, {
			label:    "Valid_Input",
			input:    "234,foo,bar",
			ok:       true,
			expected: "234,foo,bar",
		}, {
			label:    "Extra_Comma",
			input:    "234,foo,bar,",
			ok:       true,
			expected: "234,foo,bar,",
		}, {
			label:    "With_Whitespace",
			input:    "234  , foo ,\tbar",
			ok:       true,
			expected: "234,foo,bar",
		},
	}

	for _, c := range cases {
		f := func(t *testing.T) {
			var ints ParseStrings

			if err := ints.Set(c.input); err != nil && c.ok {
				t.Errorf("Got: %v; Expected: <nil>", err)
			} else if err == nil && !c.ok {
				t.Error("Got: <nil>; Expected: some error")
			} else if err == nil && c.ok {
				if got := ints.String(); got != c.expected {
					t.Errorf("Got: %q; Expected: %q", got, c.expected)
				}
			}
		}

		t.Run(c.label, f)
	}
}

func TestNilParseInts(t *testing.T) {
	const expected = ""

	if got := (*ParseInts)(nil).String(); got != expected {
		t.Errorf("Got: %q; Expected: %q", got, expected)
	}
}

func TestParseInts(t *testing.T) {
	cases := []struct {
		label    string
		input    string
		ok       bool
		expected string
	}{
		{
			label: "Empty_Input",
			input: "",
		}, {
			label: "Invalid_Int",
			input: "1,sdfg,2,3",
		}, {
			label: "Extraneous_Comma",
			input: "-1,2,,",
		}, {
			label:    "Without_Whitespace",
			input:    "-1,10,42",
			ok:       true,
			expected: "-1,10,42",
		}, {
			label:    "With_Whitespace",
			input:    "-1, 10 ,\t42",
			ok:       true,
			expected: "-1,10,42",
		},
	}

	for _, c := range cases {
		f := func(t *testing.T) {
			var ints ParseInts

			if err := ints.Set(c.input); err != nil && c.ok {
				t.Errorf("Got: %v; Expected: <nil>", err)
			} else if err == nil && !c.ok {
				t.Error("Got: <nil>; Expected: some error")
			} else if err == nil && c.ok {
				if got := ints.String(); got != c.expected {
					t.Errorf("Got: %q; Expected: %q", got, c.expected)
				}
			}
		}

		t.Run(c.label, f)
	}
}

func TestNilParseIPs(t *testing.T) {
	const expected = ""

	if got := (*ParseIPs)(nil).String(); got != expected {
		t.Errorf("Got: %q; Expected: %q", got, expected)
	}
}

func TestParseIPs(t *testing.T) {
	cases := []struct {
		label    string
		input    string
		ok       bool
		expected string
	}{
		{
			label: "Empty_Input",
			input: "",
		}, {
			label:    "Single_Valid_IPv4",
			input:    "127.0.0.1",
			ok:       true,
			expected: "127.0.0.1",
		}, {
			label:    "Single_Valid_IPv6",
			input:    "2001:0db8:85a3:0000:0000:8a2e:0370:7334",
			ok:       true,
			expected: "2001:db8:85a3::8a2e:370:7334",
		}, {
			label: "Single_IPv4_Byte_Overflow",
			input: "256.0.0.1",
		}, {
			label:    "Valid_Compact_Range",
			input:    "127.0.0.1-3",
			ok:       true,
			expected: "127.0.0.1,127.0.0.2,127.0.0.3",
		}, {
			label:    "Valid_Range",
			input:    "127.0.0.1-127.0.0.3",
			ok:       true,
			expected: "127.0.0.1,127.0.0.2,127.0.0.3",
		}, {
			label: "Empty_Range",
			input: "127.0.0.2-127.0.0.1",
		}, {
			label: "Range_End_Overflows_Byte",
			input: "0.0.0.0-256",
		}, {
			label: "Invalid_Range_End",
			input: "0.0.0.0-1-sdfgkjhsdfg",
		}, {
			label: "Invalid_Range_Start",
			input: "foo-3",
		}, {
			label:    "Range_And_IP",
			input:    "127.0.0.1-3,255.0.0.0",
			ok:       true,
			expected: "127.0.0.1,127.0.0.2,127.0.0.3,255.0.0.0",
		}, {
			label: "Extraneous_Comma",
			input: "127.0.0.1-3,255.0.0.0,",
		}, {
			label: "Whitespace_After_Comma",
			input: "127.0.0.1-3, 255.0.0.0",
		}, {
			label: "Whitespace_Before_Comma",
			input: "127.0.0.1-3 ,255.0.0.0",
		}, {
			label: "Trailing_Whitespace",
			input: "127.0.0.1-3,255.0.0.0 ",
		}, {
			label: "Leading_Whitespace",
			input: " 127.0.0.1-3,255.0.0.0",
		},
	}

	for _, c := range cases {
		f := func(t *testing.T) {
			var ips ParseIPs

			if err := ips.Set(c.input); err != nil && c.ok {
				t.Errorf("Got: %v; Expected: <nil>", err)
			} else if err == nil && !c.ok {
				t.Error("got <nil>; Expected: some error")
			} else if err == nil && c.ok {
				if got := ips.String(); got != c.expected {
					t.Errorf("got %q; Expected: %q", got, c.expected)
				}
			}
		}

		t.Run(c.label, f)
	}
}

func TestNilParseCIDRs(t *testing.T) {
	const expected = ""

	if got := (*ParseCIDRs)(nil).String(); got != expected {
		t.Errorf("Got: %q; Expected: %q", got, expected)
	}
}

func TestParseCIDRs(t *testing.T) {
	cases := []struct {
		label    string
		input    string
		ok       bool
		expected string
	}{
		{
			label: "Empty",
			input: "",
		}, {
			label:    "Valid_CIDRs",
			input:    "192.0.2.1/24,193.0.2.1/16",
			ok:       true,
			expected: "192.0.2.0/24,193.0.0.0/16",
		}, {
			label: "Invalid_CIDRs",
			input: "192.0.2.1/24,193.0.2.1/66",
		}, {
			label: "Whitespace",
			input: "\t192.0.2.1/24, 193.0.2.1/16 ",
		}, {
			label: "Extraneous_Comma",
			input: "192.0.2.1/24,193.0.2.1/16,",
		},
	}
	for _, c := range cases {
		f := func(t *testing.T) {
			var cidrs ParseCIDRs

			if err := cidrs.Set(c.input); err != nil && c.ok {
				t.Errorf("Got %v; Expected: <nil>", err)
			} else if err == nil && !c.ok {
				t.Error("Got <nil>; Expected: some error")
			} else if err == nil && c.ok {
				if got := cidrs.String(); got != c.expected {
					t.Errorf("Got %q; Expected: %q", got, c.expected)
				}
			}
		}

		t.Run(c.label, f)
	}
}

func TestParseASNs(t *testing.T) {
	cases := []struct {
		label    string
		input    string
		ok       bool
		expected string
	}{
		{
			label: "Empty",
			input: "",
		}, {
			label:    "Valid_ASNs_With_And_Without_AS_Prefix",
			input:    "AS1234,AS4567,7777",
			ok:       true,
			expected: "1234,4567,7777",
		}, {
			label: "Invalid_ASN",
			input: "AS1234,4567,ASABC",
		}, {
			label:    "Whitespace",
			input:    "\tAS1234 , 4567 ",
			ok:       true,
			expected: "1234,4567",
		}, {
			label: "Extraneous_Comma",
			input: "AS1234,",
		},
	}

	for _, c := range cases {
		f := func(t *testing.T) {
			var asns ParseASNs

			if err := asns.Set(c.input); err != nil && c.ok {
				t.Errorf("Got: %v; Expected: <nil>", err)
			} else if err == nil && !c.ok {
				t.Error("Got: <nil>; Expected: some error")
			} else if err == nil && c.ok {
				if got := asns.String(); got != c.expected {
					t.Errorf("Got: %q; Expected: %q", got, c.expected)
				}
			}
		}

		t.Run(c.label, f)
	}
}

func TestParseRange(t *testing.T) {
	type args struct {
		s string
	}
	tests := []struct {
		name    string
		args    args
		expectedStart string
		expectedEnd string
		expectedOk  bool
	}{
		{
			name:    "basic success - full range",
			args:    args{s: "192.168.0.1-192.168.0.3"},
			expectedStart: "192.168.0.1",
			expectedEnd:   "192.168.0.3",
			expectedOk:    true,
		},
		{
			name:    "basic success - short-hand range",
			args:    args{s: "192.168.0.1-4"},
			expectedStart: "192.168.0.1",
			expectedEnd:   "192.168.0.4",
			expectedOk:    true,

		},
		{
			name:    "illicit split",
			args:    args{s: "192.168.0.1"},
			expectedStart: "<nil>",
			expectedEnd:   "<nil>",
			expectedOk:    false,
		},
		{
			name:    "illicit range",
			args:    args{s: "192.168.0.255-192.168.0.260"},
			expectedStart: "192.168.0.255",
			expectedEnd:   "<nil>",
			expectedOk:    true,
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			start,end,ok := parseRange(tt.args.s);
			 if ((fmt.Sprintf("%v",start) != tt.expectedStart)&&(fmt.Sprintf("%v",end) != tt.expectedEnd)&&(ok != tt.expectedOk)){
				t.Errorf("parseIPs.parseRange() error = %v, wantErr %v", start, tt.expectedStart)
				t.Errorf("parseIPs.parseRange() error = %v, wantErr %v", end, tt.expectedEnd)
				t.Errorf("parseIPs.parseRange() error = %v, wantErr %v", ok, tt.expectedOk)
			}
		})
	}
}
<commit_msg>Cleaned up one of the unit tests<commit_after>// Copyright © by Jeff Foley 2017-2022. All rights reserved.
// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.
// SPDX-License-Identifier: Apache-2.0

package format

import (
	"fmt"
	"testing"
)

func TestNilParseStrings(t *testing.T) {
	const expected = ""

	if got := (*ParseStrings)(nil).String(); got != expected {
		t.Errorf("Got: %q; Expected: %q", got, expected)
	}
}

func TestParseStrings(t *testing.T) {
	cases := []struct {
		label    string
		input    string
		ok       bool
		expected string
	}{
		{
			label: "Empty_Input",
			input: "",
		}, {
			label:    "Valid_Input",
			input:    "234,foo,bar",
			ok:       true,
			expected: "234,foo,bar",
		}, {
			label:    "Extra_Comma",
			input:    "234,foo,bar,",
			ok:       true,
			expected: "234,foo,bar,",
		}, {
			label:    "With_Whitespace",
			input:    "234  , foo ,\tbar",
			ok:       true,
			expected: "234,foo,bar",
		},
	}

	for _, c := range cases {
		f := func(t *testing.T) {
			var ints ParseStrings

			if err := ints.Set(c.input); err != nil && c.ok {
				t.Errorf("Got: %v; Expected: <nil>", err)
			} else if err == nil && !c.ok {
				t.Error("Got: <nil>; Expected: some error")
			} else if err == nil && c.ok {
				if got := ints.String(); got != c.expected {
					t.Errorf("Got: %q; Expected: %q", got, c.expected)
				}
			}
		}

		t.Run(c.label, f)
	}
}

func TestNilParseInts(t *testing.T) {
	const expected = ""

	if got := (*ParseInts)(nil).String(); got != expected {
		t.Errorf("Got: %q; Expected: %q", got, expected)
	}
}

func TestParseInts(t *testing.T) {
	cases := []struct {
		label    string
		input    string
		ok       bool
		expected string
	}{
		{
			label: "Empty_Input",
			input: "",
		}, {
			label: "Invalid_Int",
			input: "1,sdfg,2,3",
		}, {
			label: "Extraneous_Comma",
			input: "-1,2,,",
		}, {
			label:    "Without_Whitespace",
			input:    "-1,10,42",
			ok:       true,
			expected: "-1,10,42",
		}, {
			label:    "With_Whitespace",
			input:    "-1, 10 ,\t42",
			ok:       true,
			expected: "-1,10,42",
		},
	}

	for _, c := range cases {
		f := func(t *testing.T) {
			var ints ParseInts

			if err := ints.Set(c.input); err != nil && c.ok {
				t.Errorf("Got: %v; Expected: <nil>", err)
			} else if err == nil && !c.ok {
				t.Error("Got: <nil>; Expected: some error")
			} else if err == nil && c.ok {
				if got := ints.String(); got != c.expected {
					t.Errorf("Got: %q; Expected: %q", got, c.expected)
				}
			}
		}

		t.Run(c.label, f)
	}
}

func TestNilParseIPs(t *testing.T) {
	const expected = ""

	if got := (*ParseIPs)(nil).String(); got != expected {
		t.Errorf("Got: %q; Expected: %q", got, expected)
	}
}

func TestParseIPs(t *testing.T) {
	cases := []struct {
		label    string
		input    string
		ok       bool
		expected string
	}{
		{
			label: "Empty_Input",
			input: "",
		}, {
			label:    "Single_Valid_IPv4",
			input:    "127.0.0.1",
			ok:       true,
			expected: "127.0.0.1",
		}, {
			label:    "Single_Valid_IPv6",
			input:    "2001:0db8:85a3:0000:0000:8a2e:0370:7334",
			ok:       true,
			expected: "2001:db8:85a3::8a2e:370:7334",
		}, {
			label: "Single_IPv4_Byte_Overflow",
			input: "256.0.0.1",
		}, {
			label:    "Valid_Compact_Range",
			input:    "127.0.0.1-3",
			ok:       true,
			expected: "127.0.0.1,127.0.0.2,127.0.0.3",
		}, {
			label:    "Valid_Range",
			input:    "127.0.0.1-127.0.0.3",
			ok:       true,
			expected: "127.0.0.1,127.0.0.2,127.0.0.3",
		}, {
			label: "Empty_Range",
			input: "127.0.0.2-127.0.0.1",
		}, {
			label: "Range_End_Overflows_Byte",
			input: "0.0.0.0-256",
		}, {
			label: "Invalid_Range_End",
			input: "0.0.0.0-1-sdfgkjhsdfg",
		}, {
			label: "Invalid_Range_Start",
			input: "foo-3",
		}, {
			label:    "Range_And_IP",
			input:    "127.0.0.1-3,255.0.0.0",
			ok:       true,
			expected: "127.0.0.1,127.0.0.2,127.0.0.3,255.0.0.0",
		}, {
			label: "Extraneous_Comma",
			input: "127.0.0.1-3,255.0.0.0,",
		}, {
			label: "Whitespace_After_Comma",
			input: "127.0.0.1-3, 255.0.0.0",
		}, {
			label: "Whitespace_Before_Comma",
			input: "127.0.0.1-3 ,255.0.0.0",
		}, {
			label: "Trailing_Whitespace",
			input: "127.0.0.1-3,255.0.0.0 ",
		}, {
			label: "Leading_Whitespace",
			input: " 127.0.0.1-3,255.0.0.0",
		},
	}

	for _, c := range cases {
		f := func(t *testing.T) {
			var ips ParseIPs

			if err := ips.Set(c.input); err != nil && c.ok {
				t.Errorf("Got: %v; Expected: <nil>", err)
			} else if err == nil && !c.ok {
				t.Error("got <nil>; Expected: some error")
			} else if err == nil && c.ok {
				if got := ips.String(); got != c.expected {
					t.Errorf("got %q; Expected: %q", got, c.expected)
				}
			}
		}

		t.Run(c.label, f)
	}
}

func TestNilParseCIDRs(t *testing.T) {
	const expected = ""

	if got := (*ParseCIDRs)(nil).String(); got != expected {
		t.Errorf("Got: %q; Expected: %q", got, expected)
	}
}

func TestParseCIDRs(t *testing.T) {
	cases := []struct {
		label    string
		input    string
		ok       bool
		expected string
	}{
		{
			label: "Empty",
			input: "",
		}, {
			label:    "Valid_CIDRs",
			input:    "192.0.2.1/24,193.0.2.1/16",
			ok:       true,
			expected: "192.0.2.0/24,193.0.0.0/16",
		}, {
			label: "Invalid_CIDRs",
			input: "192.0.2.1/24,193.0.2.1/66",
		}, {
			label: "Whitespace",
			input: "\t192.0.2.1/24, 193.0.2.1/16 ",
		}, {
			label: "Extraneous_Comma",
			input: "192.0.2.1/24,193.0.2.1/16,",
		},
	}
	for _, c := range cases {
		f := func(t *testing.T) {
			var cidrs ParseCIDRs

			if err := cidrs.Set(c.input); err != nil && c.ok {
				t.Errorf("Got %v; Expected: <nil>", err)
			} else if err == nil && !c.ok {
				t.Error("Got <nil>; Expected: some error")
			} else if err == nil && c.ok {
				if got := cidrs.String(); got != c.expected {
					t.Errorf("Got %q; Expected: %q", got, c.expected)
				}
			}
		}

		t.Run(c.label, f)
	}
}

func TestParseASNs(t *testing.T) {
	cases := []struct {
		label    string
		input    string
		ok       bool
		expected string
	}{
		{
			label: "Empty",
			input: "",
		}, {
			label:    "Valid_ASNs_With_And_Without_AS_Prefix",
			input:    "AS1234,AS4567,7777",
			ok:       true,
			expected: "1234,4567,7777",
		}, {
			label: "Invalid_ASN",
			input: "AS1234,4567,ASABC",
		}, {
			label:    "Whitespace",
			input:    "\tAS1234 , 4567 ",
			ok:       true,
			expected: "1234,4567",
		}, {
			label: "Extraneous_Comma",
			input: "AS1234,",
		},
	}

	for _, c := range cases {
		f := func(t *testing.T) {
			var asns ParseASNs

			if err := asns.Set(c.input); err != nil && c.ok {
				t.Errorf("Got: %v; Expected: <nil>", err)
			} else if err == nil && !c.ok {
				t.Error("Got: <nil>; Expected: some error")
			} else if err == nil && c.ok {
				if got := asns.String(); got != c.expected {
					t.Errorf("Got: %q; Expected: %q", got, c.expected)
				}
			}
		}

		t.Run(c.label, f)
	}
}

func TestParseRange(t *testing.T) {
	tests := []struct {
		name  string
		args  string
		start string
		end   string
		ok    bool
	}{
		{
			name:  "basic success - full range",
			args:  "192.168.0.1-192.168.0.3",
			start: "192.168.0.1",
			end:   "192.168.0.3",
			ok:    true,
		},
		{
			name:  "basic success - short-hand range",
			args:  "192.168.0.1-4",
			start: "192.168.0.1",
			end:   "192.168.0.4",
			ok:    true,
		},
		{
			name:  "illicit split",
			args:  "192.168.0.1",
			start: "<nil>",
			end:   "<nil>",
			ok:    false,
		},
		{
			name:  "illicit range",
			args:  "192.168.0.255-192.168.0.260",
			start: "192.168.0.255",
			end:   "<nil>",
			ok:    true,
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			if start, end, ok := parseRange(tt.args); fmt.Sprintf("%v",
				start) != tt.start && fmt.Sprintf("%v", end) != tt.end && ok != tt.ok {
				t.Errorf("parseIPs.parseRange() error = %v, wantErr %v", start, tt.start)
				t.Errorf("parseIPs.parseRange() error = %v, wantErr %v", end, tt.end)
				t.Errorf("parseIPs.parseRange() error = %v, wantErr %v", ok, tt.ok)
			}
		})
	}
}
<|endoftext|>


<commit_before>package couchbase

import (
	"bytes"
	"fmt"
)

type User struct {
	Name   string
	Id     string
	Domain string
	Roles  []Role
}

type Role struct {
	Role       string
	BucketName string `json:"bucket_name"`
}

// Sample:
// {"role":"admin","name":"Admin","desc":"Can manage ALL cluster features including security.","ce":true}
// {"role":"query_select","bucket_name":"*","name":"Query Select","desc":"Can execute SELECT statement on bucket to retrieve data"}
type RoleDescription struct {
	Role       string
	Name       string
	Desc       string
	Ce         bool
	BucketName string `json:"bucket_name"`
}

// Return user-role data, as parsed JSON.
// Sample:
//   [{"id":"ivanivanov","name":"Ivan Ivanov","roles":[{"role":"cluster_admin"},{"bucket_name":"default","role":"bucket_admin"}]},
//    {"id":"petrpetrov","name":"Petr Petrov","roles":[{"role":"replication_admin"}]}]
func (c *Client) GetUserRoles() ([]interface{}, error) {
	ret := make([]interface{}, 0, 1)
	err := c.parseURLResponse("/settings/rbac/users", &ret)
	if err != nil {
		return nil, err
	}

	// Get the configured administrator.
	// Expected result: {"port":8091,"username":"Administrator"}
	adminInfo := make(map[string]interface{}, 2)
	err = c.parseURLResponse("/settings/web", &adminInfo)
	if err != nil {
		return nil, err
	}

	// Create a special entry for the configured administrator.
	adminResult := map[string]interface{}{
		"name":   adminInfo["username"],
		"id":     adminInfo["username"],
		"domain": "ns_server",
		"roles": []interface{}{
			map[string]interface{}{
				"role": "admin",
			},
		},
	}

	// Add the configured administrator to the list of results.
	ret = append(ret, adminResult)

	return ret, nil
}

func (c *Client) GetUserInfoAll() ([]User, error) {
	ret := make([]User, 0, 16)
	err := c.parseURLResponse("/settings/rbac/users", &ret)
	if err != nil {
		return nil, err
	}
	return ret, nil
}

func rolesToParamFormat(roles []Role) string {
	var buffer bytes.Buffer
	for i, role := range roles {
		if i > 0 {
			buffer.WriteString(",")
		}
		buffer.WriteString(role.Role)
		if role.BucketName != "" {
			buffer.WriteString("[")
			buffer.WriteString(role.BucketName)
			buffer.WriteString("]")
		}
	}
	return buffer.String()
}

func (c *Client) PutUserInfo(u *User) error {
	params := map[string]interface{}{
		"name":  u.Name,
		"roles": rolesToParamFormat(u.Roles),
	}
	var target string
	switch u.Domain {
	case "external":
		target = "/settings/rbac/users/" + u.Id
	case "local":
		target = "/settings/rbac/users/local/" + u.Id
	default:
		return fmt.Errorf("Unknown user type: %s", u.Domain)
	}
	var ret string // PUT returns an empty string. We ignore it.
	err := c.parsePutURLResponse(target, params, &ret)
	return err
}

func (c *Client) GetRolesAll() ([]RoleDescription, error) {
	ret := make([]RoleDescription, 0, 32)
	err := c.parseURLResponse("/settings/rbac/roles", &ret)
	if err != nil {
		return nil, err
	}
	return ret, nil
}
<commit_msg>MB-31294 RBAC changes for GRANT / REVOKE and collection permissions<commit_after>package couchbase

import (
	"bytes"
	"fmt"
)

type User struct {
	Name   string
	Id     string
	Domain string
	Roles  []Role
}

type Role struct {
	Role       string
	BucketName string `json:"bucket_name"`
	ScopeName string `json:"scope_name"`
	CollectionName string `json:"collection_name"`
}

// Sample:
// {"role":"admin","name":"Admin","desc":"Can manage ALL cluster features including security.","ce":true}
// {"role":"query_select","bucket_name":"*","name":"Query Select","desc":"Can execute SELECT statement on bucket to retrieve data"}
type RoleDescription struct {
	Role       string
	Name       string
	Desc       string
	Ce         bool
	BucketName string `json:"bucket_name"`
}

// Return user-role data, as parsed JSON.
// Sample:
//   [{"id":"ivanivanov","name":"Ivan Ivanov","roles":[{"role":"cluster_admin"},{"bucket_name":"default","role":"bucket_admin"}]},
//    {"id":"petrpetrov","name":"Petr Petrov","roles":[{"role":"replication_admin"}]}]
func (c *Client) GetUserRoles() ([]interface{}, error) {
	ret := make([]interface{}, 0, 1)
	err := c.parseURLResponse("/settings/rbac/users", &ret)
	if err != nil {
		return nil, err
	}

	// Get the configured administrator.
	// Expected result: {"port":8091,"username":"Administrator"}
	adminInfo := make(map[string]interface{}, 2)
	err = c.parseURLResponse("/settings/web", &adminInfo)
	if err != nil {
		return nil, err
	}

	// Create a special entry for the configured administrator.
	adminResult := map[string]interface{}{
		"name":   adminInfo["username"],
		"id":     adminInfo["username"],
		"domain": "ns_server",
		"roles": []interface{}{
			map[string]interface{}{
				"role": "admin",
			},
		},
	}

	// Add the configured administrator to the list of results.
	ret = append(ret, adminResult)

	return ret, nil
}

func (c *Client) GetUserInfoAll() ([]User, error) {
	ret := make([]User, 0, 16)
	err := c.parseURLResponse("/settings/rbac/users", &ret)
	if err != nil {
		return nil, err
	}
	return ret, nil
}

func rolesToParamFormat(roles []Role) string {
	var buffer bytes.Buffer
	for i, role := range roles {
		if i > 0 {
			buffer.WriteString(",")
		}
		buffer.WriteString(role.Role)
		if role.BucketName != "" {
			buffer.WriteString("[")
			buffer.WriteString(role.BucketName)
			buffer.WriteString("]")
		}
	}
	return buffer.String()
}

func (c *Client) PutUserInfo(u *User) error {
	params := map[string]interface{}{
		"name":  u.Name,
		"roles": rolesToParamFormat(u.Roles),
	}
	var target string
	switch u.Domain {
	case "external":
		target = "/settings/rbac/users/" + u.Id
	case "local":
		target = "/settings/rbac/users/local/" + u.Id
	default:
		return fmt.Errorf("Unknown user type: %s", u.Domain)
	}
	var ret string // PUT returns an empty string. We ignore it.
	err := c.parsePutURLResponse(target, params, &ret)
	return err
}

func (c *Client) GetRolesAll() ([]RoleDescription, error) {
	ret := make([]RoleDescription, 0, 32)
	err := c.parseURLResponse("/settings/rbac/roles", &ret)
	if err != nil {
		return nil, err
	}
	return ret, nil
}
<|endoftext|>


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

package gitlab

import (
	"fmt"
	"net/url"
)

// WikisService handles communication with the wikis related methods of
// the Gitlab API.
//
// GitLab API docs: https://docs.gitlab.com/ce/api/wikis.html
type WikisService struct {
	client *Client
}

// WikiFormat represents the available wiki formats
//
// GitLab API docs: https://docs.gitlab.com/ce/api/wikis.html
type WikiFormat string

// The available todo actions.
const (
	WikiFormatMarkdown WikiFormat = "markdown"
	WikiFormatRFoc     WikiFormat = "rdoc"
	WikiFormatASCIIDoc WikiFormat = "asciidoc"
)

// Wiki represents a GitLab wiki.
//
// GitLab API docs: https://docs.gitlab.com/ce/api/wikis.html
type Wiki struct {
	Content string     `json:"content"`
	Format  WikiFormat `json:"format"`
	Slug    string     `json:"slug"`
	Title   string     `json:"title"`
}

func (w Wiki) String() string {
	return Stringify(w)
}

// ListWikisOptions represents the available ListWikis options.
//
// GitLab API docs: https://docs.gitlab.com/ce/api/wikis.html#list-wiki-pages
type ListWikisOptions struct {
	WithContent *bool `url:"with_content,omitempty" json:"with_content,omitempty"`
}

// ListWikis lists all pages of the wiki of the given project id.
// When with_content is set, it returns also the content of the pages.
//
// GitLab API docs: https://docs.gitlab.com/ce/api/wikis.html#list-wiki-pages
func (s *WikisService) ListWikis(pid interface{}, opt *ListWikisOptions, options ...OptionFunc) ([]*Wiki, *Response, error) {
	project, err := parseID(pid)
	if err != nil {
		return nil, nil, err
	}
	u := fmt.Sprintf("projects/%s/wikis", url.QueryEscape(project))

	req, err := s.client.NewRequest("GET", u, opt, options)
	if err != nil {
		return nil, nil, err
	}

	var w []*Wiki
	resp, err := s.client.Do(req, &w)
	if err != nil {
		return nil, resp, err
	}

	return w, resp, err
}

// GetWikiPage gets a wiki page for a given project.
//
// GitLab API docs: https://docs.gitlab.com/ce/api/wikis.html#get-a-wiki-page
func (s *WikisService) GetWikiPage(pid interface{}, slug string, options ...OptionFunc) (*Wiki, *Response, error) {
	project, err := parseID(pid)
	if err != nil {
		return nil, nil, err
	}
	u := fmt.Sprintf("projects/%s/wikis/%s", url.QueryEscape(project), url.QueryEscape(slug))

	req, err := s.client.NewRequest("GET", u, nil, options)
	if err != nil {
		return nil, nil, err
	}

	var w *Wiki
	resp, err := s.client.Do(req, &w)
	if err != nil {
		return nil, resp, err
	}

	return w, resp, err
}

// CreateWikiPageOptions represents options to CreateWikiPage
//
// GitLab API docs:
// https://docs.gitlab.com/ce/api/wikis.html#create-a-new-wiki-page
type CreateWikiPageOptions struct {
	Content *string `url:"content" json:"content"`
	Title   *string `url:"title" json:"title"`
	Format  *string `url:"format,omitempty" json:"format,omitempty"`
}

// CreateWikiPage creates a new wiki page for the given repository with
// the given title, slug, and content..
//
// GitLab API docs:
// https://docs.gitlab.com/ce/api/wikis.html#create-a-new-wiki-page
func (s *WikisService) CreateWikiPage(pid interface{}, opt *CreateWikiPageOptions, options ...OptionFunc) (*Wiki, *Response, error) {
	project, err := parseID(pid)
	if err != nil {
		return nil, nil, err
	}
	u := fmt.Sprintf("projects/%s/wikis", url.QueryEscape(project))

	req, err := s.client.NewRequest("POST", u, opt, options)
	if err != nil {
		return nil, nil, err
	}

	w := new(Wiki)
	resp, err := s.client.Do(req, w)
	if err != nil {
		return nil, resp, err
	}

	return w, resp, err
}

// EditWikiPageOptions represents options to EditWikiPage
//
// GitLab API docs:
// https://docs.gitlab.com/ce/api/wikis.html#edit-an-existing-wiki-page
type EditWikiPageOptions struct {
	Content *string `url:"content" json:"content"`
	Title   *string `url:"title" json:"title"`
	Format  *string `url:"format,omitempty" json:"format,omitempty"`
}

// EditWikiPage Updates an existing wiki page. At least one parameter is
// required to update the wiki page.
//
// GitLab API docs:
// https://docs.gitlab.com/ce/api/wikis.html#edit-an-existing-wiki-page
func (s *WikisService) EditWikiPage(pid interface{}, slug string, opt *EditWikiPageOptions, options ...OptionFunc) (*Wiki, *Response, error) {
	project, err := parseID(pid)
	if err != nil {
		return nil, nil, err
	}
	u := fmt.Sprintf("projects/%s/wikis/%s", url.QueryEscape(project), url.QueryEscape(slug))

	req, err := s.client.NewRequest("PUT", u, opt, options)
	if err != nil {
		return nil, nil, err
	}

	w := new(Wiki)
	resp, err := s.client.Do(req, w)
	if err != nil {
		return nil, resp, err
	}

	return w, resp, err
}

// DeleteWikiPage deletes a wiki page with a given slug.
//
// GitLab API docs: https://docs.gitlab.com/ce/api/wikis.html#delete-a-wiki-page
func (s *WikisService) DeleteWikiPage(pid interface{}, slug string, options ...OptionFunc) (*Response, error) {
	project, err := parseID(pid)
	if err != nil {
		return nil, err
	}
	u := fmt.Sprintf("projects/%s/wikis/%s", url.QueryEscape(project), url.QueryEscape(slug))

	req, err := s.client.NewRequest("DELETE", u, nil, options)
	if err != nil {
		return nil, err
	}

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

package gitlab

import (
	"fmt"
	"net/url"
)

// WikisService handles communication with the wikis related methods of
// the Gitlab API.
//
// GitLab API docs: https://docs.gitlab.com/ce/api/wikis.html
type WikisService struct {
	client *Client
}

// WikiFormat represents the available wiki formats.
//
// GitLab API docs: https://docs.gitlab.com/ce/api/wikis.html
type WikiFormat string

// The available wiki formats.
const (
	WikiFormatMarkdown WikiFormat = "markdown"
	WikiFormatRFoc     WikiFormat = "rdoc"
	WikiFormatASCIIDoc WikiFormat = "asciidoc"
)

// Wiki represents a GitLab wiki.
//
// GitLab API docs: https://docs.gitlab.com/ce/api/wikis.html
type Wiki struct {
	Content string     `json:"content"`
	Format  WikiFormat `json:"format"`
	Slug    string     `json:"slug"`
	Title   string     `json:"title"`
}

func (w Wiki) String() string {
	return Stringify(w)
}

// ListWikisOptions represents the available ListWikis options.
//
// GitLab API docs:
// https://docs.gitlab.com/ce/api/wikis.html#list-wiki-pages
type ListWikisOptions struct {
	WithContent *bool `url:"with_content,omitempty" json:"with_content,omitempty"`
}

// ListWikis lists all pages of the wiki of the given project id.
// When with_content is set, it also returns the content of the pages.
//
// GitLab API docs:
// https://docs.gitlab.com/ce/api/wikis.html#list-wiki-pages
func (s *WikisService) ListWikis(pid interface{}, opt *ListWikisOptions, options ...OptionFunc) ([]*Wiki, *Response, error) {
	project, err := parseID(pid)
	if err != nil {
		return nil, nil, err
	}
	u := fmt.Sprintf("projects/%s/wikis", url.QueryEscape(project))

	req, err := s.client.NewRequest("GET", u, opt, options)
	if err != nil {
		return nil, nil, err
	}

	var w []*Wiki
	resp, err := s.client.Do(req, &w)
	if err != nil {
		return nil, resp, err
	}

	return w, resp, err
}

// GetWikiPage gets a wiki page for a given project.
//
// GitLab API docs:
// https://docs.gitlab.com/ce/api/wikis.html#get-a-wiki-page
func (s *WikisService) GetWikiPage(pid interface{}, slug string, options ...OptionFunc) (*Wiki, *Response, error) {
	project, err := parseID(pid)
	if err != nil {
		return nil, nil, err
	}
	u := fmt.Sprintf("projects/%s/wikis/%s", url.QueryEscape(project), url.QueryEscape(slug))

	req, err := s.client.NewRequest("GET", u, nil, options)
	if err != nil {
		return nil, nil, err
	}

	var w *Wiki
	resp, err := s.client.Do(req, &w)
	if err != nil {
		return nil, resp, err
	}

	return w, resp, err
}

// CreateWikiPageOptions represents options to CreateWikiPage.
//
// GitLab API docs:
// https://docs.gitlab.com/ce/api/wikis.html#create-a-new-wiki-page
type CreateWikiPageOptions struct {
	Content *string `url:"content" json:"content"`
	Title   *string `url:"title" json:"title"`
	Format  *string `url:"format,omitempty" json:"format,omitempty"`
}

// CreateWikiPage creates a new wiki page for the given repository with
// the given title, slug, and content.
//
// GitLab API docs:
// https://docs.gitlab.com/ce/api/wikis.html#create-a-new-wiki-page
func (s *WikisService) CreateWikiPage(pid interface{}, opt *CreateWikiPageOptions, options ...OptionFunc) (*Wiki, *Response, error) {
	project, err := parseID(pid)
	if err != nil {
		return nil, nil, err
	}
	u := fmt.Sprintf("projects/%s/wikis", url.QueryEscape(project))

	req, err := s.client.NewRequest("POST", u, opt, options)
	if err != nil {
		return nil, nil, err
	}

	w := new(Wiki)
	resp, err := s.client.Do(req, w)
	if err != nil {
		return nil, resp, err
	}

	return w, resp, err
}

// EditWikiPageOptions represents options to EditWikiPage.
//
// GitLab API docs:
// https://docs.gitlab.com/ce/api/wikis.html#edit-an-existing-wiki-page
type EditWikiPageOptions struct {
	Content *string `url:"content" json:"content"`
	Title   *string `url:"title" json:"title"`
	Format  *string `url:"format,omitempty" json:"format,omitempty"`
}

// EditWikiPage Updates an existing wiki page. At least one parameter is
// required to update the wiki page.
//
// GitLab API docs:
// https://docs.gitlab.com/ce/api/wikis.html#edit-an-existing-wiki-page
func (s *WikisService) EditWikiPage(pid interface{}, slug string, opt *EditWikiPageOptions, options ...OptionFunc) (*Wiki, *Response, error) {
	project, err := parseID(pid)
	if err != nil {
		return nil, nil, err
	}
	u := fmt.Sprintf("projects/%s/wikis/%s", url.QueryEscape(project), url.QueryEscape(slug))

	req, err := s.client.NewRequest("PUT", u, opt, options)
	if err != nil {
		return nil, nil, err
	}

	w := new(Wiki)
	resp, err := s.client.Do(req, w)
	if err != nil {
		return nil, resp, err
	}

	return w, resp, err
}

// DeleteWikiPage deletes a wiki page with a given slug.
//
// GitLab API docs:
// https://docs.gitlab.com/ce/api/wikis.html#delete-a-wiki-page
func (s *WikisService) DeleteWikiPage(pid interface{}, slug string, options ...OptionFunc) (*Response, error) {
	project, err := parseID(pid)
	if err != nil {
		return nil, err
	}
	u := fmt.Sprintf("projects/%s/wikis/%s", url.QueryEscape(project), url.QueryEscape(slug))

	req, err := s.client.NewRequest("DELETE", u, nil, options)
	if err != nil {
		return nil, err
	}

	return s.client.Do(req, nil)
}
<|endoftext|>


<commit_before>// Package world provide ports to WORLD - a high-quality speech analysis, modification and synthesis system written in C++.
package world

// Functions in this file ara simple ports to original cpp functions.
// Go-like interfaces will be found in go_interface.go

// #cgo pkg-config: world
// #include <world/dio.h>
// #include <world/platinum.h>
// #include <world/synthesis.h>
// #include <world/star.h>
// #include <world/tandem_ap.h>
// #include <world/synthesis_ap.h>
// #include <stdlib.h>
import "C"

import (
	"unsafe"
)

const (
	byteSizeOfFloat64 = 8
)

type DioOption struct {
	F0Floor          float64
	F0Ceil           float64
	ChannelsInOctave float64
	FramePeriod      float64 // [ms]
	Speed            int     // (1,2, ..., 12)
}

func NewDioOption() DioOption {
	opt := DioOption{
		F0Floor:          80.0,
		F0Ceil:           640.0,
		FramePeriod:      5,
		ChannelsInOctave: 4.0,
		Speed:            6,
	}
	return opt
}

func Dio(x []float64, fs int, option DioOption) ([]float64, []float64) {
	numFrames := GetSamplesForDIO(fs, len(x), option.FramePeriod)
	timeAxis := make([]float64, numFrames)
	f0 := make([]float64, numFrames)

	// Create C interface of DioOption
	var opt C.DioOption
	opt.frame_period = C.double(option.FramePeriod)
	opt.f0_floor = C.double(option.F0Floor)
	opt.f0_ceil = C.double(option.F0Ceil)
	opt.channels_in_octave = C.double(option.ChannelsInOctave)
	opt.speed = C.int(option.Speed)

	// Perform DIO
	C.Dio2((*C.double)(&x[0]),
		C.int(len(x)),
		C.int(fs),
		opt,
		(*C.double)(&timeAxis[0]),
		(*C.double)(&f0[0]))

	return timeAxis, f0
}

func GetSamplesForDIO(fs, x_length int, framePeriod float64) int {
	return int(C.GetSamplesForDIO(C.int(fs), C.int(x_length), C.double(framePeriod)))
}

func Star(x []float64, fs int, timeAxis, f0 []float64) [][]float64 {
	FFTSize := C.size_t(C.GetFFTSizeForStar(C.int(fs)))
	numFreqBins := FFTSize/2 + 1

	// Create workspace
	wspace := make([]*C.double, len(f0))
	for i := range wspace {
		wspace[i] = (*C.double)(C.malloc(byteSizeOfFloat64 * numFreqBins))
		defer C.free(unsafe.Pointer(wspace[i]))
	}

	// Perform star
	C.Star((*C.double)(&x[0]),
		C.int(len(x)),
		C.int(fs),
		(*C.double)(&timeAxis[0]),
		(*C.double)(&f0[0]),
		C.int(len(f0)),
		(**C.double)(&wspace[0]))

	// Copy to go slice
	spectrogram := make([][]float64, len(f0))
	for i := range spectrogram {
		spectrogram[i] = CArrayToGoSlice(wspace[i], C.int(numFreqBins))
	}

	return spectrogram
}

func GetFFTSizeForStar(fs int) int {
	return int(C.GetFFTSizeForStar(C.int(fs)))
}

func Platinum(x []float64, fs int, timeAxis, f0 []float64, spectrogram [][]float64) [][]float64 {
	FFTSize := C.size_t(C.GetFFTSizeForStar(C.int(fs)))
	numFreqBins := C.size_t(FFTSize + 1)

	spectrogramUsedInC := Make2DCArrayAlternative(spectrogram)
	residualSpectrogramUsedInC := make([]*C.double, len(spectrogram))
	for i := range residualSpectrogramUsedInC {
		residualSpectrogramUsedInC[i] = (*C.double)(C.malloc(byteSizeOfFloat64 * numFreqBins))
		defer C.free(unsafe.Pointer(residualSpectrogramUsedInC[i]))
	}

	C.Platinum((*C.double)(&x[0]),
		C.int(len(x)),
		C.int(fs),
		(*C.double)(&timeAxis[0]),
		(*C.double)(&f0[0]),
		C.int(len(f0)),
		(**C.double)(&spectrogramUsedInC[0]),
		C.int(FFTSize),
		(**C.double)(&residualSpectrogramUsedInC[0]))

	residualSpectrogram := make([][]float64, len(f0))
	for i := range residualSpectrogramUsedInC {
		residualSpectrogram[i] = CArrayToGoSlice(residualSpectrogramUsedInC[i], C.int(numFreqBins))
	}

	return residualSpectrogram
}

func Synthesis(f0 []float64, spectrogram, residualSpectrogram [][]float64, framePeriod float64, fs, length int) []float64 {
	FFTSize := C.size_t(C.GetFFTSizeForStar(C.int(fs)))

	spectrogramUsedInC := Make2DCArrayAlternative(spectrogram)
	residualSpectrogramUsedInC := Make2DCArrayAlternative(residualSpectrogram)

	synthesized := make([]float64, length)
	C.Synthesis((*C.double)(&f0[0]),
		C.int(len(f0)),
		(**C.double)(&spectrogramUsedInC[0]),
		(**C.double)(&residualSpectrogramUsedInC[0]),
		C.int(FFTSize),
		C.double(framePeriod),
		C.int(fs),
		C.int(len(synthesized)),
		(*C.double)(&synthesized[0]))

	return synthesized
}

func GetNumberOfBands(fs int) int {
	return int(C.GetNumberOfBands(C.int(fs)))
}

func AperiodicityRatio(x []float64, fs int, f0 []float64, framePeriod float64) ([][]float64, float64) {
	numBands := GetNumberOfBands(fs)

	// Create workspace
	wspace := make([]*C.double, len(f0))
	for i := range wspace {
		wspace[i] = (*C.double)(C.malloc(C.size_t(byteSizeOfFloat64 * numBands)))
		defer C.free(unsafe.Pointer(wspace[i]))
	}

	// Peform aperiodicity analysis
	targetF0 := C.AperiodicityRatio((*C.double)(&x[0]),
		C.int(len(x)),
		C.int(fs),
		(*C.double)(&f0[0]),
		C.int(len(f0)),
		C.double(framePeriod),
		(**C.double)(&wspace[0]))

	// Copy to go slice
	aperiodicity := make([][]float64, len(f0))
	for i := range aperiodicity {
		aperiodicity[i] = CArrayToGoSlice(wspace[i], C.int(numBands))
	}

	return aperiodicity, float64(targetF0)
}

func SynthesisFromAperiodicity(f0 []float64, spectrogram, aperiodicity [][]float64, targetF0, framePeriod float64, fs, length int) []float64 {
	FFTSize := C.size_t(C.GetFFTSizeForStar(C.int(fs)))
	numBands := GetNumberOfBands(fs)

	spectrogramUsedInC := Make2DCArrayAlternative(spectrogram)
	aperiodicityUsedInC := Make2DCArrayAlternative(aperiodicity)

	synthesized := make([]float64, length)
	C.SynthesisFromAperiodicity((*C.double)(&f0[0]),
		C.int(len(f0)),
		(**C.double)(&spectrogramUsedInC[0]),
		C.int(FFTSize),
		(**C.double)(&aperiodicityUsedInC[0]),
		C.int(numBands),
		C.double(targetF0),
		C.double(framePeriod),
		C.int(fs),
		C.int(len(synthesized)),
		(*C.double)(&synthesized[0]))

	return synthesized
}
<commit_msg>Fix comment<commit_after>// Package world provide a Go interface to WORLD - a high-quality speech analysis, modification and synthesis system.
package world

// Functions in this file ara simple ports to original cpp functions.
// Go-like interfaces will be found in go_interface.go

// #cgo pkg-config: world
// #include <world/dio.h>
// #include <world/platinum.h>
// #include <world/synthesis.h>
// #include <world/star.h>
// #include <world/tandem_ap.h>
// #include <world/synthesis_ap.h>
// #include <stdlib.h>
import "C"

import (
	"unsafe"
)

const (
	byteSizeOfFloat64 = 8
)

type DioOption struct {
	F0Floor          float64
	F0Ceil           float64
	ChannelsInOctave float64
	FramePeriod      float64 // [ms]
	Speed            int     // (1,2, ..., 12)
}

func NewDioOption() DioOption {
	opt := DioOption{
		F0Floor:          80.0,
		F0Ceil:           640.0,
		FramePeriod:      5,
		ChannelsInOctave: 4.0,
		Speed:            6,
	}
	return opt
}

func Dio(x []float64, fs int, option DioOption) ([]float64, []float64) {
	numFrames := GetSamplesForDIO(fs, len(x), option.FramePeriod)
	timeAxis := make([]float64, numFrames)
	f0 := make([]float64, numFrames)

	// Create C interface of DioOption
	var opt C.DioOption
	opt.frame_period = C.double(option.FramePeriod)
	opt.f0_floor = C.double(option.F0Floor)
	opt.f0_ceil = C.double(option.F0Ceil)
	opt.channels_in_octave = C.double(option.ChannelsInOctave)
	opt.speed = C.int(option.Speed)

	// Perform DIO
	C.Dio2((*C.double)(&x[0]),
		C.int(len(x)),
		C.int(fs),
		opt,
		(*C.double)(&timeAxis[0]),
		(*C.double)(&f0[0]))

	return timeAxis, f0
}

func GetSamplesForDIO(fs, x_length int, framePeriod float64) int {
	return int(C.GetSamplesForDIO(C.int(fs), C.int(x_length), C.double(framePeriod)))
}

func Star(x []float64, fs int, timeAxis, f0 []float64) [][]float64 {
	FFTSize := C.size_t(C.GetFFTSizeForStar(C.int(fs)))
	numFreqBins := FFTSize/2 + 1

	// Create workspace
	wspace := make([]*C.double, len(f0))
	for i := range wspace {
		wspace[i] = (*C.double)(C.malloc(byteSizeOfFloat64 * numFreqBins))
		defer C.free(unsafe.Pointer(wspace[i]))
	}

	// Perform star
	C.Star((*C.double)(&x[0]),
		C.int(len(x)),
		C.int(fs),
		(*C.double)(&timeAxis[0]),
		(*C.double)(&f0[0]),
		C.int(len(f0)),
		(**C.double)(&wspace[0]))

	// Copy to go slice
	spectrogram := make([][]float64, len(f0))
	for i := range spectrogram {
		spectrogram[i] = CArrayToGoSlice(wspace[i], C.int(numFreqBins))
	}

	return spectrogram
}

func GetFFTSizeForStar(fs int) int {
	return int(C.GetFFTSizeForStar(C.int(fs)))
}

func Platinum(x []float64, fs int, timeAxis, f0 []float64, spectrogram [][]float64) [][]float64 {
	FFTSize := C.size_t(C.GetFFTSizeForStar(C.int(fs)))
	numFreqBins := C.size_t(FFTSize + 1)

	spectrogramUsedInC := Make2DCArrayAlternative(spectrogram)
	residualSpectrogramUsedInC := make([]*C.double, len(spectrogram))
	for i := range residualSpectrogramUsedInC {
		residualSpectrogramUsedInC[i] = (*C.double)(C.malloc(byteSizeOfFloat64 * numFreqBins))
		defer C.free(unsafe.Pointer(residualSpectrogramUsedInC[i]))
	}

	C.Platinum((*C.double)(&x[0]),
		C.int(len(x)),
		C.int(fs),
		(*C.double)(&timeAxis[0]),
		(*C.double)(&f0[0]),
		C.int(len(f0)),
		(**C.double)(&spectrogramUsedInC[0]),
		C.int(FFTSize),
		(**C.double)(&residualSpectrogramUsedInC[0]))

	residualSpectrogram := make([][]float64, len(f0))
	for i := range residualSpectrogramUsedInC {
		residualSpectrogram[i] = CArrayToGoSlice(residualSpectrogramUsedInC[i], C.int(numFreqBins))
	}

	return residualSpectrogram
}

func Synthesis(f0 []float64, spectrogram, residualSpectrogram [][]float64, framePeriod float64, fs, length int) []float64 {
	FFTSize := C.size_t(C.GetFFTSizeForStar(C.int(fs)))

	spectrogramUsedInC := Make2DCArrayAlternative(spectrogram)
	residualSpectrogramUsedInC := Make2DCArrayAlternative(residualSpectrogram)

	synthesized := make([]float64, length)
	C.Synthesis((*C.double)(&f0[0]),
		C.int(len(f0)),
		(**C.double)(&spectrogramUsedInC[0]),
		(**C.double)(&residualSpectrogramUsedInC[0]),
		C.int(FFTSize),
		C.double(framePeriod),
		C.int(fs),
		C.int(len(synthesized)),
		(*C.double)(&synthesized[0]))

	return synthesized
}

func GetNumberOfBands(fs int) int {
	return int(C.GetNumberOfBands(C.int(fs)))
}

func AperiodicityRatio(x []float64, fs int, f0 []float64, framePeriod float64) ([][]float64, float64) {
	numBands := GetNumberOfBands(fs)

	// Create workspace
	wspace := make([]*C.double, len(f0))
	for i := range wspace {
		wspace[i] = (*C.double)(C.malloc(C.size_t(byteSizeOfFloat64 * numBands)))
		defer C.free(unsafe.Pointer(wspace[i]))
	}

	// Peform aperiodicity analysis
	targetF0 := C.AperiodicityRatio((*C.double)(&x[0]),
		C.int(len(x)),
		C.int(fs),
		(*C.double)(&f0[0]),
		C.int(len(f0)),
		C.double(framePeriod),
		(**C.double)(&wspace[0]))

	// Copy to go slice
	aperiodicity := make([][]float64, len(f0))
	for i := range aperiodicity {
		aperiodicity[i] = CArrayToGoSlice(wspace[i], C.int(numBands))
	}

	return aperiodicity, float64(targetF0)
}

func SynthesisFromAperiodicity(f0 []float64, spectrogram, aperiodicity [][]float64, targetF0, framePeriod float64, fs, length int) []float64 {
	FFTSize := C.size_t(C.GetFFTSizeForStar(C.int(fs)))
	numBands := GetNumberOfBands(fs)

	spectrogramUsedInC := Make2DCArrayAlternative(spectrogram)
	aperiodicityUsedInC := Make2DCArrayAlternative(aperiodicity)

	synthesized := make([]float64, length)
	C.SynthesisFromAperiodicity((*C.double)(&f0[0]),
		C.int(len(f0)),
		(**C.double)(&spectrogramUsedInC[0]),
		C.int(FFTSize),
		(**C.double)(&aperiodicityUsedInC[0]),
		C.int(numBands),
		C.double(targetF0),
		C.double(framePeriod),
		C.int(fs),
		C.int(len(synthesized)),
		(*C.double)(&synthesized[0]))

	return synthesized
}
<|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 low level functions for interacting with the Discord
// data websocket interface.

package discordgo

import (
	"bytes"
	"compress/zlib"
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"net/http"
	"reflect"
	"runtime"
	"time"

	"github.com/gorilla/websocket"
)

type handshakeProperties struct {
	OS              string `json:"$os"`
	Browser         string `json:"$browser"`
	Device          string `json:"$device"`
	Referer         string `json:"$referer"`
	ReferringDomain string `json:"$referring_domain"`
}

type handshakeData struct {
	Version        int                 `json:"v"`
	Token          string              `json:"token"`
	Properties     handshakeProperties `json:"properties"`
	LargeThreshold int                 `json:"large_threshold"`
	Compress       bool                `json:"compress"`
}

type handshakeOp struct {
	Op   int           `json:"op"`
	Data handshakeData `json:"d"`
}

// Open opens a websocket connection to Discord.
func (s *Session) Open() (err error) {
	s.Lock()
	defer func() {
		if err != nil {
			s.Unlock()
		}
	}()

	s.VoiceConnections = make(map[string]*VoiceConnection)

	if s.wsConn != nil {
		err = errors.New("Web socket already opened.")
		return
	}

	// Get the gateway to use for the Websocket connection
	g, err := s.Gateway()
	if err != nil {
		return
	}

	header := http.Header{}
	header.Add("accept-encoding", "zlib")

	// TODO: See if there's a use for the http response.
	// conn, response, err := websocket.DefaultDialer.Dial(session.Gateway, nil)
	s.wsConn, _, err = websocket.DefaultDialer.Dial(g, header)
	if err != nil {
		return
	}

	err = s.wsConn.WriteJSON(handshakeOp{2, handshakeData{3, s.Token, handshakeProperties{runtime.GOOS, "Discordgo v" + VERSION, "", "", ""}, 250, s.Compress}})
	if err != nil {
		return
	}

	// Create listening outside of listen, as it needs to happen inside the mutex
	// lock.
	s.listening = make(chan interface{})
	go s.listen(s.wsConn, s.listening)

	s.Unlock()

	s.initialize()
	s.handle(&Connect{})

	return
}

// Close closes a websocket and stops all listening/heartbeat goroutines.
// TODO: Add support for Voice WS/UDP connections
func (s *Session) Close() (err error) {
	s.Lock()

	s.DataReady = false

	if s.listening != nil {
		close(s.listening)
		s.listening = nil
	}

	if s.wsConn != nil {
		err = s.wsConn.Close()
		s.wsConn = nil
	}

	s.Unlock()

	s.handle(&Disconnect{})

	return
}

// listen polls the websocket connection for events, it will stop when
// the listening channel is closed, or an error occurs.
func (s *Session) listen(wsConn *websocket.Conn, listening <-chan interface{}) {
	for {
		messageType, message, err := wsConn.ReadMessage()
		if err != nil {
			// Detect if we have been closed manually. If a Close() has already
			// happened, the websocket we are listening on will be different to the
			// current session.
			s.RLock()
			sameConnection := s.wsConn == wsConn
			s.RUnlock()
			if sameConnection {
				// There has been an error reading, Close() the websocket so that
				// OnDisconnect is fired.
				err := s.Close()
				if err != nil {
					fmt.Println("error closing session connection: ", err)
				}

				// Attempt to reconnect, with expenonential backoff up to 10 minutes.
				if s.ShouldReconnectOnError {
					wait := time.Duration(1)
					for {
						if s.Open() == nil {
							return
						}
						<-time.After(wait * time.Second)
						wait *= 2
						if wait > 600 {
							wait = 600
						}
					}
				}
			}
			return
		}

		select {
		case <-listening:
			return
		default:
			go s.event(messageType, message)
		}
	}
}

type heartbeatOp struct {
	Op   int `json:"op"`
	Data int `json:"d"`
}

// heartbeat sends regular heartbeats to Discord so it knows the client
// is still connected.  If you do not send these heartbeats Discord will
// disconnect the websocket connection after a few seconds.
func (s *Session) heartbeat(wsConn *websocket.Conn, listening <-chan interface{}, i time.Duration) {

	if listening == nil || wsConn == nil {
		return
	}

	s.Lock()
	s.DataReady = true
	s.Unlock()

	var err error
	ticker := time.NewTicker(i * time.Millisecond)
	for {
		err = wsConn.WriteJSON(heartbeatOp{1, int(time.Now().Unix())})
		if err != nil {
			fmt.Println("Error sending heartbeat:", err)
			return
		}

		select {
		case <-ticker.C:
			// continue loop and send heartbeat
		case <-listening:
			return
		}
	}
}

type updateStatusGame struct {
	Name string `json:"name"`
}

type updateStatusData struct {
	IdleSince *int              `json:"idle_since"`
	Game      *updateStatusGame `json:"game"`
}

type updateStatusOp struct {
	Op   int              `json:"op"`
	Data updateStatusData `json:"d"`
}

// UpdateStatus is used to update the authenticated user's status.
// If idle>0 then set status to idle.  If game>0 then set game.
// if otherwise, set status to active, and no game.
func (s *Session) UpdateStatus(idle int, game string) (err error) {
	s.RLock()
	defer s.RUnlock()
	if s.wsConn == nil {
		return errors.New("No websocket connection exists.")
	}

	var usd updateStatusData
	if idle > 0 {
		usd.IdleSince = &idle
	}
	if game != "" {
		usd.Game = &updateStatusGame{game}
	}

	err = s.wsConn.WriteJSON(updateStatusOp{3, usd})

	return
}

// Front line handler for all Websocket Events.  Determines the
// event type and passes the message along to the next handler.

// event is the front line handler for all events.  This needs to be
// broken up into smaller functions to be more idiomatic Go.
// Events will be handled by any implemented handler in Session.
// All unhandled events will then be handled by OnEvent.
func (s *Session) event(messageType int, message []byte) {
	var err error
	var reader io.Reader

	reader = bytes.NewBuffer(message)

	if messageType == 2 {
		z, err1 := zlib.NewReader(reader)
		if err1 != nil {
			fmt.Println(err1)
			return
		}
		defer func() {
			err := z.Close()
			if err != nil {
				fmt.Println("error closing zlib:", err)
			}
		}()
		reader = z
	}

	var e *Event
	decoder := json.NewDecoder(reader)
	if err = decoder.Decode(&e); err != nil {
		fmt.Println(err)
		return
	}

	if s.Debug {
		printEvent(e)
	}

	i := eventToInterface[e.Type]
	if i != nil {
		// Create a new instance of the event type.
		i = reflect.New(reflect.TypeOf(i)).Interface()

		// Attempt to unmarshal our event.
		// If there is an error we should handle the event itself.
		if err = unmarshal(e.RawData, i); err != nil {
			fmt.Println("Unable to unmarshal event data.", err)
			// Ready events must fire, even if they are empty.
			if e.Type != "READY" {
				i = e
			}
		}
	} else {
		fmt.Println("Unknown event.")
		i = e
	}

	s.handle(i)

	return
}

// ------------------------------------------------------------------------------------------------
// Code related to voice connections that initiate over the data websocket
// ------------------------------------------------------------------------------------------------

// A VoiceServerUpdate stores the data received during the Voice Server Update
// data websocket event. This data is used during the initial Voice Channel
// join handshaking.
type VoiceServerUpdate struct {
	Token    string `json:"token"`
	GuildID  string `json:"guild_id"`
	Endpoint string `json:"endpoint"`
}

type voiceChannelJoinData struct {
	GuildID   *string `json:"guild_id"`
	ChannelID *string `json:"channel_id"`
	SelfMute  bool    `json:"self_mute"`
	SelfDeaf  bool    `json:"self_deaf"`
}

type voiceChannelJoinOp struct {
	Op   int                  `json:"op"`
	Data voiceChannelJoinData `json:"d"`
}

// ChannelVoiceJoin joins the session user to a voice channel. After calling
// this func please monitor the Session.Voice.Ready bool to determine when
// it is ready and able to send/receive audio, that should happen quickly.
//
//    gID     : Guild ID of the channel to join.
//    cID     : Channel ID of the channel to join.
//    mute    : If true, you will be set to muted upon joining.
//    deaf    : If true, you will be set to deafened upon joining.
func (s *Session) ChannelVoiceJoin(gID, cID string, mute, deaf bool) (voice *VoiceConnection, err error) {

	// If a voice connection already exists for this guild then
	// return that connection. If the channel differs, also change channels.
	var ok bool
	if voice, ok = s.VoiceConnections[gID]; ok && voice.GuildID != "" {
		//TODO: consider a better variable than GuildID in the above check
		// to verify if this connection is valid or not.

		if voice.ChannelID != cID {
			err = voice.ChangeChannel(cID)
		}
		return
	}

	// Create a new voice session
	// TODO review what all these things are for....
	voice = &VoiceConnection{
		Receive:     true,
		session:     s,
		connected:   make(chan bool),
		sessionRecv: make(chan string),
		GuildID:     gID,
		ChannelID:   cID,
	}

	// Store voice in VoiceConnections map for this GuildID
	s.VoiceConnections[gID] = voice

	// Send the request to Discord that we want to join the voice channel
	data := voiceChannelJoinOp{4, voiceChannelJoinData{&gID, &cID, mute, deaf}}
	err = s.wsConn.WriteJSON(data)
	if err != nil {
		delete(s.VoiceConnections, gID)
		return
	}

	// doesn't exactly work perfect yet.. TODO
	err = voice.WaitUntilConnected()
	if err != nil {
		voice.Close()
		delete(s.VoiceConnections, gID)
		return
	}

	return
}

// onVoiceStateUpdate handles Voice State Update events on the data
// websocket.  This comes immediately after the call to VoiceChannelJoin
// for the session user.
func (s *Session) onVoiceStateUpdate(se *Session, st *VoiceStateUpdate) {

	// If we don't have a connection for the channel, don't bother
	if st.ChannelID == "" {
		return
	}

	// Check if we have a voice connection to update
	voice, exists := s.VoiceConnections[st.GuildID]
	if !exists {
		return
	}

	// Need to have this happen at login and store it in the Session
	// TODO : This should be done upon connecting to Discord, or
	// be moved to a small helper function
	self, err := s.User("@me") // TODO: move to Login/New
	if err != nil {
		fmt.Println(err)
		return
	}

	// We only care about events that are about us
	if st.UserID != self.ID {
		return
	}

	// Store the SessionID for later use.
	voice.UserID = self.ID // TODO: Review
	voice.sessionID = st.SessionID

	// TODO: Consider this...
	// voice.sessionRecv <- st.SessionID
}

// onVoiceServerUpdate handles the Voice Server Update data websocket event.
// This event tells us the information needed to open a voice websocket
// connection and should happen after the VOICE_STATE event.
//
// This is also fired if the Guild's voice region changes while connected
// to a voice channel.  In that case, need to re-establish connection to
// the new region endpoint.
func (s *Session) onVoiceServerUpdate(se *Session, st *VoiceServerUpdate) {

	voice, exists := s.VoiceConnections[st.GuildID]

	// If no VoiceConnection exists, just skip this
	if !exists {
		fmt.Println("doesn't exist! Oh noooo bail out.. emergency..")
		return
	}

	// Store values for later use
	voice.token = st.Token
	voice.endpoint = st.Endpoint
	voice.GuildID = st.GuildID

	// If currently connected to voice ws/udp, then disconnect.
	// Has no effect if not connected.
	// voice.Close()

	// Wait for the sessionID from onVoiceStateUpdate
	// voice.sessionID = <-voice.sessionRecv
	// TODO review above
	// wouldn't this cause a huge problem, if it's just a guild server
	// update.. ?
	// I could add a timeout loop of some sort and also check if the
	// sessionID doesn't or does exist already...
	// something.. a bit smarter.

	// We now have enough information to open a voice websocket conenction
	// so, that's what the next call does.
	err := voice.Open()
	if err != nil {
		fmt.Println("onVoiceServerUpdate Voice.Open error: ", err)
		// TODO better logging
	}
}
<commit_msg>Cleanup<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 low level functions for interacting with the Discord
// data websocket interface.

package discordgo

import (
	"bytes"
	"compress/zlib"
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"net/http"
	"reflect"
	"runtime"
	"time"

	"github.com/gorilla/websocket"
)

type handshakeProperties struct {
	OS              string `json:"$os"`
	Browser         string `json:"$browser"`
	Device          string `json:"$device"`
	Referer         string `json:"$referer"`
	ReferringDomain string `json:"$referring_domain"`
}

type handshakeData struct {
	Version        int                 `json:"v"`
	Token          string              `json:"token"`
	Properties     handshakeProperties `json:"properties"`
	LargeThreshold int                 `json:"large_threshold"`
	Compress       bool                `json:"compress"`
}

type handshakeOp struct {
	Op   int           `json:"op"`
	Data handshakeData `json:"d"`
}

// Open opens a websocket connection to Discord.
func (s *Session) Open() (err error) {
	s.Lock()
	defer func() {
		if err != nil {
			s.Unlock()
		}
	}()

	s.VoiceConnections = make(map[string]*VoiceConnection)

	if s.wsConn != nil {
		err = errors.New("Web socket already opened.")
		return
	}

	// Get the gateway to use for the Websocket connection
	g, err := s.Gateway()
	if err != nil {
		return
	}

	header := http.Header{}
	header.Add("accept-encoding", "zlib")

	// TODO: See if there's a use for the http response.
	// conn, response, err := websocket.DefaultDialer.Dial(session.Gateway, nil)
	s.wsConn, _, err = websocket.DefaultDialer.Dial(g, header)
	if err != nil {
		return
	}

	err = s.wsConn.WriteJSON(handshakeOp{2, handshakeData{3, s.Token, handshakeProperties{runtime.GOOS, "Discordgo v" + VERSION, "", "", ""}, 250, s.Compress}})
	if err != nil {
		return
	}

	// Create listening outside of listen, as it needs to happen inside the mutex
	// lock.
	s.listening = make(chan interface{})
	go s.listen(s.wsConn, s.listening)

	s.Unlock()

	s.initialize()
	s.handle(&Connect{})

	return
}

// Close closes a websocket and stops all listening/heartbeat goroutines.
// TODO: Add support for Voice WS/UDP connections
func (s *Session) Close() (err error) {
	s.Lock()

	s.DataReady = false

	if s.listening != nil {
		close(s.listening)
		s.listening = nil
	}

	if s.wsConn != nil {
		err = s.wsConn.Close()
		s.wsConn = nil
	}

	s.Unlock()

	s.handle(&Disconnect{})

	return
}

// listen polls the websocket connection for events, it will stop when
// the listening channel is closed, or an error occurs.
func (s *Session) listen(wsConn *websocket.Conn, listening <-chan interface{}) {
	for {
		messageType, message, err := wsConn.ReadMessage()
		if err != nil {
			// Detect if we have been closed manually. If a Close() has already
			// happened, the websocket we are listening on will be different to the
			// current session.
			s.RLock()
			sameConnection := s.wsConn == wsConn
			s.RUnlock()
			if sameConnection {
				// There has been an error reading, Close() the websocket so that
				// OnDisconnect is fired.
				err := s.Close()
				if err != nil {
					fmt.Println("error closing session connection: ", err)
				}

				// Attempt to reconnect, with expenonential backoff up to 10 minutes.
				if s.ShouldReconnectOnError {
					wait := time.Duration(1)
					for {
						if s.Open() == nil {
							return
						}
						<-time.After(wait * time.Second)
						wait *= 2
						if wait > 600 {
							wait = 600
						}
					}
				}
			}
			return
		}

		select {
		case <-listening:
			return
		default:
			go s.event(messageType, message)
		}
	}
}

type heartbeatOp struct {
	Op   int `json:"op"`
	Data int `json:"d"`
}

// heartbeat sends regular heartbeats to Discord so it knows the client
// is still connected.  If you do not send these heartbeats Discord will
// disconnect the websocket connection after a few seconds.
func (s *Session) heartbeat(wsConn *websocket.Conn, listening <-chan interface{}, i time.Duration) {

	if listening == nil || wsConn == nil {
		return
	}

	s.Lock()
	s.DataReady = true
	s.Unlock()

	var err error
	ticker := time.NewTicker(i * time.Millisecond)
	for {
		err = wsConn.WriteJSON(heartbeatOp{1, int(time.Now().Unix())})
		if err != nil {
			fmt.Println("Error sending heartbeat:", err)
			return
		}

		select {
		case <-ticker.C:
			// continue loop and send heartbeat
		case <-listening:
			return
		}
	}
}

type updateStatusGame struct {
	Name string `json:"name"`
}

type updateStatusData struct {
	IdleSince *int              `json:"idle_since"`
	Game      *updateStatusGame `json:"game"`
}

type updateStatusOp struct {
	Op   int              `json:"op"`
	Data updateStatusData `json:"d"`
}

// UpdateStatus is used to update the authenticated user's status.
// If idle>0 then set status to idle.  If game>0 then set game.
// if otherwise, set status to active, and no game.
func (s *Session) UpdateStatus(idle int, game string) (err error) {
	s.RLock()
	defer s.RUnlock()
	if s.wsConn == nil {
		return errors.New("No websocket connection exists.")
	}

	var usd updateStatusData
	if idle > 0 {
		usd.IdleSince = &idle
	}
	if game != "" {
		usd.Game = &updateStatusGame{game}
	}

	err = s.wsConn.WriteJSON(updateStatusOp{3, usd})

	return
}

// Front line handler for all Websocket Events.  Determines the
// event type and passes the message along to the next handler.

// event is the front line handler for all events.  This needs to be
// broken up into smaller functions to be more idiomatic Go.
// Events will be handled by any implemented handler in Session.
// All unhandled events will then be handled by OnEvent.
func (s *Session) event(messageType int, message []byte) {
	var err error
	var reader io.Reader

	reader = bytes.NewBuffer(message)

	if messageType == 2 {
		z, err1 := zlib.NewReader(reader)
		if err1 != nil {
			fmt.Println(err1)
			return
		}
		defer func() {
			err := z.Close()
			if err != nil {
				fmt.Println("error closing zlib:", err)
			}
		}()
		reader = z
	}

	var e *Event
	decoder := json.NewDecoder(reader)
	if err = decoder.Decode(&e); err != nil {
		fmt.Println(err)
		return
	}

	if s.Debug {
		printEvent(e)
	}

	i := eventToInterface[e.Type]
	if i != nil {
		// Create a new instance of the event type.
		i = reflect.New(reflect.TypeOf(i)).Interface()

		// Attempt to unmarshal our event.
		// If there is an error we should handle the event itself.
		if err = unmarshal(e.RawData, i); err != nil {
			fmt.Println("Unable to unmarshal event data.", err)
			// Ready events must fire, even if they are empty.
			if e.Type != "READY" {
				i = e
			}
		}
	} else {
		fmt.Println("Unknown event.")
		i = e
	}

	s.handle(i)

	return
}

// ------------------------------------------------------------------------------------------------
// Code related to voice connections that initiate over the data websocket
// ------------------------------------------------------------------------------------------------

// A VoiceServerUpdate stores the data received during the Voice Server Update
// data websocket event. This data is used during the initial Voice Channel
// join handshaking.
type VoiceServerUpdate struct {
	Token    string `json:"token"`
	GuildID  string `json:"guild_id"`
	Endpoint string `json:"endpoint"`
}

type voiceChannelJoinData struct {
	GuildID   *string `json:"guild_id"`
	ChannelID *string `json:"channel_id"`
	SelfMute  bool    `json:"self_mute"`
	SelfDeaf  bool    `json:"self_deaf"`
}

type voiceChannelJoinOp struct {
	Op   int                  `json:"op"`
	Data voiceChannelJoinData `json:"d"`
}

// ChannelVoiceJoin joins the session user to a voice channel.
//
//    gID     : Guild ID of the channel to join.
//    cID     : Channel ID of the channel to join.
//    mute    : If true, you will be set to muted upon joining.
//    deaf    : If true, you will be set to deafened upon joining.
func (s *Session) ChannelVoiceJoin(gID, cID string, mute, deaf bool) (voice *VoiceConnection, err error) {

	// If a voice connection already exists for this guild then
	// return that connection. If the channel differs, also change channels.
	var ok bool
	if voice, ok = s.VoiceConnections[gID]; ok && voice.GuildID != "" {
		//TODO: consider a better variable than GuildID in the above check
		// to verify if this connection is valid or not.

		if voice.ChannelID != cID {
			err = voice.ChangeChannel(cID)
		}
		return
	}

	// Create a new voice session
	// TODO review what all these things are for....
	voice = &VoiceConnection{
		Receive:     true,
		session:     s,
		connected:   make(chan bool),
		sessionRecv: make(chan string),
		GuildID:     gID,
		ChannelID:   cID,
	}

	// Store voice in VoiceConnections map for this GuildID
	s.VoiceConnections[gID] = voice

	// Send the request to Discord that we want to join the voice channel
	data := voiceChannelJoinOp{4, voiceChannelJoinData{&gID, &cID, mute, deaf}}
	err = s.wsConn.WriteJSON(data)
	if err != nil {
		delete(s.VoiceConnections, gID)
		return
	}

	// doesn't exactly work perfect yet.. TODO
	err = voice.WaitUntilConnected()
	if err != nil {
		voice.Close()
		delete(s.VoiceConnections, gID)
		return
	}

	return
}

// onVoiceStateUpdate handles Voice State Update events on the data websocket.
func (s *Session) onVoiceStateUpdate(se *Session, st *VoiceStateUpdate) {

	// If we don't have a connection for the channel, don't bother
	if st.ChannelID == "" {
		return
	}

	// Check if we have a voice connection to update
	voice, exists := s.VoiceConnections[st.GuildID]
	if !exists {
		return
	}

	// Need to have this happen at login and store it in the Session
	// TODO : This should be done upon connecting to Discord, or
	// be moved to a small helper function
	self, err := s.User("@me") // TODO: move to Login/New
	if err != nil {
		fmt.Println(err)
		return
	}

	// We only care about events that are about us
	if st.UserID != self.ID {
		return
	}

	// Store the SessionID for later use.
	voice.UserID = self.ID // TODO: Review
	voice.sessionID = st.SessionID

	// TODO: Consider this...
	// voice.sessionRecv <- st.SessionID
}

// onVoiceServerUpdate handles the Voice Server Update data websocket event.
//
// This is also fired if the Guild's voice region changes while connected
// to a voice channel.  In that case, need to re-establish connection to
// the new region endpoint.
func (s *Session) onVoiceServerUpdate(se *Session, st *VoiceServerUpdate) {

	voice, exists := s.VoiceConnections[st.GuildID]

	// If no VoiceConnection exists, just skip this
	if !exists {
		return
	}

	// Store values for later use
	voice.token = st.Token
	voice.endpoint = st.Endpoint
	voice.GuildID = st.GuildID

	// If currently connected to voice ws/udp, then disconnect.
	// Has no effect if not connected.
	// voice.Close()

	// Wait for the sessionID from onVoiceStateUpdate
	// voice.sessionID = <-voice.sessionRecv
	// TODO review above
	// wouldn't this cause a huge problem, if it's just a guild server
	// update.. ?
	// I could add a timeout loop of some sort and also check if the
	// sessionID doesn't or does exist already...
	// something.. a bit smarter.

	// We now have enough information to open a voice websocket conenction
	// so, that's what the next call does.
	err := voice.Open()
	if err != nil {
		fmt.Println("onVoiceServerUpdate Voice.Open error: ", err)
		// TODO better logging
	}
}
<|endoftext|>


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

package common

import (
	"errors"
	"fmt"
	"os"
	"path/filepath"
	"strconv"
	"syscall"

	"github.com/appc/spec/schema"
	"github.com/appc/spec/schema/types"
	"github.com/coreos/rkt/common"
	"github.com/hashicorp/errwrap"
)

func MountSharedVolumes(root string, appName types.ACName, volumes []types.Volume, ra *schema.RuntimeApp) error {
	app := ra.App
	vols := make(map[types.ACName]types.Volume)
	for _, v := range volumes {
		vols[v.Name] = v
	}

	sharedVolPath := common.SharedVolumesPath(root)
	if err := os.MkdirAll(sharedVolPath, sharedVolPerm); err != nil {
		return errwrap.Wrap(errors.New("could not create shared volumes directory"), err)
	}
	if err := os.Chmod(sharedVolPath, sharedVolPerm); err != nil {
		return errwrap.Wrap(fmt.Errorf("could not change permissions of %q", sharedVolPath), err)
	}

	mounts := generateMounts(ra, vols)
	for _, m := range mounts {
		vol := vols[m.Volume]

		if vol.Kind == "empty" {
			p := filepath.Join(sharedVolPath, vol.Name.String())
			if err := os.MkdirAll(p, sharedVolPerm); err != nil {
				return errwrap.Wrap(fmt.Errorf("could not create shared volume %q", vol.Name), err)
			}
			if err := os.Chown(p, *vol.UID, *vol.GID); err != nil {
				return errwrap.Wrap(fmt.Errorf("could not change owner of %q", p), err)
			}
			mod, err := strconv.ParseUint(*vol.Mode, 8, 32)
			if err != nil {
				return errwrap.Wrap(fmt.Errorf("invalid mode %q for volume %q", *vol.Mode, vol.Name), err)
			}
			if err := os.Chmod(p, os.FileMode(mod)); err != nil {
				return errwrap.Wrap(fmt.Errorf("could not change permissions of %q", p), err)
			}
		}

		readOnly := IsMountReadOnly(vol, app.MountPoints)
		var source string
		switch vol.Kind {
		case "host":
			source = vol.Source
		case "empty":
			source = filepath.Join(common.SharedVolumesPath(root), vol.Name.String())
		default:
			return fmt.Errorf(`invalid volume kind %q. Must be one of "host" or "empty"`, vol.Kind)
		}
		appRootfs := common.AppRootfsPath(".", appName)
		mntPath, err := evaluateAppMountPath(appRootfs, m.Path)
		if err != nil {
			return errwrap.Wrap(fmt.Errorf("could not evaluate path %v", m.Path), err)
		}

		destination := filepath.Join(appRootfs, mntPath)
		// TODO: verify if rkt should do this, or it should be some outer responsibility
		// to ensure if such patch exists
		if err := ensureDestinationExists(source, destination); err != nil {
			return errwrap.Wrap(fmt.Errorf("could not create destination mount point: %v", destination), err)
		}

		if err := doBindMount(source, destination, readOnly); err != nil {
			return errwrap.Wrap(fmt.Errorf("could not bind mount path %v (s: %v, d: %v)", m.Path, source, destination), err)
		}
	}
	return nil
}

func doBindMount(source, destination string, readOnly bool) error {
	if err := syscall.Mount(source, destination, "bind", syscall.MS_BIND, ""); err != nil {
		return err
	}
	if readOnly {
		return syscall.Mount(source, destination, "bind", syscall.MS_REMOUNT|syscall.MS_RDONLY|syscall.MS_BIND, "")
	}
	return nil
}

func ensureDestinationExists(source, destination string) error {
	fileInfo, err := os.Stat(source)
	if err != nil {
		return errwrap.Wrap(fmt.Errorf("could not stat source location: %v", source), err)
	}

	targetPathParent, _ := filepath.Split(destination)
	if err := os.MkdirAll(targetPathParent, sharedVolPerm); err != nil {
		return errwrap.Wrap(fmt.Errorf("could not create parent directory: %v", targetPathParent), err)
	}

	if fileInfo.IsDir() {
		if err := os.Mkdir(destination, sharedVolPerm); !os.IsExist(err) {
			return err
		}
	} else {
		if file, err := os.OpenFile(destination, os.O_CREATE, sharedVolPerm); err != nil {
			return err
		} else {
			file.Close()
		}
	}
	return nil
}
<commit_msg>kvm: fix for mounting symlinks<commit_after>// Copyright 2015 The rkt Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package common

import (
	"errors"
	"fmt"
	"os"
	"path/filepath"
	"strconv"
	"strings"
	"syscall"

	"github.com/appc/spec/schema"
	"github.com/appc/spec/schema/types"
	"github.com/coreos/rkt/common"
	"github.com/hashicorp/errwrap"
)

func MountSharedVolumes(root string, appName types.ACName, volumes []types.Volume, ra *schema.RuntimeApp) error {
	app := ra.App
	vols := make(map[types.ACName]types.Volume)
	for _, v := range volumes {
		vols[v.Name] = v
	}

	sharedVolPath := common.SharedVolumesPath(root)
	if err := os.MkdirAll(sharedVolPath, sharedVolPerm); err != nil {
		return errwrap.Wrap(errors.New("could not create shared volumes directory"), err)
	}
	if err := os.Chmod(sharedVolPath, sharedVolPerm); err != nil {
		return errwrap.Wrap(fmt.Errorf("could not change permissions of %q", sharedVolPath), err)
	}

	mounts := generateMounts(ra, vols)
	for _, m := range mounts {
		vol := vols[m.Volume]

		if vol.Kind == "empty" {
			p := filepath.Join(sharedVolPath, vol.Name.String())
			if err := os.MkdirAll(p, sharedVolPerm); err != nil {
				return errwrap.Wrap(fmt.Errorf("could not create shared volume %q", vol.Name), err)
			}
			if err := os.Chown(p, *vol.UID, *vol.GID); err != nil {
				return errwrap.Wrap(fmt.Errorf("could not change owner of %q", p), err)
			}
			mod, err := strconv.ParseUint(*vol.Mode, 8, 32)
			if err != nil {
				return errwrap.Wrap(fmt.Errorf("invalid mode %q for volume %q", *vol.Mode, vol.Name), err)
			}
			if err := os.Chmod(p, os.FileMode(mod)); err != nil {
				return errwrap.Wrap(fmt.Errorf("could not change permissions of %q", p), err)
			}
		}

		readOnly := IsMountReadOnly(vol, app.MountPoints)
		var source string
		switch vol.Kind {
		case "host":
			source = vol.Source
		case "empty":
			source = filepath.Join(common.SharedVolumesPath(root), vol.Name.String())
		default:
			return fmt.Errorf(`invalid volume kind %q. Must be one of "host" or "empty"`, vol.Kind)
		}
		absAppRootfs, err := filepath.Abs(common.AppRootfsPath(".", appName))
		if err != nil {
			return fmt.Errorf(`could not evaluate absolute path for application rootfs in app: %v`, appName)
		}

		absDestination, err := filepath.Abs(filepath.Join(absAppRootfs, m.Path))
		if err != nil {
			return fmt.Errorf(`could not evaluate absolute path for application volume path %q in: %v`, m.Path, appName)
		}
		if !strings.HasPrefix(absDestination, absAppRootfs) {
			return fmt.Errorf("path escapes app's root: %v", absDestination)
		}
		// TODO: verify if rkt should ensure existance of destination there, or it should be some
		// outer responsibility to ensure if such path exists
		if cleanedSource, err := filepath.EvalSymlinks(source); err != nil {
			return errwrap.Wrap(fmt.Errorf("could not resolve symlink for source: %v", source), err)
		} else if err := ensureDestinationExists(cleanedSource, absDestination); err != nil {
			return errwrap.Wrap(fmt.Errorf("could not create destination mount point: %v", absDestination), err)
		} else if err := doBindMount(cleanedSource, absDestination, readOnly); err != nil {
			return errwrap.Wrap(fmt.Errorf("could not bind mount path %v (s: %v, d: %v)", m.Path, source, absDestination), err)
		}
	}
	return nil
}

func doBindMount(source, destination string, readOnly bool) error {
	if err := syscall.Mount(source, destination, "bind", syscall.MS_BIND, ""); err != nil {
		return err
	}
	if readOnly {
		return syscall.Mount(source, destination, "bind", syscall.MS_REMOUNT|syscall.MS_RDONLY|syscall.MS_BIND, "")
	}
	return nil
}

func ensureDestinationExists(source, destination string) error {
	fileInfo, err := os.Stat(source)
	if err != nil {
		return errwrap.Wrap(fmt.Errorf("could not stat source location: %v", source), err)
	}

	targetPathParent, _ := filepath.Split(destination)
	if err := os.MkdirAll(targetPathParent, sharedVolPerm); err != nil {
		return errwrap.Wrap(fmt.Errorf("could not create parent directory: %v", targetPathParent), err)
	}

	if fileInfo.IsDir() {
		if err := os.Mkdir(destination, sharedVolPerm); !os.IsExist(err) {
			return err
		}
	} else {
		if file, err := os.OpenFile(destination, os.O_CREATE, sharedVolPerm); err != nil {
			return err
		} else {
			file.Close()
		}
	}
	return nil
}
<|endoftext|>


<commit_before>package xfers

import (
	"bytes"
	"encoding/json"
	"errors"
	"io/ioutil"
	"net/http"
)

const XFERS_ENDPOINT_SANDBOX = "https://sandbox.xfers.io/api/v3"
const XFERS_ENDPOINT = "https://www.xfers.io/api/v3"
const XFERS_FEE = 0.89 // as of 29 Jan 2016

type XfersClient struct {
	Endpoint  string
	key       string
	isSandbox bool
	client    *http.Client
}

type XfersError struct {
	Error string
}

type XfersMsg struct {
	Msg string `json:"msg"`
}

type XfersAccount struct {
	AvailableBalance float64
	LedgerBalance    float64
	CreditCardRate   float64
	CreditCardFee    string
	BankTransferFee  float64
	FirstName        string
	LastName         string
	AddressLine1     string
	AddressLine2     string
	Nationality      string
	PostalCode       string
	IdentityNo       string
	Country          string
	Email            string
	IdBack           string
	IdDocument       string
	IdFront          string
	IdSelfie         string
	PhoneNo          string
}

type XfersChargeReqParam struct {
	Amount           float64     `json:"amount,string"` // ! total XfersCharge.Items.price must sum up to XferCharge.Amount
	Currency         string      `json:"currency"`      // !
	OrderId          string      `json:"order_id"`      // !
	Description      string      `json:"description"`   // !
	NotifyUrl        string      `json:"notify_url,omitempty"`
	ReturnUrl        string      `json:"return_url,omitempty"`
	CancelUrl        string      `json:"cancel_url,omitempty"`
	Refundable       bool        `json:"refundable,omitempty,string"` // Default true
	Redirect         bool        `json:"redirect,string"`             // Default true
	Items            []XfersItem `json:"items,omitempty"`             // JSON formatted array of items- description, name, price, quantity
	Shipping         float64     `json:"shipping,omitempty,string"`
	Tax              float64     `json:"tax,omitempty,string"`
	HrsToExpirations float64     `json:"hrs_to_expirations,omitempty,string"` // Default to 48 hours from now
	ReceiptEmail     string      `json:"receipt_email,omitempty"`
	UserApiToken     string      `json:"user_api_token,omitempty"`       // Optional
	UserPhoneNo      bool        `json:"user_phone_no,omitempty,string"` // Default false
	DebitOnly        bool        `json:"debit_only,omitempty,string"`    // Default false
	MetaData         string      `json:"meta_data,omitempty"`            // Key value pairs json
}

type XfersItem struct {
	Description string  `json:"description"`
	Name        string  `json:"name"`
	Price       float64 `json:"price"`
	Quantity    float64 `json:"quantity"`
	ItemId      string  `json:"item_id,omitempty"` // Optional
}

type XfersCharge struct {
	Id                  string  `json:"id"`
	CheckoutUrl         string  `json:"checkout_url"`
	NotifyUrl           string  `json:"notify_url"`
	ReturnUrl           string  `json:"return_url"`
	CancelUrl           string  `json:"cancel_url"`
	Object              string  `json:"object"` // 'charge'
	Amount              float64 `json:"amount,string"`
	Currency            string  `json:"currency"`
	Customer            string  `json:"customer"`
	OrderId             string  `json:"order_id"`
	Capture             bool    `json:"capture"`
	Refundable          bool    `json:"refundable"`
	Description         string  `json:"description"`
	StatementDescriptor string  `json:"statement_Descriptor"`
	ReceiptEmail        string  `json:"receipt_email"`
	Shipping            float64 `json:"shipping,string"`
	Tax                 float64 `json:"tax,string"`
	TotalAmount         float64 `json:"total_amount,string"`
	Status              string  `json:"status"`
}

type XfersVerifyParam struct {
	OrderId     string  `json:"order_id"`
	TotalAmount float64 `json:"total_amount,string"`
	Currency    string  `json:"currency"`
	Status      string  `json:"status"`
}

type XfersNotifyParam struct {
	TxnId       string  `form:"txn_id" json:"txn_id" binding:"required"`
	OrderId     string  `form:"order_id" json:"order_id" binding:"required"`
	TotalAmount float64 `form:"total_amount" json:"total_amount" binding:"required"`
	Currency    string  `form:"currency" json:"currency" binding:"required"`
	Status      string  `form:"status" json:"status" binding:"required"` // “cancelled” or “paid” or “expired”
}

func NewClient(key string, usesSandbox bool) (*XfersClient, error) {
	if key == "" {
		return nil, errors.New("Missing API Key")
	}
	xfersClient := XfersClient{}
	xfersClient.isSandbox = usesSandbox
	xfersClient.key = key
	xfersClient.client = new(http.Client)
	if xfersClient.isSandbox {
		xfersClient.Endpoint = XFERS_ENDPOINT_SANDBOX
	} else {
		xfersClient.Endpoint = XFERS_ENDPOINT
	}
	return &xfersClient, nil
}

func (xClient *XfersClient) PerformRequest(req *http.Request) ([]byte, error) {
	req.Header.Add("X-XFERS-USER-API-KEY", xClient.key)
	req.Header.Add("Content-Type", "application/json")

	resp, err := xClient.client.Do(req)
	defer resp.Body.Close()
	if err != nil {
		return nil, err
	}

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, err
	}

	if body == nil {
		return nil, errors.New("Missing body")
	}

	if string(body[0:1]) != "[" {
		errorResponse := XfersError{}
		err = json.Unmarshal(body, &errorResponse)
		if err != nil {
			return nil, err
		}
		if errorResponse.Error != "" {
			return nil, errors.New(errorResponse.Error)
		}
	}

	return body, err
}

func (xClient *XfersClient) GetAccountInfo() (XfersAccount, error) {
	xfersAccount := XfersAccount{}
	req, err := http.NewRequest("GET", xClient.Endpoint+"/user", nil)
	if err != nil {
		return xfersAccount, err
	}
	resp, err := xClient.PerformRequest(req)
	if err != nil {
		return xfersAccount, err
	}
	err = json.Unmarshal(resp, &xfersAccount)
	return xfersAccount, err
}

func (xClient *XfersClient) CreateCharge(param XfersChargeReqParam) (XfersCharge, error) {
	xfersCharge := XfersCharge{}
	param.Redirect = false // Force to JSON Response!
	paramJson, err := json.Marshal(param)
	if err != nil {
		return xfersCharge, err
	}
	req, err := http.NewRequest("POST", xClient.Endpoint+"/charges", bytes.NewReader(paramJson))
	if err != nil {
		return xfersCharge, err
	}
	resp, err := xClient.PerformRequest(req)
	if err != nil {
		return xfersCharge, err
	}
	err = json.Unmarshal(resp, &xfersCharge)
	return xfersCharge, err
}

func (xClient *XfersClient) RetrieveCharge(id string) (XfersCharge, error) {
	xfersCharge := XfersCharge{}
	req, err := http.NewRequest("GET", xClient.Endpoint+"/charges/"+id, nil)
	if err != nil {
		return xfersCharge, err
	}
	resp, err := xClient.PerformRequest(req)
	if err != nil {
		return xfersCharge, err
	}
	err = json.Unmarshal(resp, &xfersCharge)
	return xfersCharge, err
}

func (xClient *XfersClient) ListAllCharges() ([]XfersCharge, error) {
	xfersCharges := []XfersCharge{}
	// supported params
	// customer - only returns specified customer ID
	// ending_before - cursor for position, use order_id
	// starting_after
	// limit
	req, err := http.NewRequest("GET", xClient.Endpoint+"/charges", nil)
	if err != nil {
		return xfersCharges, err
	}
	resp, err := xClient.PerformRequest(req)
	if err != nil {
		return xfersCharges, err
	}
	err = json.Unmarshal(resp, &xfersCharges)
	return xfersCharges, err
}

func (xClient *XfersClient) VerifyCharge(id string, param XfersVerifyParam) (XfersMsg, error) {
	xfersMsg := XfersMsg{}
	paramJson, err := json.Marshal(param)
	if err != nil {
		return xfersMsg, err
	}
	req, err := http.NewRequest("POST", xClient.Endpoint+"/charges/"+id+"/validate", bytes.NewReader(paramJson))
	if err != nil {
		return xfersMsg, err
	}
	resp, err := xClient.PerformRequest(req)
	if err != nil {
		return xfersMsg, err
	}
	err = json.Unmarshal(resp, &xfersMsg)
	return xfersMsg, err
}
<commit_msg>Add helper function for initializing the XfersVerifyParam from the XfersNotifyParam<commit_after>package xfers

import (
	"bytes"
	"encoding/json"
	"errors"
	"io/ioutil"
	"net/http"
)

const XFERS_ENDPOINT_SANDBOX = "https://sandbox.xfers.io/api/v3"
const XFERS_ENDPOINT = "https://www.xfers.io/api/v3"
const XFERS_FEE = 0.89 // as of 29 Jan 2016

type XfersClient struct {
	Endpoint  string
	key       string
	isSandbox bool
	client    *http.Client
}

type XfersError struct {
	Error string
}

type XfersMsg struct {
	Msg string `json:"msg"`
}

type XfersAccount struct {
	AvailableBalance float64
	LedgerBalance    float64
	CreditCardRate   float64
	CreditCardFee    string
	BankTransferFee  float64
	FirstName        string
	LastName         string
	AddressLine1     string
	AddressLine2     string
	Nationality      string
	PostalCode       string
	IdentityNo       string
	Country          string
	Email            string
	IdBack           string
	IdDocument       string
	IdFront          string
	IdSelfie         string
	PhoneNo          string
}

type XfersChargeReqParam struct {
	Amount           float64     `json:"amount,string"` // ! total XfersCharge.Items.price must sum up to XferCharge.Amount
	Currency         string      `json:"currency"`      // !
	OrderId          string      `json:"order_id"`      // !
	Description      string      `json:"description"`   // !
	NotifyUrl        string      `json:"notify_url,omitempty"`
	ReturnUrl        string      `json:"return_url,omitempty"`
	CancelUrl        string      `json:"cancel_url,omitempty"`
	Refundable       bool        `json:"refundable,omitempty,string"` // Default true
	Redirect         bool        `json:"redirect,string"`             // Default true
	Items            []XfersItem `json:"items,omitempty"`             // JSON formatted array of items- description, name, price, quantity
	Shipping         float64     `json:"shipping,omitempty,string"`
	Tax              float64     `json:"tax,omitempty,string"`
	HrsToExpirations float64     `json:"hrs_to_expirations,omitempty,string"` // Default to 48 hours from now
	ReceiptEmail     string      `json:"receipt_email,omitempty"`
	UserApiToken     string      `json:"user_api_token,omitempty"`       // Optional
	UserPhoneNo      bool        `json:"user_phone_no,omitempty,string"` // Default false
	DebitOnly        bool        `json:"debit_only,omitempty,string"`    // Default false
	MetaData         string      `json:"meta_data,omitempty"`            // Key value pairs json
}

type XfersItem struct {
	Description string  `json:"description"`
	Name        string  `json:"name"`
	Price       float64 `json:"price"`
	Quantity    float64 `json:"quantity"`
	ItemId      string  `json:"item_id,omitempty"` // Optional
}

type XfersCharge struct {
	Id                  string  `json:"id"`
	CheckoutUrl         string  `json:"checkout_url"`
	NotifyUrl           string  `json:"notify_url"`
	ReturnUrl           string  `json:"return_url"`
	CancelUrl           string  `json:"cancel_url"`
	Object              string  `json:"object"` // 'charge'
	Amount              float64 `json:"amount,string"`
	Currency            string  `json:"currency"`
	Customer            string  `json:"customer"`
	OrderId             string  `json:"order_id"`
	Capture             bool    `json:"capture"`
	Refundable          bool    `json:"refundable"`
	Description         string  `json:"description"`
	StatementDescriptor string  `json:"statement_Descriptor"`
	ReceiptEmail        string  `json:"receipt_email"`
	Shipping            float64 `json:"shipping,string"`
	Tax                 float64 `json:"tax,string"`
	TotalAmount         float64 `json:"total_amount,string"`
	Status              string  `json:"status"`
}

type XfersVerifyParam struct {
	OrderId     string  `json:"order_id"`
	TotalAmount float64 `json:"total_amount,string"`
	Currency    string  `json:"currency"`
	Status      string  `json:"status"`
}

func (x *XfersVerifyParam) Init(param XfersNotifyParam) {
	x.OrderId = param.OrderId
	x.TotalAmount = param.TotalAmount
	x.Currency = param.Currency
	x.Status = param.Status
}

type XfersNotifyParam struct {
	TxnId       string  `form:"txn_id" json:"txn_id" binding:"required"`
	OrderId     string  `form:"order_id" json:"order_id" binding:"required"`
	TotalAmount float64 `form:"total_amount" json:"total_amount" binding:"required"`
	Currency    string  `form:"currency" json:"currency" binding:"required"`
	Status      string  `form:"status" json:"status" binding:"required"` // “cancelled” or “paid” or “expired”
}

func NewClient(key string, usesSandbox bool) (*XfersClient, error) {
	if key == "" {
		return nil, errors.New("Missing API Key")
	}
	xfersClient := XfersClient{}
	xfersClient.isSandbox = usesSandbox
	xfersClient.key = key
	xfersClient.client = new(http.Client)
	if xfersClient.isSandbox {
		xfersClient.Endpoint = XFERS_ENDPOINT_SANDBOX
	} else {
		xfersClient.Endpoint = XFERS_ENDPOINT
	}
	return &xfersClient, nil
}

func (xClient *XfersClient) PerformRequest(req *http.Request) ([]byte, error) {
	req.Header.Add("X-XFERS-USER-API-KEY", xClient.key)
	req.Header.Add("Content-Type", "application/json")

	resp, err := xClient.client.Do(req)
	defer resp.Body.Close()
	if err != nil {
		return nil, err
	}

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, err
	}

	if body == nil {
		return nil, errors.New("Missing body")
	}

	if string(body[0:1]) != "[" {
		errorResponse := XfersError{}
		err = json.Unmarshal(body, &errorResponse)
		if err != nil {
			return nil, err
		}
		if errorResponse.Error != "" {
			return nil, errors.New(errorResponse.Error)
		}
	}

	return body, err
}

func (xClient *XfersClient) GetAccountInfo() (XfersAccount, error) {
	xfersAccount := XfersAccount{}
	req, err := http.NewRequest("GET", xClient.Endpoint+"/user", nil)
	if err != nil {
		return xfersAccount, err
	}
	resp, err := xClient.PerformRequest(req)
	if err != nil {
		return xfersAccount, err
	}
	err = json.Unmarshal(resp, &xfersAccount)
	return xfersAccount, err
}

func (xClient *XfersClient) CreateCharge(param XfersChargeReqParam) (XfersCharge, error) {
	xfersCharge := XfersCharge{}
	param.Redirect = false // Force to JSON Response!
	paramJson, err := json.Marshal(param)
	if err != nil {
		return xfersCharge, err
	}
	req, err := http.NewRequest("POST", xClient.Endpoint+"/charges", bytes.NewReader(paramJson))
	if err != nil {
		return xfersCharge, err
	}
	resp, err := xClient.PerformRequest(req)
	if err != nil {
		return xfersCharge, err
	}
	err = json.Unmarshal(resp, &xfersCharge)
	return xfersCharge, err
}

func (xClient *XfersClient) RetrieveCharge(id string) (XfersCharge, error) {
	xfersCharge := XfersCharge{}
	req, err := http.NewRequest("GET", xClient.Endpoint+"/charges/"+id, nil)
	if err != nil {
		return xfersCharge, err
	}
	resp, err := xClient.PerformRequest(req)
	if err != nil {
		return xfersCharge, err
	}
	err = json.Unmarshal(resp, &xfersCharge)
	return xfersCharge, err
}

func (xClient *XfersClient) ListAllCharges() ([]XfersCharge, error) {
	xfersCharges := []XfersCharge{}
	// supported params
	// customer - only returns specified customer ID
	// ending_before - cursor for position, use order_id
	// starting_after
	// limit
	req, err := http.NewRequest("GET", xClient.Endpoint+"/charges", nil)
	if err != nil {
		return xfersCharges, err
	}
	resp, err := xClient.PerformRequest(req)
	if err != nil {
		return xfersCharges, err
	}
	err = json.Unmarshal(resp, &xfersCharges)
	return xfersCharges, err
}

func (xClient *XfersClient) VerifyCharge(id string, param XfersVerifyParam) (XfersMsg, error) {
	xfersMsg := XfersMsg{}
	paramJson, err := json.Marshal(param)
	if err != nil {
		return xfersMsg, err
	}
	req, err := http.NewRequest("POST", xClient.Endpoint+"/charges/"+id+"/validate", bytes.NewReader(paramJson))
	if err != nil {
		return xfersMsg, err
	}
	resp, err := xClient.PerformRequest(req)
	if err != nil {
		return xfersMsg, err
	}
	err = json.Unmarshal(resp, &xfersMsg)
	return xfersMsg, err
}
<|endoftext|>


<commit_before>package byteio

// ReadUintX reads an unsinged integer that was encoded using a variable number
// of bytes
func (e *StickyBigEndianReader) ReadUintX() uint64 {
	c, _ := e.ReadByte()
	val := uint64(c) & 0x7f
	n := 1
	for ; c&0x80 != 0 && n < 9; n++ {
		c, _ = e.ReadByte()
		val++
		if n == 8 {
			val = (val << 8) | uint64(c)
		} else {
			val = (val << 7) | uint64(c&0x7f)
		}
	}
	return val
}

// ReadIntX reads an integer that was encoded using a variable number of bytes
func (e *StickyBigEndianReader) ReadIntX() int64 {
	return unzigzag(e.ReadUintX())
}
<commit_msg>moved loop init to loop line<commit_after>package byteio

// ReadUintX reads an unsinged integer that was encoded using a variable number
// of bytes
func (e *StickyBigEndianReader) ReadUintX() uint64 {
	c, _ := e.ReadByte()
	val := uint64(c) & 0x7f
	for n := 1; c&0x80 != 0 && n < 9; n++ {
		c, _ = e.ReadByte()
		val++
		if n == 8 {
			val = (val << 8) | uint64(c)
		} else {
			val = (val << 7) | uint64(c&0x7f)
		}
	}
	return val
}

// ReadIntX reads an integer that was encoded using a variable number of bytes
func (e *StickyBigEndianReader) ReadIntX() int64 {
	return unzigzag(e.ReadUintX())
}
<|endoftext|>