<commit_before>package vm

import (
	"testing"
)

func TestMethodCallWithoutSelf(t *testing.T) {
	tests := []struct {
		input    string
		expected int
	}{
		{
			`
			class Foo
			  def set_x(x)
			    @x = x
			  end

			  def foo
			    set_x(10)
			    a = 10
			    @x + a
			  end
			end

			f = Foo.new
			f.foo
			`,
			20,
		},
		{
			`
			class Foo
			  def bar=(x)
			    @bar = x
			  end

			  def bar
			    @bar
			  end
			end

			f = Foo.new
			f.bar = 10
			f.bar
			`,
			10,
		},
		{
			`
			class Foo
			  def set_x(x)
			    @x = x
			  end

			  def foo
			    set_x(10 + 10 * 100)
			    a = 10
			    @x + a
			  end
			end

			f = Foo.new
			f.foo
			`,
			1020,
		},
		{
			`class Foo
				def bar
					10
				end

				def foo
					bar = 100
					10 + bar
				end
			end

			f = Foo.new
			f.foo
			`,
			110,
		},
		{
			`class Foo
				def bar
					10
				end

				def foo
					a = 10
					bar + a
				end
			end

			Foo.new.foo
			`,
			20,
		},
		{
			`class Foo
				def self.bar
					10
				end

				def self.foo
					a = 10
					bar + a
				end
			end

			Foo.foo
			`,
			20,
		},
		{
			`class Foo
				def bar
					100
				end

				def self.bar
					10
				end

				def foo
					a = 10
					bar + a
				end
			end

			Foo.new.foo
			`,
			110,
		},
	}

	for _, tt := range tests {
		evaluated := testEval(t, tt.input)

		if isError(evaluated) {
			t.Fatalf("got Error: %s", evaluated.(*Error).Message)
		}

		testIntegerObject(t, evaluated, tt.expected)
	}
}

func TestClassMethodEvaluation(t *testing.T) {
	tests := []struct {
		input    string
		expected interface{}
	}{
		{
			`
			class Bar
				def self.foo
					10
				end
			end
			Bar.foo;
			`,
			10,
		},
		{
			`
			class Bar
				def self.foo
					10
				end
			end
			class Foo < Bar; end
			class FooBar < Foo; end
			FooBar.foo
			`,
			10,
		},
		{
			`
			class Foo
				def self.foo
					10
				end
			end

			class Bar < Foo; end
			Bar.foo
			`,
			10,
		},
		{
			`
			class Foo
				def self.foo
					10
				end
			end

			class Bar < Foo
				def self.foo
					100
				end
			end
			Bar.foo
			`,
			100,
		},
		{
			`
			class Bar
				def self.foo
					bar
				end

				def self.bar
					100
				end

				def bar
					1000
				end
			end
			Bar.foo
			`,
			100,
		},
		{
			`
			# Test class method call inside class method.
			class JobPosition
				def initialize(name)
					@name = name
				end

				def self.engineer
					new("Engineer")
				end

				def name
					@name
				end
			end
			job = JobPosition.engineer
			job.name
			`,
			"Engineer",
		},
		{
			`
			class Foo; end
			Foo.new.class.name
			`,
			"Foo",
		},
	}

	for _, tt := range tests {
		evaluated := testEval(t, tt.input)

		if isError(evaluated) {
			t.Fatalf("got Error: %s", evaluated.(*Error).Message)
		}

		switch expected := tt.expected.(type) {
		case int:
			testIntegerObject(t, evaluated, expected)
		case string:
			testStringObject(t, evaluated, expected)
		}
	}
}

func TestSelfExpressionEvaluation(t *testing.T) {
	tests := []struct {
		input    string
		expected string
	}{
		{`self.class.name`, "Object"},
		{
			`
			class Bar
				def whoami
					"Instance of " + self.class.name
				end
			end

			Bar.new.whoami
		`, "Instance of Bar"},
		{
			`
			class Foo
				Self = self

				def get_self
					Self
				end
			end

			Foo.new.get_self.name
			`,
			"Foo"},
		{
			`
			class Foo
				def class
					Foo
				end
			end

			Foo.new.class.name
			`,
			"Foo"},
		{
			`
			class Foo
				def class_name
					self.class.name
				end
			end

			Foo.new.class_name
			`,
			"Foo"},
	}

	for _, tt := range tests {
		evaluated := testEval(t, tt.input)

		if isError(evaluated) {
			t.Fatalf("got Error: %s", evaluated.(*Error).Message)
		}

		testStringObject(t, evaluated, tt.expected)
	}
}

func TestEvalInstanceVariable(t *testing.T) {
	tests := []struct {
		input    string
		expected interface{}
	}{
		{`
		class Foo
			def set(x)
				@x = x;
			end

			def get
				@x
			end

			def double_get
				self.get() * 2;
			end
		end

		class Bar
			def set(x)
				@x = x;
			end

			def get
				@x
			end
		end

		f1 = Foo.new
		f1.set(10)

		f2 = Foo.new
		f2.set(20)

		b = Bar.new
		b.set(10)

		f2.double_get() + f1.get() + b.get()
	`, 60},
		{`
		class Foo
		  attr_reader("bar")
		end

		Foo.new.bar
		`, nil},
		{`
		class Foo
		  def bar
		    @x
		  end
		end

		Foo.new.bar
		`, nil},
	}

	for _, tt := range tests {
		evaluated := testEval(t, tt.input)

		if isError(evaluated) {
			t.Fatalf("got Error: %s", evaluated.(*Error).Message)
		}

		checkExpected(t, evaluated, tt.expected)
	}
}

func TestEvalInstanceMethodCall(t *testing.T) {
	input := `

		class Bar
			def set(x)
				@x = x
			end
		end

		class Foo < Bar
			def add(x, y)
				x + y
			end
		end

		class FooBar < Foo
			def get
				@x
			end
		end

		fb = FooBar.new
		fb.set(100)
		fb.add(10, fb.get)
	`

	evaluated := testEval(t, input)

	if isError(evaluated) {
		t.Fatalf("got Error: %s", evaluated.(*Error).Message)
	}

	result, ok := evaluated.(*IntegerObject)

	if !ok {
		t.Errorf("expect result to be an integer. got=%T", evaluated)
	}

	if result.Value != 110 {
		t.Errorf("expect result to be 110. got=%d", result.Value)
	}
}

func TestEvalMethodInheritance(t *testing.T) {
	input := `
		class Foo
			def add(x, y)
				x + y
			end
		end
		Foo.new.add(10, 11)
	`

	evaluated := testEval(t, input)

	if isError(evaluated) {
		t.Fatalf("got Error: %s", evaluated.(*Error).Message)
	}

	result, ok := evaluated.(*IntegerObject)

	if !ok {
		t.Errorf("expect result to be an integer. got=%T", evaluated)
	}

	if result.Value != 21 {
		t.Errorf("expect result to be 21. got=%d", result.Value)
	}
}

func TestEvalClassInheritance(t *testing.T) {
	input := `
		class Bar
		end

		class Foo < Bar
		  def self.add
		    10
		  end
		end

		Foo.superclass.name
	`

	evaluated := testEval(t, input)

	testStringObject(t, evaluated, "Bar")
}

func TestEvalIfExpression(t *testing.T) {
	tests := []struct {
		input    string
		expected interface{}
	}{
		{
			`
			if 10 > 5
				100
			else
				-10
			end
			`,
			100,
		},
		{
			`
			if 5 != 5
				false
			else
				true
			end
			`,
			true,
		},
		{"if true; 10 end", 10},
		{"if false; 10 end", nil},
		{"if 1; 10; end", 10},
		{"if 1 < 2; 10 end", 10},
		{"if 1 > 2; 10 end", nil},
		{"if 1 > 2; 10 else 20 end", 20},
		{"if 1 < 2; 10 else 20 end", 10},
		{"if nil; 10 else 20 end", 20},
	}

	for _, tt := range tests {
		evaluated := testEval(t, tt.input)

		switch tt.expected.(type) {
		case int64:
			testIntegerObject(t, evaluated, tt.expected.(int))
		case bool:
			testBooleanObject(t, evaluated, tt.expected.(bool))
		case nil:
			testNullObject(t, evaluated)
		}

	}
}

func TestEvalPostfix(t *testing.T) {
	tests := []struct {
		input    string
		expected int
	}{
		{"1++", 2},
		{"10--", 9},
		{"0--", -1},
		{"-5++", -4},
		{`
		a = 10
		a ++
		`, 11},
		{`
		a = 10
		a --
		`, 9},
		{`
		(1 + 2 * 3)++
		`, 8},
	}

	for _, tt := range tests {
		evaluated := testEval(t, tt.input)
		testIntegerObject(t, evaluated, tt.expected)
	}
}

func TestEvalBangPrefixExpression(t *testing.T) {
	tests := []struct {
		input    string
		expected bool
	}{
		{"!5", false},
		{"!true", false},
		{"!false", true},
		{"!!true", true},
		{"!!false", false},
		{"!!5", true},
	}

	for _, tt := range tests {
		evaluated := testEval(t, tt.input)
		testBooleanObject(t, evaluated, tt.expected)
	}
}

func TestEvalMinusPrefixExpression(t *testing.T) {
	tests := []struct {
		input    string
		expected int
	}{
		{"-5", -5},
		{"-10", -10},
		{"-(-10)", 10},
		{"-(-5)", 5},
	}

	for _, tt := range tests {
		evaluated := testEval(t, tt.input)
		testIntegerObject(t, evaluated, tt.expected)
	}
}

func TestMethodCallWithBlockArgument(t *testing.T) {
	tests := []struct {
		input    string
		expected int
	}{
		{`
				class Foo
				  def bar
				    yield(1, 3, 5)
				  end
				end

				Foo.new.bar do |first, second, third|
				  first + second * third
				end

				`, 16},
		{`
				class Foo
				  def bar
				    yield
				  end
				end

				Foo.new.bar do
				  3
				end

				`, 3},
		{`
				class Bar
				  def foo
				    yield(10)
				  end
				end

				class Foo
				  def bar
				    yield
				  end
				end

				Bar.new.foo do |num|
				  Foo.new.bar do
				    3 * num
				  end
				end

				`, 30},
		{`
				class Foo
				  def bar
				    0
				  end
				end

				Foo.new.bar do
				  3
				end

				`, 0},
		{`
				class Foo
				  def bar
				    yield
				  end
				end

				i = 10
				Foo.new.bar do
				  i = 3 + i
				end
				i

				`, 13},
		{`
		class Car
		  def initialize
		    yield(self)
		  end

		  def doors=(ds)
		    @doors = ds
		  end

		  def doors
		    @doors
		  end
		end

		car = Car.new do |c|
		  c.doors = 4
		end

		car.doors
				`,
			4},
		{`
		class Foo
		  def bar(x)
		    yield(x)
		  end
		end

		f = Foo.new
		x = 100
		y = 10

		f.bar(10) do |x|
                  y = x + y
		end

		y
		`, 20},
	}

	for _, tt := range tests {
		evaluated := testEval(t, tt.input)
		testIntegerObject(t, evaluated, tt.expected)
	}
}

func TestMethodCallWithNestedBlock(t *testing.T) {
	tests := []struct {
		input    string
		expected int
	}{
		{`
		class Foo
		  def bar
		    yield
		  end
		end

		a = 100
		i = 10
		b = 1000

		f = Foo.new

		f.bar do
		  i = 3 * a
		  f.bar do
		    i = 3 + i
		  end
		end
		i

		`, 303},
		{`
		class Foo
		  def bar
		    yield
		  end
		end

		i = 10
		a = 100
		b = 1000

		f = Foo.new

		f.bar do
		  a = 20
		  f.bar do
		    b = (3 + i) * a
		  end
		end
		b

		`, 260},
	}

	for _, tt := range tests {
		evaluated := testEval(t, tt.input)
		testIntegerObject(t, evaluated, tt.expected)
	}
}
<commit_msg>Add tests for next statement evaluation.<commit_after>package vm

import (
	"testing"
)

func TestNextStatement(t *testing.T) {
	tests := []struct {
		input    string
		expected interface{}
	}{
		{`
		x = 0
		y = 0

		while x < 10 do
		  x = x + 1
		  if x == 5
		    next
		  end
		  y = y + 1
		end

		x + y
		`, 19},
		{`
		x = 0
		y = 0
		i = 0

		while x < 10 do
		  x = x + 1
		  while y < 5 do
		    y = y + 1

		    if y == 3
		      next
		    end

		    i = i + x * y
		  end
		end

		i
		`, 12},
	}

	for _, tt := range tests {
		evaluated := testEval(t, tt.input)
		checkExpected(t, evaluated, tt.expected)
	}
}

func TestMethodCallWithoutSelf(t *testing.T) {
	tests := []struct {
		input    string
		expected int
	}{
		{
			`
			class Foo
			  def set_x(x)
			    @x = x
			  end

			  def foo
			    set_x(10)
			    a = 10
			    @x + a
			  end
			end

			f = Foo.new
			f.foo
			`,
			20,
		},
		{
			`
			class Foo
			  def bar=(x)
			    @bar = x
			  end

			  def bar
			    @bar
			  end
			end

			f = Foo.new
			f.bar = 10
			f.bar
			`,
			10,
		},
		{
			`
			class Foo
			  def set_x(x)
			    @x = x
			  end

			  def foo
			    set_x(10 + 10 * 100)
			    a = 10
			    @x + a
			  end
			end

			f = Foo.new
			f.foo
			`,
			1020,
		},
		{
			`class Foo
				def bar
					10
				end

				def foo
					bar = 100
					10 + bar
				end
			end

			f = Foo.new
			f.foo
			`,
			110,
		},
		{
			`class Foo
				def bar
					10
				end

				def foo
					a = 10
					bar + a
				end
			end

			Foo.new.foo
			`,
			20,
		},
		{
			`class Foo
				def self.bar
					10
				end

				def self.foo
					a = 10
					bar + a
				end
			end

			Foo.foo
			`,
			20,
		},
		{
			`class Foo
				def bar
					100
				end

				def self.bar
					10
				end

				def foo
					a = 10
					bar + a
				end
			end

			Foo.new.foo
			`,
			110,
		},
	}

	for _, tt := range tests {
		evaluated := testEval(t, tt.input)

		if isError(evaluated) {
			t.Fatalf("got Error: %s", evaluated.(*Error).Message)
		}

		testIntegerObject(t, evaluated, tt.expected)
	}
}

func TestClassMethodEvaluation(t *testing.T) {
	tests := []struct {
		input    string
		expected interface{}
	}{
		{
			`
			class Bar
				def self.foo
					10
				end
			end
			Bar.foo;
			`,
			10,
		},
		{
			`
			class Bar
				def self.foo
					10
				end
			end
			class Foo < Bar; end
			class FooBar < Foo; end
			FooBar.foo
			`,
			10,
		},
		{
			`
			class Foo
				def self.foo
					10
				end
			end

			class Bar < Foo; end
			Bar.foo
			`,
			10,
		},
		{
			`
			class Foo
				def self.foo
					10
				end
			end

			class Bar < Foo
				def self.foo
					100
				end
			end
			Bar.foo
			`,
			100,
		},
		{
			`
			class Bar
				def self.foo
					bar
				end

				def self.bar
					100
				end

				def bar
					1000
				end
			end
			Bar.foo
			`,
			100,
		},
		{
			`
			# Test class method call inside class method.
			class JobPosition
				def initialize(name)
					@name = name
				end

				def self.engineer
					new("Engineer")
				end

				def name
					@name
				end
			end
			job = JobPosition.engineer
			job.name
			`,
			"Engineer",
		},
		{
			`
			class Foo; end
			Foo.new.class.name
			`,
			"Foo",
		},
	}

	for _, tt := range tests {
		evaluated := testEval(t, tt.input)

		if isError(evaluated) {
			t.Fatalf("got Error: %s", evaluated.(*Error).Message)
		}

		switch expected := tt.expected.(type) {
		case int:
			testIntegerObject(t, evaluated, expected)
		case string:
			testStringObject(t, evaluated, expected)
		}
	}
}

func TestSelfExpressionEvaluation(t *testing.T) {
	tests := []struct {
		input    string
		expected string
	}{
		{`self.class.name`, "Object"},
		{
			`
			class Bar
				def whoami
					"Instance of " + self.class.name
				end
			end

			Bar.new.whoami
		`, "Instance of Bar"},
		{
			`
			class Foo
				Self = self

				def get_self
					Self
				end
			end

			Foo.new.get_self.name
			`,
			"Foo"},
		{
			`
			class Foo
				def class
					Foo
				end
			end

			Foo.new.class.name
			`,
			"Foo"},
		{
			`
			class Foo
				def class_name
					self.class.name
				end
			end

			Foo.new.class_name
			`,
			"Foo"},
	}

	for _, tt := range tests {
		evaluated := testEval(t, tt.input)

		if isError(evaluated) {
			t.Fatalf("got Error: %s", evaluated.(*Error).Message)
		}

		testStringObject(t, evaluated, tt.expected)
	}
}

func TestEvalInstanceVariable(t *testing.T) {
	tests := []struct {
		input    string
		expected interface{}
	}{
		{`
		class Foo
			def set(x)
				@x = x;
			end

			def get
				@x
			end

			def double_get
				self.get() * 2;
			end
		end

		class Bar
			def set(x)
				@x = x;
			end

			def get
				@x
			end
		end

		f1 = Foo.new
		f1.set(10)

		f2 = Foo.new
		f2.set(20)

		b = Bar.new
		b.set(10)

		f2.double_get() + f1.get() + b.get()
	`, 60},
		{`
		class Foo
		  attr_reader("bar")
		end

		Foo.new.bar
		`, nil},
		{`
		class Foo
		  def bar
		    @x
		  end
		end

		Foo.new.bar
		`, nil},
	}

	for _, tt := range tests {
		evaluated := testEval(t, tt.input)

		if isError(evaluated) {
			t.Fatalf("got Error: %s", evaluated.(*Error).Message)
		}

		checkExpected(t, evaluated, tt.expected)
	}
}

func TestEvalInstanceMethodCall(t *testing.T) {
	input := `

		class Bar
			def set(x)
				@x = x
			end
		end

		class Foo < Bar
			def add(x, y)
				x + y
			end
		end

		class FooBar < Foo
			def get
				@x
			end
		end

		fb = FooBar.new
		fb.set(100)
		fb.add(10, fb.get)
	`

	evaluated := testEval(t, input)

	if isError(evaluated) {
		t.Fatalf("got Error: %s", evaluated.(*Error).Message)
	}

	result, ok := evaluated.(*IntegerObject)

	if !ok {
		t.Errorf("expect result to be an integer. got=%T", evaluated)
	}

	if result.Value != 110 {
		t.Errorf("expect result to be 110. got=%d", result.Value)
	}
}

func TestEvalMethodInheritance(t *testing.T) {
	input := `
		class Foo
			def add(x, y)
				x + y
			end
		end
		Foo.new.add(10, 11)
	`

	evaluated := testEval(t, input)

	if isError(evaluated) {
		t.Fatalf("got Error: %s", evaluated.(*Error).Message)
	}

	result, ok := evaluated.(*IntegerObject)

	if !ok {
		t.Errorf("expect result to be an integer. got=%T", evaluated)
	}

	if result.Value != 21 {
		t.Errorf("expect result to be 21. got=%d", result.Value)
	}
}

func TestEvalClassInheritance(t *testing.T) {
	input := `
		class Bar
		end

		class Foo < Bar
		  def self.add
		    10
		  end
		end

		Foo.superclass.name
	`

	evaluated := testEval(t, input)

	testStringObject(t, evaluated, "Bar")
}

func TestEvalIfExpression(t *testing.T) {
	tests := []struct {
		input    string
		expected interface{}
	}{
		{
			`
			if 10 > 5
				100
			else
				-10
			end
			`,
			100,
		},
		{
			`
			if 5 != 5
				false
			else
				true
			end
			`,
			true,
		},
		{"if true; 10 end", 10},
		{"if false; 10 end", nil},
		{"if 1; 10; end", 10},
		{"if 1 < 2; 10 end", 10},
		{"if 1 > 2; 10 end", nil},
		{"if 1 > 2; 10 else 20 end", 20},
		{"if 1 < 2; 10 else 20 end", 10},
		{"if nil; 10 else 20 end", 20},
	}

	for _, tt := range tests {
		evaluated := testEval(t, tt.input)

		switch tt.expected.(type) {
		case int64:
			testIntegerObject(t, evaluated, tt.expected.(int))
		case bool:
			testBooleanObject(t, evaluated, tt.expected.(bool))
		case nil:
			testNullObject(t, evaluated)
		}

	}
}

func TestEvalPostfix(t *testing.T) {
	tests := []struct {
		input    string
		expected int
	}{
		{"1++", 2},
		{"10--", 9},
		{"0--", -1},
		{"-5++", -4},
		{`
		a = 10
		a ++
		`, 11},
		{`
		a = 10
		a --
		`, 9},
		{`
		(1 + 2 * 3)++
		`, 8},
	}

	for _, tt := range tests {
		evaluated := testEval(t, tt.input)
		testIntegerObject(t, evaluated, tt.expected)
	}
}

func TestEvalBangPrefixExpression(t *testing.T) {
	tests := []struct {
		input    string
		expected bool
	}{
		{"!5", false},
		{"!true", false},
		{"!false", true},
		{"!!true", true},
		{"!!false", false},
		{"!!5", true},
	}

	for _, tt := range tests {
		evaluated := testEval(t, tt.input)
		testBooleanObject(t, evaluated, tt.expected)
	}
}

func TestEvalMinusPrefixExpression(t *testing.T) {
	tests := []struct {
		input    string
		expected int
	}{
		{"-5", -5},
		{"-10", -10},
		{"-(-10)", 10},
		{"-(-5)", 5},
	}

	for _, tt := range tests {
		evaluated := testEval(t, tt.input)
		testIntegerObject(t, evaluated, tt.expected)
	}
}

func TestMethodCallWithBlockArgument(t *testing.T) {
	tests := []struct {
		input    string
		expected int
	}{
		{`
				class Foo
				  def bar
				    yield(1, 3, 5)
				  end
				end

				Foo.new.bar do |first, second, third|
				  first + second * third
				end

				`, 16},
		{`
				class Foo
				  def bar
				    yield
				  end
				end

				Foo.new.bar do
				  3
				end

				`, 3},
		{`
				class Bar
				  def foo
				    yield(10)
				  end
				end

				class Foo
				  def bar
				    yield
				  end
				end

				Bar.new.foo do |num|
				  Foo.new.bar do
				    3 * num
				  end
				end

				`, 30},
		{`
				class Foo
				  def bar
				    0
				  end
				end

				Foo.new.bar do
				  3
				end

				`, 0},
		{`
				class Foo
				  def bar
				    yield
				  end
				end

				i = 10
				Foo.new.bar do
				  i = 3 + i
				end
				i

				`, 13},
		{`
		class Car
		  def initialize
		    yield(self)
		  end

		  def doors=(ds)
		    @doors = ds
		  end

		  def doors
		    @doors
		  end
		end

		car = Car.new do |c|
		  c.doors = 4
		end

		car.doors
				`,
			4},
		{`
		class Foo
		  def bar(x)
		    yield(x)
		  end
		end

		f = Foo.new
		x = 100
		y = 10

		f.bar(10) do |x|
                  y = x + y
		end

		y
		`, 20},
	}

	for _, tt := range tests {
		evaluated := testEval(t, tt.input)
		testIntegerObject(t, evaluated, tt.expected)
	}
}

func TestMethodCallWithNestedBlock(t *testing.T) {
	tests := []struct {
		input    string
		expected int
	}{
		{`
		class Foo
		  def bar
		    yield
		  end
		end

		a = 100
		i = 10
		b = 1000

		f = Foo.new

		f.bar do
		  i = 3 * a
		  f.bar do
		    i = 3 + i
		  end
		end
		i

		`, 303},
		{`
		class Foo
		  def bar
		    yield
		  end
		end

		i = 10
		a = 100
		b = 1000

		f = Foo.new

		f.bar do
		  a = 20
		  f.bar do
		    b = (3 + i) * a
		  end
		end
		b

		`, 260},
	}

	for _, tt := range tests {
		evaluated := testEval(t, tt.input)
		testIntegerObject(t, evaluated, tt.expected)
	}
}
<|endoftext|>


<commit_before>// Package xid is a globally unique id generator suited for web scale
//
// Xid is using Mongo Object ID algorithm to generate globally unique ids:
// https://docs.mongodb.org/manual/reference/object-id/
//
//   - 4-byte value representing the seconds since the Unix epoch,
//   - 3-byte machine identifier,
//   - 2-byte process id, and
//   - 3-byte counter, starting with a random value.
//
// The binary representation of the id is compatible with Mongo 12 bytes Object IDs.
// The string representation is using base32 hex (w/o padding) for better space efficiency
// when stored in that form (20 bytes). The hex variant of base32 is used to retain the
// sortable property of the id.
//
// Xid doesn't use base64 because case sensitivity and the 2 non alphanum chars may be an
// issue when transported as a string between various systems. Base36 wasn't retained either
// because 1/ it's not standard 2/ the resulting size is not predictable (not bit aligned)
// and 3/ it would not remain sortable. To validate a base32 `xid`, expect a 20 chars long,
// all lowercase sequence of `a` to `v` letters and `0` to `9` numbers (`[0-9a-v]{20}`).
//
// UUID is 16 bytes (128 bits), snowflake is 8 bytes (64 bits), xid stands in between
// with 12 bytes with a more compact string representation ready for the web and no
// required configuration or central generation server.
//
// Features:
//
//   - Size: 12 bytes (96 bits), smaller than UUID, larger than snowflake
//   - Base32 hex encoded by default (16 bytes storage when transported as printable string)
//   - Non configured, you don't need set a unique machine and/or data center id
//   - K-ordered
//   - Embedded time with 1 second precision
//   - Unicity guaranted for 16,777,216 (24 bits) unique ids per second and per host/process
//
// Best used with xlog's RequestIDHandler (https://godoc.org/github.com/rs/xlog#RequestIDHandler).
//
// References:
//
//   - http://www.slideshare.net/davegardnerisme/unique-id-generation-in-distributed-systems
//   - https://en.wikipedia.org/wiki/Universally_unique_identifier
//   - https://blog.twitter.com/2010/announcing-snowflake
package xid

import (
	"crypto/md5"
	"crypto/rand"
	"database/sql/driver"
	"encoding/binary"
	"errors"
	"fmt"
	"os"
	"sync/atomic"
	"time"
)

// Code inspired from mgo/bson ObjectId

// ID represents a unique request id
type ID [rawLen]byte

const (
	encodedLen = 20 // string encoded len
	decodedLen = 15 // len after base32 decoding with the padded data
	rawLen     = 12 // binary raw len

	// encoding stores a custom version of the base32 encoding with lower case
	// letters.
	encoding = "0123456789abcdefghijklmnopqrstuv"
)

// ErrInvalidID is returned when trying to unmarshal an invalid ID
var ErrInvalidID = errors.New("xid: invalid ID")

// objectIDCounter is atomically incremented when generating a new ObjectId
// using NewObjectId() function. It's used as a counter part of an id.
// This id is initialized with a random value.
var objectIDCounter = randInt()

// machineId stores machine id generated once and used in subsequent calls
// to NewObjectId function.
var machineID = readMachineID()

// pid stores the current process id
var pid = os.Getpid()

// dec is the decoding map for base32 encoding
var dec [256]byte

func init() {
	for i := 0; i < len(dec); i++ {
		dec[i] = 0xFF
	}
	for i := 0; i < len(encoding); i++ {
		dec[encoding[i]] = byte(i)
	}
}

// readMachineId generates machine id and puts it into the machineId global
// variable. If this function fails to get the hostname, it will cause
// a runtime error.
func readMachineID() []byte {
	id := make([]byte, 3)
	if hostname, err := os.Hostname(); err == nil {
		hw := md5.New()
		hw.Write([]byte(hostname))
		copy(id, hw.Sum(nil))
	} else {
		// Fallback to rand number if machine id can't be gathered
		if _, randErr := rand.Reader.Read(id); randErr != nil {
			panic(fmt.Errorf("xid: cannot get hostname nor generate a random number: %v; %v", err, randErr))
		}
	}
	return id
}

// randInt generates a random uint32
func randInt() uint32 {
	b := make([]byte, 3)
	if _, err := rand.Reader.Read(b); err != nil {
		panic(fmt.Errorf("xid: cannot generate random number: %v;", err))
	}
	return uint32(b[0])<<16 | uint32(b[1])<<8 | uint32(b[2])
}

// New generates a globaly unique ID
func New() ID {
	var id ID
	// Timestamp, 4 bytes, big endian
	binary.BigEndian.PutUint32(id[:], uint32(time.Now().Unix()))
	// Machine, first 3 bytes of md5(hostname)
	id[4] = machineID[0]
	id[5] = machineID[1]
	id[6] = machineID[2]
	// Pid, 2 bytes, specs don't specify endianness, but we use big endian.
	id[7] = byte(pid >> 8)
	id[8] = byte(pid)
	// Increment, 3 bytes, big endian
	i := atomic.AddUint32(&objectIDCounter, 1)
	id[9] = byte(i >> 16)
	id[10] = byte(i >> 8)
	id[11] = byte(i)
	return id
}

// FromString reads an ID from its string representation
func FromString(id string) (ID, error) {
	i := &ID{}
	err := i.UnmarshalText([]byte(id))
	return *i, err
}

// String returns a base32 hex lowercased with no padding representation of the id (char set is 0-9, a-v).
func (id ID) String() string {
	text := make([]byte, encodedLen)
	encode(text, id[:])
	return string(text)
}

// MarshalText implements encoding/text TextMarshaler interface
func (id ID) MarshalText() ([]byte, error) {
	text := make([]byte, encodedLen)
	encode(text, id[:])
	return text, nil
}

// encode by unrolling the stdlib base32 algorithm + removing all safe checks
func encode(dst, id []byte) {
	dst[0] = encoding[id[0]>>3]
	dst[1] = encoding[(id[1]>>6)&0x1F|(id[0]<<2)&0x1F]
	dst[2] = encoding[(id[1]>>1)&0x1F]
	dst[3] = encoding[(id[2]>>4)&0x1F|(id[1]<<4)&0x1F]
	dst[4] = encoding[id[3]>>7|(id[2]<<1)&0x1F]
	dst[5] = encoding[(id[3]>>2)&0x1F]
	dst[6] = encoding[id[4]>>5|(id[3]<<3)&0x1F]
	dst[7] = encoding[id[4]&0x1F]
	dst[8] = encoding[id[5]>>3]
	dst[9] = encoding[(id[6]>>6)&0x1F|(id[5]<<2)&0x1F]
	dst[10] = encoding[(id[6]>>1)&0x1F]
	dst[11] = encoding[(id[7]>>4)&0x1F|(id[6]<<4)&0x1F]
	dst[12] = encoding[id[8]>>7|(id[7]<<1)&0x1F]
	dst[13] = encoding[(id[8]>>2)&0x1F]
	dst[14] = encoding[(id[9]>>5)|(id[8]<<3)&0x1F]
	dst[15] = encoding[id[9]&0x1F]
	dst[16] = encoding[id[10]>>3]
	dst[17] = encoding[(id[11]>>6)&0x1F|(id[10]<<2)&0x1F]
	dst[18] = encoding[(id[11]>>1)&0x1F]
	dst[19] = encoding[(id[11]<<4)&0x1F]
}

// UnmarshalText implements encoding/text TextUnmarshaler interface
func (id *ID) UnmarshalText(text []byte) error {
	if len(text) != encodedLen {
		return ErrInvalidID
	}
	for _, c := range text {
		if dec[c] == 0xFF {
			return ErrInvalidID
		}
	}
	decode(id, text)
	return nil
}

// decode by unrolling the stdlib base32 algorithm + removing all safe checks
func decode(id *ID, src []byte) {
	id[0] = dec[src[0]]<<3 | dec[src[1]]>>2
	id[1] = dec[src[1]]<<6 | dec[src[2]]<<1 | dec[src[3]]>>4
	id[2] = dec[src[3]]<<4 | dec[src[4]]>>1
	id[3] = dec[src[4]]<<7 | dec[src[5]]<<2 | dec[src[6]]>>3
	id[4] = dec[src[6]]<<5 | dec[src[7]]
	id[5] = dec[src[8]]<<3 | dec[src[9]]>>2
	id[6] = dec[src[9]]<<6 | dec[src[10]]<<1 | dec[src[11]]>>4
	id[7] = dec[src[11]]<<4 | dec[src[12]]>>1
	id[8] = dec[src[12]]<<7 | dec[src[13]]<<2 | dec[src[14]]>>3
	id[9] = dec[src[14]]<<5 | dec[src[15]]
	id[10] = dec[src[16]]<<3 | dec[src[17]]>>2
	id[11] = dec[src[17]]<<6 | dec[src[18]]<<1 | dec[src[19]]>>4
}

// Time returns the timestamp part of the id.
// It's a runtime error to call this method with an invalid id.
func (id ID) Time() time.Time {
	// First 4 bytes of ObjectId is 32-bit big-endian seconds from epoch.
	secs := int64(binary.BigEndian.Uint32(id[0:4]))
	return time.Unix(secs, 0)
}

// Machine returns the 3-byte machine id part of the id.
// It's a runtime error to call this method with an invalid id.
func (id ID) Machine() []byte {
	return id[4:7]
}

// Pid returns the process id part of the id.
// It's a runtime error to call this method with an invalid id.
func (id ID) Pid() uint16 {
	return binary.BigEndian.Uint16(id[7:9])
}

// Counter returns the incrementing value part of the id.
// It's a runtime error to call this method with an invalid id.
func (id ID) Counter() int32 {
	b := id[9:12]
	// Counter is stored as big-endian 3-byte value
	return int32(uint32(b[0])<<16 | uint32(b[1])<<8 | uint32(b[2]))
}

// Value implements the driver.Valuer interface.
func (id ID) Value() (driver.Value, error) {
	b, err := id.MarshalText()
	return string(b), err
}

// Scan implements the sql.Scanner interface.
func (id *ID) Scan(value interface{}) (err error) {
	switch val := value.(type) {
	case string:
		return id.UnmarshalText([]byte(val))
	case []byte:
		return id.UnmarshalText(val)
	default:
		return fmt.Errorf("xid: scanning unsupported type: %T", value)
	}
}
<commit_msg>Use cpuset value to define PID when inside a container (#19)<commit_after>// Package xid is a globally unique id generator suited for web scale
//
// Xid is using Mongo Object ID algorithm to generate globally unique ids:
// https://docs.mongodb.org/manual/reference/object-id/
//
//   - 4-byte value representing the seconds since the Unix epoch,
//   - 3-byte machine identifier,
//   - 2-byte process id, and
//   - 3-byte counter, starting with a random value.
//
// The binary representation of the id is compatible with Mongo 12 bytes Object IDs.
// The string representation is using base32 hex (w/o padding) for better space efficiency
// when stored in that form (20 bytes). The hex variant of base32 is used to retain the
// sortable property of the id.
//
// Xid doesn't use base64 because case sensitivity and the 2 non alphanum chars may be an
// issue when transported as a string between various systems. Base36 wasn't retained either
// because 1/ it's not standard 2/ the resulting size is not predictable (not bit aligned)
// and 3/ it would not remain sortable. To validate a base32 `xid`, expect a 20 chars long,
// all lowercase sequence of `a` to `v` letters and `0` to `9` numbers (`[0-9a-v]{20}`).
//
// UUID is 16 bytes (128 bits), snowflake is 8 bytes (64 bits), xid stands in between
// with 12 bytes with a more compact string representation ready for the web and no
// required configuration or central generation server.
//
// Features:
//
//   - Size: 12 bytes (96 bits), smaller than UUID, larger than snowflake
//   - Base32 hex encoded by default (16 bytes storage when transported as printable string)
//   - Non configured, you don't need set a unique machine and/or data center id
//   - K-ordered
//   - Embedded time with 1 second precision
//   - Unicity guaranted for 16,777,216 (24 bits) unique ids per second and per host/process
//
// Best used with xlog's RequestIDHandler (https://godoc.org/github.com/rs/xlog#RequestIDHandler).
//
// References:
//
//   - http://www.slideshare.net/davegardnerisme/unique-id-generation-in-distributed-systems
//   - https://en.wikipedia.org/wiki/Universally_unique_identifier
//   - https://blog.twitter.com/2010/announcing-snowflake
package xid

import (
	"crypto/md5"
	"crypto/rand"
	"database/sql/driver"
	"encoding/binary"
	"errors"
	"fmt"
	"hash/crc32"
	"io/ioutil"
	"os"
	"sync/atomic"
	"time"
)

// Code inspired from mgo/bson ObjectId

// ID represents a unique request id
type ID [rawLen]byte

const (
	encodedLen = 20 // string encoded len
	decodedLen = 15 // len after base32 decoding with the padded data
	rawLen     = 12 // binary raw len

	// encoding stores a custom version of the base32 encoding with lower case
	// letters.
	encoding = "0123456789abcdefghijklmnopqrstuv"
)

// ErrInvalidID is returned when trying to unmarshal an invalid ID
var ErrInvalidID = errors.New("xid: invalid ID")

// objectIDCounter is atomically incremented when generating a new ObjectId
// using NewObjectId() function. It's used as a counter part of an id.
// This id is initialized with a random value.
var objectIDCounter = randInt()

// machineId stores machine id generated once and used in subsequent calls
// to NewObjectId function.
var machineID = readMachineID()

// pid stores the current process id
var pid = os.Getpid()

// dec is the decoding map for base32 encoding
var dec [256]byte

func init() {
	for i := 0; i < len(dec); i++ {
		dec[i] = 0xFF
	}
	for i := 0; i < len(encoding); i++ {
		dec[encoding[i]] = byte(i)
	}

	// If PID is 1 and /proc/1/cpuset exists and is not /, we can assume that we
	// are in a form of container and use the content of /proc/1/cpuset instead
	// of the PID.
	if pid == 1 {
		b, err := ioutil.ReadFile("/proc/1/cpuset")
		if err == nil && len(b) > 1 {
			pid = int(crc32.ChecksumIEEE(b))
		}
	}
}

// readMachineId generates machine id and puts it into the machineId global
// variable. If this function fails to get the hostname, it will cause
// a runtime error.
func readMachineID() []byte {
	id := make([]byte, 3)
	if hostname, err := os.Hostname(); err == nil {
		hw := md5.New()
		hw.Write([]byte(hostname))
		copy(id, hw.Sum(nil))
	} else {
		// Fallback to rand number if machine id can't be gathered
		if _, randErr := rand.Reader.Read(id); randErr != nil {
			panic(fmt.Errorf("xid: cannot get hostname nor generate a random number: %v; %v", err, randErr))
		}
	}
	return id
}

// randInt generates a random uint32
func randInt() uint32 {
	b := make([]byte, 3)
	if _, err := rand.Reader.Read(b); err != nil {
		panic(fmt.Errorf("xid: cannot generate random number: %v;", err))
	}
	return uint32(b[0])<<16 | uint32(b[1])<<8 | uint32(b[2])
}

// New generates a globaly unique ID
func New() ID {
	var id ID
	// Timestamp, 4 bytes, big endian
	binary.BigEndian.PutUint32(id[:], uint32(time.Now().Unix()))
	// Machine, first 3 bytes of md5(hostname)
	id[4] = machineID[0]
	id[5] = machineID[1]
	id[6] = machineID[2]
	// Pid, 2 bytes, specs don't specify endianness, but we use big endian.
	id[7] = byte(pid >> 8)
	id[8] = byte(pid)
	// Increment, 3 bytes, big endian
	i := atomic.AddUint32(&objectIDCounter, 1)
	id[9] = byte(i >> 16)
	id[10] = byte(i >> 8)
	id[11] = byte(i)
	return id
}

// FromString reads an ID from its string representation
func FromString(id string) (ID, error) {
	i := &ID{}
	err := i.UnmarshalText([]byte(id))
	return *i, err
}

// String returns a base32 hex lowercased with no padding representation of the id (char set is 0-9, a-v).
func (id ID) String() string {
	text := make([]byte, encodedLen)
	encode(text, id[:])
	return string(text)
}

// MarshalText implements encoding/text TextMarshaler interface
func (id ID) MarshalText() ([]byte, error) {
	text := make([]byte, encodedLen)
	encode(text, id[:])
	return text, nil
}

// encode by unrolling the stdlib base32 algorithm + removing all safe checks
func encode(dst, id []byte) {
	dst[0] = encoding[id[0]>>3]
	dst[1] = encoding[(id[1]>>6)&0x1F|(id[0]<<2)&0x1F]
	dst[2] = encoding[(id[1]>>1)&0x1F]
	dst[3] = encoding[(id[2]>>4)&0x1F|(id[1]<<4)&0x1F]
	dst[4] = encoding[id[3]>>7|(id[2]<<1)&0x1F]
	dst[5] = encoding[(id[3]>>2)&0x1F]
	dst[6] = encoding[id[4]>>5|(id[3]<<3)&0x1F]
	dst[7] = encoding[id[4]&0x1F]
	dst[8] = encoding[id[5]>>3]
	dst[9] = encoding[(id[6]>>6)&0x1F|(id[5]<<2)&0x1F]
	dst[10] = encoding[(id[6]>>1)&0x1F]
	dst[11] = encoding[(id[7]>>4)&0x1F|(id[6]<<4)&0x1F]
	dst[12] = encoding[id[8]>>7|(id[7]<<1)&0x1F]
	dst[13] = encoding[(id[8]>>2)&0x1F]
	dst[14] = encoding[(id[9]>>5)|(id[8]<<3)&0x1F]
	dst[15] = encoding[id[9]&0x1F]
	dst[16] = encoding[id[10]>>3]
	dst[17] = encoding[(id[11]>>6)&0x1F|(id[10]<<2)&0x1F]
	dst[18] = encoding[(id[11]>>1)&0x1F]
	dst[19] = encoding[(id[11]<<4)&0x1F]
}

// UnmarshalText implements encoding/text TextUnmarshaler interface
func (id *ID) UnmarshalText(text []byte) error {
	if len(text) != encodedLen {
		return ErrInvalidID
	}
	for _, c := range text {
		if dec[c] == 0xFF {
			return ErrInvalidID
		}
	}
	decode(id, text)
	return nil
}

// decode by unrolling the stdlib base32 algorithm + removing all safe checks
func decode(id *ID, src []byte) {
	id[0] = dec[src[0]]<<3 | dec[src[1]]>>2
	id[1] = dec[src[1]]<<6 | dec[src[2]]<<1 | dec[src[3]]>>4
	id[2] = dec[src[3]]<<4 | dec[src[4]]>>1
	id[3] = dec[src[4]]<<7 | dec[src[5]]<<2 | dec[src[6]]>>3
	id[4] = dec[src[6]]<<5 | dec[src[7]]
	id[5] = dec[src[8]]<<3 | dec[src[9]]>>2
	id[6] = dec[src[9]]<<6 | dec[src[10]]<<1 | dec[src[11]]>>4
	id[7] = dec[src[11]]<<4 | dec[src[12]]>>1
	id[8] = dec[src[12]]<<7 | dec[src[13]]<<2 | dec[src[14]]>>3
	id[9] = dec[src[14]]<<5 | dec[src[15]]
	id[10] = dec[src[16]]<<3 | dec[src[17]]>>2
	id[11] = dec[src[17]]<<6 | dec[src[18]]<<1 | dec[src[19]]>>4
}

// Time returns the timestamp part of the id.
// It's a runtime error to call this method with an invalid id.
func (id ID) Time() time.Time {
	// First 4 bytes of ObjectId is 32-bit big-endian seconds from epoch.
	secs := int64(binary.BigEndian.Uint32(id[0:4]))
	return time.Unix(secs, 0)
}

// Machine returns the 3-byte machine id part of the id.
// It's a runtime error to call this method with an invalid id.
func (id ID) Machine() []byte {
	return id[4:7]
}

// Pid returns the process id part of the id.
// It's a runtime error to call this method with an invalid id.
func (id ID) Pid() uint16 {
	return binary.BigEndian.Uint16(id[7:9])
}

// Counter returns the incrementing value part of the id.
// It's a runtime error to call this method with an invalid id.
func (id ID) Counter() int32 {
	b := id[9:12]
	// Counter is stored as big-endian 3-byte value
	return int32(uint32(b[0])<<16 | uint32(b[1])<<8 | uint32(b[2]))
}

// Value implements the driver.Valuer interface.
func (id ID) Value() (driver.Value, error) {
	b, err := id.MarshalText()
	return string(b), err
}

// Scan implements the sql.Scanner interface.
func (id *ID) Scan(value interface{}) (err error) {
	switch val := value.(type) {
	case string:
		return id.UnmarshalText([]byte(val))
	case []byte:
		return id.UnmarshalText(val)
	default:
		return fmt.Errorf("xid: scanning unsupported type: %T", value)
	}
}
<|endoftext|>


<commit_before>package redlot

import (
	"errors"
	"fmt"
	"strconv"
	"time"

	"github.com/syndtr/goleveldb/leveldb/util"
)

func encode_kv_key(key []byte) (buf []byte) {
	buf = append(buf, typeKV)
	buf = append(buf, key...)
	return
}

func decode_kv_key(buf []byte) (key []byte) {
	if len(buf) < 4 {
		return nil
	}
	return buf[1:]
}

func Get(args [][]byte) (interface{}, error) {
	if len(args) < 1 {
		return "", errNosArgs
	}

	v, err := db.Get(encode_kv_key(args[0]), nil)
	return string(v), err
}

func Set(args [][]byte) (interface{}, error) {
	if len(args) < 2 {
		return nil, errNosArgs
	}

	fmt.Printf("SET %s %s\n", args[0], args[1])
	return nil, db.Put(encode_kv_key(args[0]), args[1], nil)
}

func Del(args [][]byte) (interface{}, error) {
	if len(args) < 1 {
		return nil, errNosArgs
	}

	return nil, db.Delete(encode_kv_key(args[0]), nil)
}

func Exists(args [][]byte) (interface{}, error) {
	if len(args) < 1 {
		return int64(-1), errNosArgs
	}

	ret, err := db.Has(encode_kv_key(args[0]), nil)
	if ret {
		return int64(1), err
	}
	return int64(0), err
}

func Expire(args [][]byte) (interface{}, error) {
	if len(args) < 2 {
		return nil, errNosArgs
	}

	key := encode_kv_key(args[0])
	has, _ := db.Has(key, nil)
	if has {
		ttl := strToInt64(string(args[1]))
		if ttl < 1 {
			return nil, errors.New("TTL must > 0, you set to " + string(args[1]))
		}
		bs := uint64ToBytes(uint64(time.Now().UTC().Unix() + ttl))
		if meta.Put(key, bs, nil) == nil {
			return int64(1), nil
		}
	}
	return int64(0), nil
}

func Setx(args [][]byte) (interface{}, error) {
	if len(args) < 3 {
		return nil, errNosArgs
	}

	key := encode_kv_key(args[0])

	ttl := strToInt64(string(args[2]))
	if ttl < 1 {
		return nil, errors.New("TTL must > 0, you set to " + string(args[2]))
	}
	bs := uint64ToBytes(uint64(time.Now().UTC().Unix() + ttl))
	meta.Put(key, bs, nil)

	return nil, db.Put(key, args[1], nil)
}

func Ttl(args [][]byte) (interface{}, error) {
	if len(args) < 1 {
		return int64(-1), errNosArgs
	}

	key := encode_kv_key(args[0])
	b, _ := meta.Get(key, nil)
	if len(b) < 1 {
		return int64(-1), nil
	}
	ttl := int64(bytesToUint64(b)) - time.Now().UTC().Unix()
	if ttl < 0 {
		ttl = -1
		meta.Delete(key, nil)
		db.Delete(key, nil)
	}
	return ttl, nil
}

func Keys(args [][]byte) ([]string, error) {
	if len(args) < 3 {
		return []string{}, errNosArgs
	}

	ks := encode_kv_key(args[0])
	ke := encode_kv_key(args[1])
	limit, _ := strconv.Atoi(string(args[2]))

	var keys []string
	iter := db.NewIterator(&util.Range{Start: ks, Limit: ke}, nil)
	for iter.Next() {
		k := decode_kv_key(iter.Key())
		keys = append(keys, string(k))
		limit--
		if limit == 0 {
			break
		}
	}
	iter.Release()
	err := iter.Error()
	return keys, err
}

func Scan(args [][]byte) ([]string, error) {
	if len(args) < 3 {
		return []string{}, errNosArgs
	}

	ks := encode_kv_key(args[0])
	ke := encode_kv_key(args[1])
	limit, _ := strconv.Atoi(string(args[2]))

	var ret []string
	iter := db.NewIterator(&util.Range{Start: ks, Limit: ke}, nil)
	for iter.Next() {
		k := decode_kv_key(iter.Key())
		ret = append(ret, string(k))
		ret = append(ret, string(iter.Value()))
		limit--
		if limit == 0 {
			break
		}
	}
	iter.Release()
	err := iter.Error()
	return ret, err
}
<commit_msg>Remove underscores.<commit_after>package redlot

import (
	"errors"
	"fmt"
	"strconv"
	"time"

	"github.com/syndtr/goleveldb/leveldb/util"
)

func encodeKvKey(key []byte) (buf []byte) {
	buf = append(buf, typeKV)
	buf = append(buf, key...)
	return
}

func decodeKvKey(buf []byte) (key []byte) {
	if len(buf) < 4 {
		return nil
	}
	return buf[1:]
}

func Get(args [][]byte) (interface{}, error) {
	if len(args) < 1 {
		return "", errNosArgs
	}

	v, err := db.Get(encodeKvKey(args[0]), nil)
	return string(v), err
}

func Set(args [][]byte) (interface{}, error) {
	if len(args) < 2 {
		return nil, errNosArgs
	}

	fmt.Printf("SET %s %s\n", args[0], args[1])
	return nil, db.Put(encodeKvKey(args[0]), args[1], nil)
}

func Del(args [][]byte) (interface{}, error) {
	if len(args) < 1 {
		return nil, errNosArgs
	}

	return nil, db.Delete(encodeKvKey(args[0]), nil)
}

func Exists(args [][]byte) (interface{}, error) {
	if len(args) < 1 {
		return int64(-1), errNosArgs
	}

	ret, err := db.Has(encodeKvKey(args[0]), nil)
	if ret {
		return int64(1), err
	}
	return int64(0), err
}

func Expire(args [][]byte) (interface{}, error) {
	if len(args) < 2 {
		return nil, errNosArgs
	}

	key := encodeKvKey(args[0])
	has, _ := db.Has(key, nil)
	if has {
		ttl := strToInt64(string(args[1]))
		if ttl < 1 {
			return nil, errors.New("TTL must > 0, you set to " + string(args[1]))
		}
		bs := uint64ToBytes(uint64(time.Now().UTC().Unix() + ttl))
		if meta.Put(key, bs, nil) == nil {
			return int64(1), nil
		}
	}
	return int64(0), nil
}

func Setx(args [][]byte) (interface{}, error) {
	if len(args) < 3 {
		return nil, errNosArgs
	}

	key := encodeKvKey(args[0])

	ttl := strToInt64(string(args[2]))
	if ttl < 1 {
		return nil, errors.New("TTL must > 0, you set to " + string(args[2]))
	}
	bs := uint64ToBytes(uint64(time.Now().UTC().Unix() + ttl))
	meta.Put(key, bs, nil)

	return nil, db.Put(key, args[1], nil)
}

func Ttl(args [][]byte) (interface{}, error) {
	if len(args) < 1 {
		return int64(-1), errNosArgs
	}

	key := encodeKvKey(args[0])
	b, _ := meta.Get(key, nil)
	if len(b) < 1 {
		return int64(-1), nil
	}
	ttl := int64(bytesToUint64(b)) - time.Now().UTC().Unix()
	if ttl < 0 {
		ttl = -1
		meta.Delete(key, nil)
		db.Delete(key, nil)
	}
	return ttl, nil
}

func Keys(args [][]byte) ([]string, error) {
	if len(args) < 3 {
		return []string{}, errNosArgs
	}

	ks := encodeKvKey(args[0])
	ke := encodeKvKey(args[1])
	limit, _ := strconv.Atoi(string(args[2]))

	var keys []string
	iter := db.NewIterator(&util.Range{Start: ks, Limit: ke}, nil)
	for iter.Next() {
		k := decodeKvKey(iter.Key())
		keys = append(keys, string(k))
		limit--
		if limit == 0 {
			break
		}
	}
	iter.Release()
	err := iter.Error()
	return keys, err
}

func Scan(args [][]byte) ([]string, error) {
	if len(args) < 3 {
		return []string{}, errNosArgs
	}

	ks := encodeKvKey(args[0])
	ke := encodeKvKey(args[1])
	limit, _ := strconv.Atoi(string(args[2]))

	var ret []string
	iter := db.NewIterator(&util.Range{Start: ks, Limit: ke}, nil)
	for iter.Next() {
		k := decodeKvKey(iter.Key())
		ret = append(ret, string(k))
		ret = append(ret, string(iter.Value()))
		limit--
		if limit == 0 {
			break
		}
	}
	iter.Release()
	err := iter.Error()
	return ret, err
}
<|endoftext|>


<commit_before>package vmlist

import (
	"fmt"
	"io"
	"path"

	simplejson "github.com/bitly/go-simplejson"
)

type BrowserSpec struct {
	OsName       string
	SoftwareName string
	Version      string
	OsVersion    string
}

type ChunkFile struct {
	Md5url string
	Url    string
}

func (f *ChunkFile) GetLocalFileName() string {
	return path.Base(f.Url)
}

func GetFilesForBrowser(r io.Reader, spec *BrowserSpec) ([]ChunkFile, error) {
	osList, err := simplejson.NewFromReader(r)
	if err != nil {
		return nil, err
	}

	softwareList, err := getSoftwareListForOsName(osList, spec.OsName)
	if err != nil {
		return nil, err
	}

	browsers, err := getBrowsersForSoftwareName(softwareList, spec.SoftwareName)
	if err != nil {
		return nil, err
	}

	return getFilesForVersionAndOsVersion(browsers, spec.Version, spec.OsVersion)
}

func getSoftwareListForOsName(js *simplejson.Json, osName string) (*simplejson.Json, error) {
	return findArrayForKey(js, "softwareList", "osName", osName)
}

func getBrowsersForSoftwareName(js *simplejson.Json, softwareName string) (*simplejson.Json, error) {
	return findArrayForKey(js, "browsers", "softwareName", softwareName)
}

func getFilesForVersionAndOsVersion(js *simplejson.Json, version, osVersion string) ([]ChunkFile, error) {
	jsFiles, err := findArrayFor2Keys(js, "files", "version", version, "osVersion", osVersion)
	if err != nil {
		return nil, err
	}

	elems, err := jsFiles.Array()
	if err != nil {
		return nil, err
	}

	files := make([]ChunkFile, len(elems))
	for i, _ := range elems {
		elem := jsFiles.GetIndex(i)
		if err != nil {
			return nil, err
		}

		md5url, err := elem.Get("md5").String()
		if err != nil {
			return nil, err
		}

		url, err := elem.Get("url").String()
		if err != nil {
			return nil, err
		}

		files[i] = ChunkFile{
			Md5url: md5url,
			Url:    url,
		}
	}
	return files, nil
}

func findArrayForKey(js *simplejson.Json, arrayKey, keyName, keyValue string) (*simplejson.Json, error) {
	elems, err := js.Array()
	if err != nil {
		return nil, err
	}

	for i, _ := range elems {
		elem := js.GetIndex(i)
		if err != nil {
			return nil, err
		}

		value, err := elem.Get(keyName).String()
		if err != nil {
			return nil, err
		}

		if value == keyValue {
			jsArray := elem.Get(arrayKey)
			_, err := jsArray.Array()
			if err != nil {
				return nil, err
			}

			return jsArray, nil
		}
	}
	return nil, fmt.Errorf("%s:\"%s\" not found", keyName, keyValue)
}

func findArrayFor2Keys(js *simplejson.Json, arrayKey, key1Name, key1Value, key2Name, key2Value string) (*simplejson.Json, error) {
	elems, err := js.Array()
	if err != nil {
		return nil, err
	}

	for i, _ := range elems {
		elem := js.GetIndex(i)
		if err != nil {
			return nil, err
		}

		value1, err := elem.Get(key1Name).String()
		if err != nil {
			return nil, err
		}

		value2, err := elem.Get(key2Name).String()
		if err != nil {
			return nil, err
		}

		if value1 == key1Value && value2 == key2Value {
			jsArray := elem.Get(arrayKey)
			_, err := jsArray.Array()
			if err != nil {
				return nil, err
			}

			return jsArray, nil
		}
	}
	return nil, fmt.Errorf("%s:\"%s\", %s:\"%s\" not found", key1Name, key1Value, key2Name, key2Value)
}
<commit_msg>Use encoding/json instead of github.com/bitly/go-simplejson<commit_after>package vmlist

import (
	"encoding/json"
	"fmt"
	"io"
	"path"
)

type BrowserSpec struct {
	OsName       string
	SoftwareName string
	Version      string
	OsVersion    string
}

type osData struct {
	OsName       string
	SoftwareList []softwareData
}

type softwareData struct {
	SoftwareName string
	Browsers     []browserData
}

type browserData struct {
	Version   string
	OsVersion string
	Files     []ChunkFile
}

type ChunkFile struct {
	Md5url string `json:"md5"`
	Url    string
}

func (f *ChunkFile) GetLocalFileName() string {
	return path.Base(f.Url)
}

func GetFilesForBrowser(r io.Reader, spec *BrowserSpec) ([]ChunkFile, error) {
	var osList []osData
	decoder := json.NewDecoder(r)
	err := decoder.Decode(&osList)
	if err != nil {
		return nil, err
	}

	softwareList := getSoftwareListForOsName(osList, spec.OsName)
	if softwareList == nil {
		return nil, fmt.Errorf("softwareList not found for os: %s", spec.OsName)
	}

	browsers := getBrowsersForSoftwareName(softwareList, spec.SoftwareName)
	if browsers == nil {
		return nil, fmt.Errorf("browsers not found for softwareName: %s", spec.SoftwareName)
	}

	files := getFilesForVersionAndOsVersion(browsers, spec.Version, spec.OsVersion)
	if files == nil {
		return nil, fmt.Errorf("files not found for version: %s, osVersion: %s", spec.Version, spec.OsVersion)
	}

	return files, nil
}

func getSoftwareListForOsName(osList []osData, osName string) []softwareData {
	for _, os := range osList {
		if os.OsName == osName {
			return os.SoftwareList
		}
	}
	return nil
}

func getBrowsersForSoftwareName(softwareList []softwareData, softwareName string) []browserData {
	for _, software := range softwareList {
		if software.SoftwareName == softwareName {
			return software.Browsers
		}
	}
	return nil
}

func getFilesForVersionAndOsVersion(browsers []browserData, version, osVersion string) []ChunkFile {
	for _, browser := range browsers {
		if browser.Version == version && browser.OsVersion == osVersion {
			return browser.Files
		}
	}
	return nil
}
<|endoftext|>


<commit_before>package solr

import (
	"fmt"
	"math"
	"net/url"
)

type Document map[string]interface{}

type SolrResponse struct {
	Status   int
	Response map[string]interface{}
}

type SolrUpdateResponse struct {
	Success bool
	Result  map[string]interface{}
}

// Has check if a key exist in document
func (d Document) Has(k string) bool {
	_, ok := d[k]
	return ok
}

// Get returns value of a key
func (d Document) Get(k string) interface{} {
	v, _ := d[k]
	return v
}

// Set add a key/value to document
func (d Document) Set(k string, v interface{}) {
	d[k] = v
}

type Collection struct {
	Docs     []Document
	Start    int
	NumFound int
}

type SolrResult struct {
	Status         int         // status quick access to status
	Results        *Collection // results parsed documents, basically response object
	ResponseHeader map[string]interface{}
	FacetCounts    map[string]interface{}
	Highlighting   map[string]interface{}
	Error          map[string]interface{}
	Grouped        map[string]interface{} // grouped for grouping result if grouping Results will be empty
	Stats          map[string]interface{}
	MoreLikeThis   map[string]interface{} // MoreLikeThis using Search (select) Component
}

type SolrMltResult struct {
	Status         int         // status quick access to status
	Results        *Collection // results parsed documents, basically response object
	Match          *Collection
	ResponseHeader map[string]interface{}
	Error          map[string]interface{}
}

type SolrInterface struct {
	conn *Connection
}

// Return a new instance of SolrInterface
func NewSolrInterface(solrUrl, core string) (*SolrInterface, error) {
	c, err := NewConnection(solrUrl, core)
	if err != nil {
		return nil, err
	}
	return &SolrInterface{conn: c}, nil
}

// Set to new core, this is just wrapper to Connection.SetCore which mean
// it will affect all places that use this Connection instance
func (si *SolrInterface) SetCore(core string) {
	si.conn.SetCore(core)
}

// SetBasicAuth sets the request's Authorization header to use HTTP Basic Authentication with the provided username and password.
// See http://golang.org/pkg/net/http/#Request.SetBasicAuth
func (si *SolrInterface) SetBasicAuth(username, password string) {
	si.conn.SetBasicAuth(username, password)
}

// Return a new instace of Search, q is optional and one can set it later
func (si *SolrInterface) Search(q *Query) *Search {
	return NewSearch(si.conn, q)
}

// makeAddChunks splits the documents into chunks. If chunk_size is less than one it will be default to 100
func makeAddChunks(docs []Document, chunk_size int) []map[string]interface{} {
	if chunk_size < 1 {
		chunk_size = 100
	}
	docs_len := len(docs)
	num_chunk := int(math.Ceil(float64(docs_len) / float64(chunk_size)))
	doc_counter := 0
	chunks := make([]map[string]interface{}, num_chunk)
	for i := 0; i < num_chunk; i++ {
		add := make([]Document, 0, chunk_size)
		for j := 0; j < chunk_size; j++ {
			if doc_counter >= docs_len {
				break
			}
			add = append(add, docs[doc_counter])
			doc_counter++
		}
		chunks[i] = map[string]interface{}{"add": add}
	}
	return chunks
}

// Add will insert documents in batch of chunk_size. success is false as long as one chunk failed.
// The result in UpdateResponse is summery of response from all chunks
// with key chunk_%d
func (si *SolrInterface) Add(docs []Document, chunk_size int, params *url.Values) (*SolrUpdateResponse, error) {
	result := &SolrUpdateResponse{Success: true}
	responses := map[string]interface{}{}
	chunks := makeAddChunks(docs, chunk_size)

	for i := 0; i < len(chunks); i++ {
		res, err := si.Update(chunks[i], params)
		if err != nil {
			return nil, err
		}
		result.Success = result.Success && res.Success
		responses[fmt.Sprintf("chunk_%d", i+1)] = map[string]interface{}{
			"result":  res.Result,
			"success": res.Success,
			"total":   len(chunks[i]["add"].([]Document))}
	}
	result.Result = responses
	return result, nil
}

// Delete take data of type map and optional params which can use to specify addition parameters such as commit=true .
// Only one delete statement is supported, ie data can be { "id":"ID" } .
// If you want to delete more docs use { "query":"QUERY" } .
// Extra params can specify in params or in data such as { "query":"QUERY", "commitWithin":"500" }
func (si *SolrInterface) Delete(data map[string]interface{}, params *url.Values) (*SolrUpdateResponse, error) {
	message := map[string]interface{}{"delete": data}
	return si.Update(message, params)
}

// DeleteAll will remove all documents and commit
func (si *SolrInterface) DeleteAll() (*SolrUpdateResponse, error) {
	params := &url.Values{}
	params.Add("commit", "true")
	return si.Delete(map[string]interface{}{"query": "*:*"}, params)
}

// Update take data of type map and optional params which can use to specify addition parameters such as commit=true
func (si *SolrInterface) Update(data map[string]interface{}, params *url.Values) (*SolrUpdateResponse, error) {
	if si.conn == nil {
		return nil, fmt.Errorf("No connection found for making request to solr")
	}
	return si.conn.Update(data, params)
}

// Commit the changes since the last commit
func (si *SolrInterface) Commit() (*SolrUpdateResponse, error) {
	params := &url.Values{}
	params.Add("commit", "true")
	return si.Update(map[string]interface{}{}, params)
}

func (si *SolrInterface) Optimize(params *url.Values) (*SolrUpdateResponse, error) {
	if params == nil {
		params = &url.Values{}
	}
	params.Set("optimize", "true")
	return si.Update(map[string]interface{}{}, params)
}

// Rollback rollbacks all add/deletes made to the index since the last commit.
// This should use with caution.
// See https://wiki.apache.org/solr/UpdateXmlMessages#A.22rollback.22
func (si *SolrInterface) Rollback() (*SolrUpdateResponse, error) {
	return si.Update(map[string]interface{}{"rollback": map[string]interface{}{}}, nil)
}

// Return new instance of CoreAdmin with provided solrUrl and basic auth
func (si *SolrInterface) CoreAdmin() (*CoreAdmin, error) {
	ca, err := NewCoreAdmin(si.conn.url.String())
	if err != nil {
		return nil, err
	}
	ca.SetBasicAuth(si.conn.username, si.conn.password)
	return ca, nil
}

// Return new instance of Schema with provided solrUrl and basic auth
func (si *SolrInterface) Schema() (*Schema, error) {
	s, err := NewSchema(si.conn.url.String(), si.conn.core)
	if err != nil {
		return nil, err
	}
	s.SetBasicAuth(si.conn.username, si.conn.password)
	return s, nil
}

// Return 'status' and QTime from solr, if everything is fine status should have value 'OK'
// QTime will have value -1 if can not determine
func (si *SolrInterface) Ping() (status string, qtime int, err error) {
	r, err := HTTPGet(fmt.Sprintf("%s/%s/admin/ping?wt=json", si.conn.url.String(), si.conn.core), nil, si.conn.username, si.conn.password)
	if err != nil {
		return "", -1, err
	}

	resp, err := bytes2json(&r)
	if err != nil {
		return "", -1, err
	}
	status, ok := resp["status"].(string)
	if ok == false {
		return "", -1, fmt.Errorf("Unexpected response returned")
	}
	if QTime, ok := resp["responseHeader"].(map[string]interface{})["QTime"]; ok {
		qtime = int(QTime.(float64))
	} else {
		qtime = -1
	}
	return status, qtime, nil
}
<commit_msg>#27 Adding more docstring<commit_after>package solr

import (
	"fmt"
	"math"
	"net/url"
)

type Document map[string]interface{}

type SolrResponse struct {
	Status   int
	Response map[string]interface{}
}

type SolrUpdateResponse struct {
	Success bool
	Result  map[string]interface{}
}

// Has check if a key exist in document
func (d Document) Has(k string) bool {
	_, ok := d[k]
	return ok
}

// Get returns value of a key
func (d Document) Get(k string) interface{} {
	v, _ := d[k]
	return v
}

// Set add a key/value to document
func (d Document) Set(k string, v interface{}) {
	d[k] = v
}

type Collection struct {
	Docs     []Document
	Start    int
	NumFound int
}

// Parsed result for SearchHandler response, ie /select
type SolrResult struct {
	Status         int         // status quick access to status
	Results        *Collection // results parsed documents, basically response object
	ResponseHeader map[string]interface{}
	FacetCounts    map[string]interface{}
	Highlighting   map[string]interface{}
	Error          map[string]interface{}
	Grouped        map[string]interface{} // grouped for grouping result if grouping Results will be empty
	Stats          map[string]interface{}
	MoreLikeThis   map[string]interface{} // MoreLikeThis using Search (select) Component
}

// Parsed result for MoreLikeThisHandler response, ie /mlt
type SolrMltResult struct {
	Status         int         // status quick access to status
	Results        *Collection // results parsed documents, basically response object
	Match          *Collection // Documents for match section
	ResponseHeader map[string]interface{}
	Error          map[string]interface{}
}

type SolrInterface struct {
	conn *Connection
}

// Return a new instance of SolrInterface
func NewSolrInterface(solrUrl, core string) (*SolrInterface, error) {
	c, err := NewConnection(solrUrl, core)
	if err != nil {
		return nil, err
	}
	return &SolrInterface{conn: c}, nil
}

// Set to new core, this is just wrapper to Connection.SetCore which mean
// it will affect all places that use this Connection instance
func (si *SolrInterface) SetCore(core string) {
	si.conn.SetCore(core)
}

// SetBasicAuth sets the request's Authorization header to use HTTP Basic Authentication with the provided username and password.
// See http://golang.org/pkg/net/http/#Request.SetBasicAuth
func (si *SolrInterface) SetBasicAuth(username, password string) {
	si.conn.SetBasicAuth(username, password)
}

// Return a new instace of Search, q is optional and one can set it later
func (si *SolrInterface) Search(q *Query) *Search {
	return NewSearch(si.conn, q)
}

// makeAddChunks splits the documents into chunks. If chunk_size is less than one it will be default to 100
func makeAddChunks(docs []Document, chunk_size int) []map[string]interface{} {
	if chunk_size < 1 {
		chunk_size = 100
	}
	docs_len := len(docs)
	num_chunk := int(math.Ceil(float64(docs_len) / float64(chunk_size)))
	doc_counter := 0
	chunks := make([]map[string]interface{}, num_chunk)
	for i := 0; i < num_chunk; i++ {
		add := make([]Document, 0, chunk_size)
		for j := 0; j < chunk_size; j++ {
			if doc_counter >= docs_len {
				break
			}
			add = append(add, docs[doc_counter])
			doc_counter++
		}
		chunks[i] = map[string]interface{}{"add": add}
	}
	return chunks
}

// Add will insert documents in batch of chunk_size. success is false as long as one chunk failed.
// The result in UpdateResponse is summery of response from all chunks
// with key chunk_%d
func (si *SolrInterface) Add(docs []Document, chunk_size int, params *url.Values) (*SolrUpdateResponse, error) {
	result := &SolrUpdateResponse{Success: true}
	responses := map[string]interface{}{}
	chunks := makeAddChunks(docs, chunk_size)

	for i := 0; i < len(chunks); i++ {
		res, err := si.Update(chunks[i], params)
		if err != nil {
			return nil, err
		}
		result.Success = result.Success && res.Success
		responses[fmt.Sprintf("chunk_%d", i+1)] = map[string]interface{}{
			"result":  res.Result,
			"success": res.Success,
			"total":   len(chunks[i]["add"].([]Document))}
	}
	result.Result = responses
	return result, nil
}

// Delete take data of type map and optional params which can use to specify addition parameters such as commit=true .
// Only one delete statement is supported, ie data can be { "id":"ID" } .
// If you want to delete more docs use { "query":"QUERY" } .
// Extra params can specify in params or in data such as { "query":"QUERY", "commitWithin":"500" }
func (si *SolrInterface) Delete(data map[string]interface{}, params *url.Values) (*SolrUpdateResponse, error) {
	message := map[string]interface{}{"delete": data}
	return si.Update(message, params)
}

// DeleteAll will remove all documents and commit
func (si *SolrInterface) DeleteAll() (*SolrUpdateResponse, error) {
	params := &url.Values{}
	params.Add("commit", "true")
	return si.Delete(map[string]interface{}{"query": "*:*"}, params)
}

// Update take data of type map and optional params which can use to specify addition parameters such as commit=true
func (si *SolrInterface) Update(data map[string]interface{}, params *url.Values) (*SolrUpdateResponse, error) {
	if si.conn == nil {
		return nil, fmt.Errorf("No connection found for making request to solr")
	}
	return si.conn.Update(data, params)
}

// Commit the changes since the last commit
func (si *SolrInterface) Commit() (*SolrUpdateResponse, error) {
	params := &url.Values{}
	params.Add("commit", "true")
	return si.Update(map[string]interface{}{}, params)
}

func (si *SolrInterface) Optimize(params *url.Values) (*SolrUpdateResponse, error) {
	if params == nil {
		params = &url.Values{}
	}
	params.Set("optimize", "true")
	return si.Update(map[string]interface{}{}, params)
}

// Rollback rollbacks all add/deletes made to the index since the last commit.
// This should use with caution.
// See https://wiki.apache.org/solr/UpdateXmlMessages#A.22rollback.22
func (si *SolrInterface) Rollback() (*SolrUpdateResponse, error) {
	return si.Update(map[string]interface{}{"rollback": map[string]interface{}{}}, nil)
}

// Return new instance of CoreAdmin with provided solrUrl and basic auth
func (si *SolrInterface) CoreAdmin() (*CoreAdmin, error) {
	ca, err := NewCoreAdmin(si.conn.url.String())
	if err != nil {
		return nil, err
	}
	ca.SetBasicAuth(si.conn.username, si.conn.password)
	return ca, nil
}

// Return new instance of Schema with provided solrUrl and basic auth
func (si *SolrInterface) Schema() (*Schema, error) {
	s, err := NewSchema(si.conn.url.String(), si.conn.core)
	if err != nil {
		return nil, err
	}
	s.SetBasicAuth(si.conn.username, si.conn.password)
	return s, nil
}

// Return 'status' and QTime from solr, if everything is fine status should have value 'OK'
// QTime will have value -1 if can not determine
func (si *SolrInterface) Ping() (status string, qtime int, err error) {
	r, err := HTTPGet(fmt.Sprintf("%s/%s/admin/ping?wt=json", si.conn.url.String(), si.conn.core), nil, si.conn.username, si.conn.password)
	if err != nil {
		return "", -1, err
	}

	resp, err := bytes2json(&r)
	if err != nil {
		return "", -1, err
	}
	status, ok := resp["status"].(string)
	if ok == false {
		return "", -1, fmt.Errorf("Unexpected response returned")
	}
	if QTime, ok := resp["responseHeader"].(map[string]interface{})["QTime"]; ok {
		qtime = int(QTime.(float64))
	} else {
		qtime = -1
	}
	return status, qtime, nil
}
<|endoftext|>


<commit_before>package main

import (
//	"github.com/davecgh/go-spew/spew"
)

type Kube struct {
	Gistid      string `json:"gistid"`
	Filename    string `json:"filename"`
	Description string `json:"description"`
	Tag         string `json:"tag"`
	Like        int    `json:"like"`
}

func pushToDB(id string, filename string, tag string, description string) {
	kube := Kube{
		id,
		filename,
		tag,
		description,
		0,
	}
	pushKube(kube)
}
<commit_msg>fix bug in kube data field<commit_after>package main

import (
//	"github.com/davecgh/go-spew/spew"
)

type Kube struct {
	Gistid      string `json:"gistid"`
	Filename    string `json:"filename"`
	Description string `json:"description"`
	Tag         string `json:"tag"`
	Like        int    `json:"like"`
}

func pushToDB(id string, filename string, tag string, description string) {
	kube := Kube{
		id,
		filename,
		description,
		tag,
		0,
	}
	pushKube(kube)
}
<|endoftext|>


<commit_before>package speedtest

import (
	"github.com/taruti/monotime"
	"io"
	"net/http"
	"strconv"
	"sync"
	"time"
)

type State struct {
	l sync.RWMutex
	m map[string]string
}

func (s *State) Init() {
	s.l.Lock()
	s.m = map[string]string{}
	s.l.Unlock()
}

func (s *State) WriteSpeedJSON(w http.ResponseWriter, remoteHost string) error {
	s.l.RLock()
	r, ok := s.m[remoteHost]
	s.l.RUnlock()
	if !ok {
		el := monotime.NewElapsed()
		timer := time.NewTimer(5 * time.Second)
		defer timer.Stop()
		total := 0.0
		for total < 1024*1024 {
			select {
			case <-timer.C:
				break
			default:
				n, e := w.Write(spaces)
				if e != nil {
					return e
				}
				total += float64(n)
			}
		}
		r = strconv.FormatInt(round(total/el.Current().Seconds()), 10)
		s.l.Lock()
		s.m[remoteHost] = r
		s.l.Unlock()
	}
	_, e := io.WriteString(w, r)
	return e
}

func round(f float64) int64 {
	return int64(f + 0.5)
}

var spaces = func() []byte {
	bs := make([]byte, 4096)
	for i := range bs {
		bs[i] = ' '
	}
	return bs
}()
<commit_msg>use a plain io.Writer<commit_after>// Speedtesting for use with writers.
package speedtest

import (
	"github.com/taruti/monotime"
	"io"
	"strconv"
	"sync"
	"time"
)

type State struct {
	l sync.RWMutex
	m map[string]string
}

func (s *State) Init() {
	s.l.Lock()
	s.m = map[string]string{}
	s.l.Unlock()
}

func (s *State) WriteSpeedJSON(w io.Writer, remoteHost string) error {
	s.l.RLock()
	r, ok := s.m[remoteHost]
	s.l.RUnlock()
	if !ok {
		el := monotime.NewElapsed()
		timer := time.NewTimer(5 * time.Second)
		defer timer.Stop()
		total := 0.0
		for total < 1024*1024 {
			select {
			case <-timer.C:
				break
			default:
				n, e := w.Write(spaces)
				if e != nil {
					return e
				}
				total += float64(n)
			}
		}
		r = strconv.FormatInt(round(total/el.Current().Seconds()), 10)
		s.l.Lock()
		s.m[remoteHost] = r
		s.l.Unlock()
	}
	_, e := io.WriteString(w, r)
	return e
}

func round(f float64) int64 {
	return int64(f + 0.5)
}

var spaces = func() []byte {
	bs := make([]byte, 4096)
	for i := range bs {
		bs[i] = ' '
	}
	return bs
}()
<|endoftext|>


<commit_before>package goshopify

import (
	"fmt"
	"net/url"
)

type ProductsCountResponse struct {
	Count int64 `json:"count"`
}

type ProductResponse struct {
	Product *Product `json:"product"`
}

type ProductsResponse struct {
	Products []*Product `json:"products"`
}

type Product struct {
	BodyHtml       string     `json:"body_html"`
	CreatedAt      string     `json:"created_at"`
	Handle         string     `json:"handle"`
	Id             int64      `json:"id"`
	ProductType    string     `json:"product_type"`
	PublishedAt    string     `json:"published_at"`
	PublishedScope string     `json:"published_scope"`
	TemplateSuffix string     `json:"template_suffix`
	Title          string     `json:"title"`
	UpdatedAt      string     `json:"updated_at"`
	Vendor         string     `json:"vendor"`
	Tags           string     `json:"tags"`
	Variants       []*Variant `json:"variants"`
	Options        []*Option  `json:"options"`
	Images         []*Image   `json:"images"`
	Image          *Image     `json:"image,omitempty"`
}

type Option struct {
	Id        int64  `json:"id"`
	Name      string `json:"name"`
	Position  int    `json:"position"`
	ProductId int64  `json:"product_id"`
}

type Image struct {
	CreatedAt  string  `json:"created_at"`
	Id         int64   `json:"id"`
	Position   int     `json:"position"`
	ProductId  int64   `json:"product_id"`
	UpdatedAt  string  `json:"updated_at"`
	Source     string  `json:"src"`
	VariantIds []int64 `json:"variant_ids"`
}

func (s *Shopify) GetProduct(productId string, creds *Credentials, params url.Values) (*Product, error) {
	uri, err := s.getUri(fmt.Sprintf(ProductEndpoint, productId), creds, params)
	if err != nil {
		return nil, err
	}

	var productResponse *ProductResponse
	err = s.DoResponse("GET", uri, creds, nil, &productResponse)
	if err != nil {
		return nil, fmt.Errorf("Product: %s", err.Error())
	}

	return productResponse.Product, nil
}

func (s *Shopify) GetProducts(creds *Credentials, params url.Values) ([]*Product, error) {
	uri, err := s.getUri(ProductsEndpoint, creds, params)
	if err != nil {
		return nil, err
	}

	var productsResponse *ProductsResponse
	err = s.DoResponse("GET", uri, creds, nil, &productsResponse)
	if err != nil {
		return nil, fmt.Errorf("Products: %s", err.Error())
	}

	return productsResponse.Products, nil
}

func (s *Shopify) GetProductsCount(creds *Credentials, params url.Values) (int64, error) {
	uri, err := s.getUri(ProductsCountEndpoint, creds, params)
	if err != nil {
		return 0, err
	}

	var productCount ProductsCountResponse
	err = s.DoResponse("GET", uri, creds, nil, &productCount)
	if err != nil {
		return 0, fmt.Errorf("ProductsCount: %s", err.Error())
	}

	return productCount.Count, nil
}
<commit_msg>updating products count<commit_after>package goshopify

import (
	"fmt"
	"net/url"
)

type ProductsCount struct {
	Count int64 `json:"count"`
}

type ProductResponse struct {
	Product *Product `json:"product"`
}

type ProductsResponse struct {
	Products []*Product `json:"products"`
}

type Product struct {
	BodyHtml       string     `json:"body_html"`
	CreatedAt      string     `json:"created_at"`
	Handle         string     `json:"handle"`
	Id             int64      `json:"id"`
	ProductType    string     `json:"product_type"`
	PublishedAt    string     `json:"published_at"`
	PublishedScope string     `json:"published_scope"`
	TemplateSuffix string     `json:"template_suffix`
	Title          string     `json:"title"`
	UpdatedAt      string     `json:"updated_at"`
	Vendor         string     `json:"vendor"`
	Tags           string     `json:"tags"`
	Variants       []*Variant `json:"variants"`
	Options        []*Option  `json:"options"`
	Images         []*Image   `json:"images"`
	Image          *Image     `json:"image,omitempty"`
}

type Option struct {
	Id        int64  `json:"id"`
	Name      string `json:"name"`
	Position  int    `json:"position"`
	ProductId int64  `json:"product_id"`
}

type Image struct {
	CreatedAt  string  `json:"created_at"`
	Id         int64   `json:"id"`
	Position   int     `json:"position"`
	ProductId  int64   `json:"product_id"`
	UpdatedAt  string  `json:"updated_at"`
	Source     string  `json:"src"`
	VariantIds []int64 `json:"variant_ids"`
}

func (s *Shopify) GetProduct(productId string, creds *Credentials, params url.Values) (*Product, error) {
	uri, err := s.getUri(fmt.Sprintf(ProductEndpoint, productId), creds, params)
	if err != nil {
		return nil, err
	}

	var productResponse *ProductResponse
	err = s.DoResponse("GET", uri, creds, nil, &productResponse)
	if err != nil {
		return nil, fmt.Errorf("Product: %s", err.Error())
	}

	return productResponse.Product, nil
}

func (s *Shopify) GetProducts(creds *Credentials, params url.Values) ([]*Product, error) {
	uri, err := s.getUri(ProductsEndpoint, creds, params)
	if err != nil {
		return nil, err
	}

	var productsResponse *ProductsResponse
	err = s.DoResponse("GET", uri, creds, nil, &productsResponse)
	if err != nil {
		return nil, fmt.Errorf("Products: %s", err.Error())
	}

	return productsResponse.Products, nil
}

func (s *Shopify) GetProductsCount(creds *Credentials, params url.Values) (*ProductsCount, error) {
	uri, err := s.getUri(ProductsCountEndpoint, creds, params)
	if err != nil {
		return nil, err
	}

	var productCount *ProductsCount
	err = s.DoResponse("GET", uri, creds, nil, &productCount)
	if err != nil {
		return nil, fmt.Errorf("ProductsCount: %s", err.Error())
	}

	return productCount, nil
}
<|endoftext|>


<commit_before>// Package mq provides an ability to integrate with message broker via AMQP in a declarative way.
package mq

import (
	"fmt"
	"net"
	"sync/atomic"
	"time"

	"github.com/NeowayLabs/wabbit"
	"github.com/NeowayLabs/wabbit/amqp"
	"github.com/NeowayLabs/wabbit/amqptest"
	"github.com/NeowayLabs/wabbit/utils"
	amqpDriver "github.com/streadway/amqp"
)

const (
	// Describes states during reconnect.
	statusReadyForReconnect int32 = 0
	statusReconnecting            = 1
)

// Used for creating connection to the fake AMQP server for tests.
var brokerIsMocked bool

// MQ describes methods provided by message broker adapter.
type MQ interface {
	GetConsumer(name string) (Consumer, error)
	SetConsumerHandler(name string, handler ConsumerHandler) error
	GetProducer(name string) (Producer, error)
	Error() <-chan error
	Close()
}

type conn interface {
	Channel() (wabbit.Channel, error)
	Close() error
	NotifyClose(chan wabbit.Error) chan wabbit.Error
}

type mq struct {
	channel              wabbit.Channel
	config               Config
	connection           conn
	errorChannel         chan error
	internalErrorChannel chan error
	consumers            *consumersRegistry
	producers            *producersRegistry
	reconnectStatus      int32 // Defines whether client is trying to reconnect or not.
}

// New initializes AMQP connection to the message broker
// and returns adapter that provides an ability
// to get configured consumers and producers, read occurred errors and shutdown all workers.
func New(config Config) (MQ, error) {
	config.normalize()

	mq := &mq{
		config:               config,
		errorChannel:         make(chan error),
		internalErrorChannel: make(chan error),
		consumers:            newConsumersRegistry(len(config.Consumers)),
		producers:            newProducersRegistry(len(config.Producers)),
	}

	if err := mq.connect(); err != nil {
		return nil, err
	}

	go mq.errorHandler()

	return mq, mq.initialSetup()
}

// GetConsumer returns a consumer by its name or error if consumer wasn't found.
func (mq *mq) GetConsumer(name string) (consumer Consumer, err error) {
	consumer, ok := mq.consumers.Get(name)
	if !ok {
		err = fmt.Errorf("Consumer '%s' is not registered. Check your configuration.", name)
	}

	return
}

// Set handler for consumer by its name. Returns false if consumer wasn't found.
func (mq *mq) SetConsumerHandler(name string, handler ConsumerHandler) error {
	consumer, err := mq.GetConsumer(name)
	if err != nil {
		return err
	}

	consumer.Consume(handler)

	return nil
}

// GetProducer returns a producer by its name or false if producer wasn't found.
func (mq *mq) GetProducer(name string) (producer Producer, err error) {
	producer, ok := mq.producers.Get(name)
	if !ok {
		err = fmt.Errorf("Producer '%s' is not registered. Check your configuration,", name)
	}

	return
}

// Error provides an ability to access occurring errors.
func (mq *mq) Error() <-chan error {
	return mq.errorChannel
}

// Shutdown all workers and close connection to the message broker.
func (mq *mq) Close() {
	mq.stopProducersAndConsumers()

	if mq.channel != nil {
		mq.channel.Close()
	}

	if mq.connection != nil {
		mq.connection.Close()
	}
}

func (mq *mq) connect() error {
	connection, err := mq.createConnection()
	if err != nil {
		return err
	}

	channel, err := connection.Channel()
	if err != nil {
		connection.Close()

		return err
	}

	mq.connection = connection
	mq.channel = channel

	go mq.handleCloseEvent()

	return nil
}

func (mq *mq) createConnection() (conn conn, err error) {
	if brokerIsMocked {
		return amqptest.Dial(mq.config.DSN)
	}

	return amqp.Dial(mq.config.DSN)
}

// Register close handler.
// To get more details visit https://godoc.org/github.com/streadway/amqp#Connection.NotifyClose.
func (mq *mq) handleCloseEvent() {
	err := <-mq.connection.NotifyClose(make(chan wabbit.Error))
	if err != nil {
		mq.internalErrorChannel <- err
	}
}

func (mq *mq) errorHandler() {
	for err := range mq.internalErrorChannel {
		mq.errorChannel <- err // Proxies errors to the user.
		mq.processError(err)
	}
}

func (mq *mq) processError(err interface{}) {
	switch err.(type) {
	case *net.OpError:
		go mq.reconnect()
	case *utils.Error: // Broken connection. Used in tests.
		go mq.reconnect()
	case *amqpDriver.Error:
		rmqErr, _ := err.(*amqpDriver.Error)
		if rmqErr.Server == false { // For example channel was closed.
			go mq.reconnect()
		}
	default:
		// There is no special behaviour for other errors.
	}
}

func (mq *mq) initialSetup() error {
	if err := mq.setupExchanges(); err != nil {
		return err
	}

	if err := mq.setupQueues(); err != nil {
		return err
	}

	if err := mq.setupProducers(); err != nil {
		return err
	}

	return mq.setupConsumers()
}

// Called after each reconnect to recreate non-durable queues and exchanges.
func (mq *mq) setupAfterReconnect() error {
	if err := mq.setupExchanges(); err != nil {
		return err
	}

	if err := mq.setupQueues(); err != nil {
		return err
	}

	mq.producers.GoEach(func(producer *producer) {
		if err := mq.reconnectProducer(producer); err != nil {
			mq.internalErrorChannel <- err
		}
	})

	mq.consumers.GoEach(func(consumer *consumer) {
		if err := mq.reconnectConsumer(consumer); err != nil {
			mq.internalErrorChannel <- err
		}
	})

	return nil
}

func (mq *mq) setupExchanges() error {
	for _, config := range mq.config.Exchanges {
		if err := mq.declareExchange(config); err != nil {
			return err
		}
	}

	return nil
}

func (mq *mq) declareExchange(config ExchangeConfig) error {
	return mq.channel.ExchangeDeclare(config.Name, config.Type, wabbit.Option(config.Options))
}

func (mq *mq) setupQueues() error {
	for _, config := range mq.config.Queues {
		if err := mq.declareQueue(config); err != nil {
			return err
		}
	}

	return nil
}

func (mq *mq) declareQueue(config QueueConfig) error {
	if _, err := mq.channel.QueueDeclare(config.Name, wabbit.Option(config.Options)); err != nil {
		return err
	}

	return mq.channel.QueueBind(config.Name, config.RoutingKey, config.Exchange, wabbit.Option(config.BindingOptions))
}

func (mq *mq) setupProducers() error {
	for _, config := range mq.config.Producers {
		if err := mq.registerProducer(config); err != nil {
			return err
		}
	}

	return nil
}

func (mq *mq) registerProducer(config ProducerConfig) error {
	if _, ok := mq.producers.Get(config.Name); ok {
		return fmt.Errorf(`Producer with name "%s" is already registered`, config.Name)
	}

	channel, err := mq.connection.Channel()
	if err != nil {
		return err
	}

	producer := newProducer(channel, mq.internalErrorChannel, config)

	go producer.worker()
	mq.producers.Set(config.Name, producer)

	return nil
}

func (mq *mq) reconnectProducer(producer *producer) error {
	channel, err := mq.connection.Channel()
	if err != nil {
		return err
	}

	producer.setChannel(channel)
	go producer.worker()

	return nil
}

func (mq *mq) setupConsumers() error {
	for _, config := range mq.config.Consumers {
		if err := mq.registerConsumer(config); err != nil {
			return err
		}
	}

	return nil
}

func (mq *mq) registerConsumer(config ConsumerConfig) error {
	if _, ok := mq.consumers.Get(config.Name); ok {
		return fmt.Errorf(`Consumer with name "%s" is already registered`, config.Name)
	}

	// Consumer must have at least one worker.
	if config.Workers == 0 {
		config.Workers = 1
	}

	consumer := newConsumer(config) // We need to save a whole config for reconnect.
	consumer.prefetchCount = config.PrefetchCount
	consumer.prefetchSize = config.PrefetchSize

	for i := 0; i < config.Workers; i++ {
		worker := newWorker(mq.internalErrorChannel)

		if err := mq.initializeConsumersWorker(consumer, worker); err != nil {
			return err
		}

		consumer.workers[i] = worker
	}

	mq.consumers.Set(config.Name, consumer) // Workers will start after consumer.Consume method call.

	return nil
}

func (mq *mq) reconnectConsumer(consumer *consumer) error {
	for _, worker := range consumer.workers {
		if err := mq.initializeConsumersWorker(consumer, worker); err != nil {
			return err
		}

		go worker.Run(consumer.handler)
	}

	return nil
}

func (mq *mq) initializeConsumersWorker(consumer *consumer, worker *worker) error {
	channel, err := mq.connection.Channel()
	if err != nil {
		return err
	}

	if err := channel.Qos(consumer.prefetchCount, consumer.prefetchSize, false); err != nil {
		return err
	}

	deliveries, err := channel.Consume(consumer.queue, "", consumer.options)
	if err != nil {
		return err
	}

	worker.setChannel(channel)
	worker.deliveries = deliveries

	return nil
}

// Reconnect stops current producers and consumers,
// recreates connection to the rabbit and than runs producers and consumers.
func (mq *mq) reconnect() {
	notBusy := atomic.CompareAndSwapInt32(&mq.reconnectStatus, statusReadyForReconnect, statusReconnecting)
	if !notBusy {
		// There is no need to start a new reconnect if the previous one is not finished yet.
		return
	}

	defer func() {
		atomic.StoreInt32(&mq.reconnectStatus, statusReadyForReconnect)
	}()

	time.Sleep(mq.config.ReconnectDelay) // TODO Add incremental sleep.

	mq.stopProducersAndConsumers()

	if err := mq.connect(); err != nil {
		mq.internalErrorChannel <- err

		return
	}

	if err := mq.setupAfterReconnect(); err != nil {
		mq.internalErrorChannel <- err
	}
}

func (mq *mq) stopProducersAndConsumers() {
	mq.producers.GoEach(func(producer *producer) {
		producer.Stop()
	})

	mq.consumers.GoEach(func(consumer *consumer) {
		consumer.Stop()
	})
}
<commit_msg>Fixed linter's warnings.<commit_after>// Package mq provides an ability to integrate with message broker via AMQP in a declarative way.
package mq

import (
	"fmt"
	"net"
	"sync/atomic"
	"time"

	"github.com/NeowayLabs/wabbit"
	"github.com/NeowayLabs/wabbit/amqp"
	"github.com/NeowayLabs/wabbit/amqptest"
	"github.com/NeowayLabs/wabbit/utils"
	amqpDriver "github.com/streadway/amqp"
)

const (
	// Describes states during reconnect.
	statusReadyForReconnect int32 = 0
	statusReconnecting            = 1
)

// Used for creating connection to the fake AMQP server for tests.
var brokerIsMocked bool

// MQ describes methods provided by message broker adapter.
type MQ interface {
	GetConsumer(name string) (Consumer, error)
	SetConsumerHandler(name string, handler ConsumerHandler) error
	GetProducer(name string) (Producer, error)
	Error() <-chan error
	Close()
}

type conn interface {
	Channel() (wabbit.Channel, error)
	Close() error
	NotifyClose(chan wabbit.Error) chan wabbit.Error
}

type mq struct {
	channel              wabbit.Channel
	config               Config
	connection           conn
	errorChannel         chan error
	internalErrorChannel chan error
	consumers            *consumersRegistry
	producers            *producersRegistry
	reconnectStatus      int32 // Defines whether client is trying to reconnect or not.
}

// New initializes AMQP connection to the message broker
// and returns adapter that provides an ability
// to get configured consumers and producers, read occurred errors and shutdown all workers.
func New(config Config) (MQ, error) {
	config.normalize()

	mq := &mq{
		config:               config,
		errorChannel:         make(chan error),
		internalErrorChannel: make(chan error),
		consumers:            newConsumersRegistry(len(config.Consumers)),
		producers:            newProducersRegistry(len(config.Producers)),
	}

	if err := mq.connect(); err != nil {
		return nil, err
	}

	go mq.errorHandler()

	return mq, mq.initialSetup()
}

// GetConsumer returns a consumer by its name or error if consumer wasn't found.
func (mq *mq) GetConsumer(name string) (consumer Consumer, err error) {
	consumer, ok := mq.consumers.Get(name)
	if !ok {
		err = fmt.Errorf("consumer '%s' is not registered. Check your configuration", name)
	}

	return
}

// Set handler for consumer by its name. Returns false if consumer wasn't found.
func (mq *mq) SetConsumerHandler(name string, handler ConsumerHandler) error {
	consumer, err := mq.GetConsumer(name)
	if err != nil {
		return err
	}

	consumer.Consume(handler)

	return nil
}

// GetProducer returns a producer by its name or false if producer wasn't found.
func (mq *mq) GetProducer(name string) (producer Producer, err error) {
	producer, ok := mq.producers.Get(name)
	if !ok {
		err = fmt.Errorf("Producer '%s' is not registered. Check your configuration,", name)
	}

	return
}

// Error provides an ability to access occurring errors.
func (mq *mq) Error() <-chan error {
	return mq.errorChannel
}

// Shutdown all workers and close connection to the message broker.
func (mq *mq) Close() {
	mq.stopProducersAndConsumers()

	if mq.channel != nil {
		mq.channel.Close()
	}

	if mq.connection != nil {
		mq.connection.Close()
	}
}

func (mq *mq) connect() error {
	connection, err := mq.createConnection()
	if err != nil {
		return err
	}

	channel, err := connection.Channel()
	if err != nil {
		connection.Close()

		return err
	}

	mq.connection = connection
	mq.channel = channel

	go mq.handleCloseEvent()

	return nil
}

func (mq *mq) createConnection() (conn conn, err error) {
	if brokerIsMocked {
		return amqptest.Dial(mq.config.DSN)
	}

	return amqp.Dial(mq.config.DSN)
}

// Register close handler.
// To get more details visit https://godoc.org/github.com/streadway/amqp#Connection.NotifyClose.
func (mq *mq) handleCloseEvent() {
	err := <-mq.connection.NotifyClose(make(chan wabbit.Error))
	if err != nil {
		mq.internalErrorChannel <- err
	}
}

func (mq *mq) errorHandler() {
	for err := range mq.internalErrorChannel {
		mq.errorChannel <- err // Proxies errors to the user.
		mq.processError(err)
	}
}

func (mq *mq) processError(err interface{}) {
	switch err.(type) {
	case *net.OpError:
		go mq.reconnect()
	case *utils.Error: // Broken connection. Used in tests.
		go mq.reconnect()
	case *amqpDriver.Error:
		rmqErr, _ := err.(*amqpDriver.Error)
		if rmqErr.Server == false { // For example channel was closed.
			go mq.reconnect()
		}
	default:
		// There is no special behaviour for other errors.
	}
}

func (mq *mq) initialSetup() error {
	if err := mq.setupExchanges(); err != nil {
		return err
	}

	if err := mq.setupQueues(); err != nil {
		return err
	}

	if err := mq.setupProducers(); err != nil {
		return err
	}

	return mq.setupConsumers()
}

// Called after each reconnect to recreate non-durable queues and exchanges.
func (mq *mq) setupAfterReconnect() error {
	if err := mq.setupExchanges(); err != nil {
		return err
	}

	if err := mq.setupQueues(); err != nil {
		return err
	}

	mq.producers.GoEach(func(producer *producer) {
		if err := mq.reconnectProducer(producer); err != nil {
			mq.internalErrorChannel <- err
		}
	})

	mq.consumers.GoEach(func(consumer *consumer) {
		if err := mq.reconnectConsumer(consumer); err != nil {
			mq.internalErrorChannel <- err
		}
	})

	return nil
}

func (mq *mq) setupExchanges() error {
	for _, config := range mq.config.Exchanges {
		if err := mq.declareExchange(config); err != nil {
			return err
		}
	}

	return nil
}

func (mq *mq) declareExchange(config ExchangeConfig) error {
	return mq.channel.ExchangeDeclare(config.Name, config.Type, wabbit.Option(config.Options))
}

func (mq *mq) setupQueues() error {
	for _, config := range mq.config.Queues {
		if err := mq.declareQueue(config); err != nil {
			return err
		}
	}

	return nil
}

func (mq *mq) declareQueue(config QueueConfig) error {
	if _, err := mq.channel.QueueDeclare(config.Name, wabbit.Option(config.Options)); err != nil {
		return err
	}

	return mq.channel.QueueBind(config.Name, config.RoutingKey, config.Exchange, wabbit.Option(config.BindingOptions))
}

func (mq *mq) setupProducers() error {
	for _, config := range mq.config.Producers {
		if err := mq.registerProducer(config); err != nil {
			return err
		}
	}

	return nil
}

func (mq *mq) registerProducer(config ProducerConfig) error {
	if _, ok := mq.producers.Get(config.Name); ok {
		return fmt.Errorf(`Producer with name "%s" is already registered`, config.Name)
	}

	channel, err := mq.connection.Channel()
	if err != nil {
		return err
	}

	producer := newProducer(channel, mq.internalErrorChannel, config)

	go producer.worker()
	mq.producers.Set(config.Name, producer)

	return nil
}

func (mq *mq) reconnectProducer(producer *producer) error {
	channel, err := mq.connection.Channel()
	if err != nil {
		return err
	}

	producer.setChannel(channel)
	go producer.worker()

	return nil
}

func (mq *mq) setupConsumers() error {
	for _, config := range mq.config.Consumers {
		if err := mq.registerConsumer(config); err != nil {
			return err
		}
	}

	return nil
}

func (mq *mq) registerConsumer(config ConsumerConfig) error {
	if _, ok := mq.consumers.Get(config.Name); ok {
		return fmt.Errorf(`Consumer with name "%s" is already registered`, config.Name)
	}

	// Consumer must have at least one worker.
	if config.Workers == 0 {
		config.Workers = 1
	}

	consumer := newConsumer(config) // We need to save a whole config for reconnect.
	consumer.prefetchCount = config.PrefetchCount
	consumer.prefetchSize = config.PrefetchSize

	for i := 0; i < config.Workers; i++ {
		worker := newWorker(mq.internalErrorChannel)

		if err := mq.initializeConsumersWorker(consumer, worker); err != nil {
			return err
		}

		consumer.workers[i] = worker
	}

	mq.consumers.Set(config.Name, consumer) // Workers will start after consumer.Consume method call.

	return nil
}

func (mq *mq) reconnectConsumer(consumer *consumer) error {
	for _, worker := range consumer.workers {
		if err := mq.initializeConsumersWorker(consumer, worker); err != nil {
			return err
		}

		go worker.Run(consumer.handler)
	}

	return nil
}

func (mq *mq) initializeConsumersWorker(consumer *consumer, worker *worker) error {
	channel, err := mq.connection.Channel()
	if err != nil {
		return err
	}

	if err := channel.Qos(consumer.prefetchCount, consumer.prefetchSize, false); err != nil {
		return err
	}

	deliveries, err := channel.Consume(consumer.queue, "", consumer.options)
	if err != nil {
		return err
	}

	worker.setChannel(channel)
	worker.deliveries = deliveries

	return nil
}

// Reconnect stops current producers and consumers,
// recreates connection to the rabbit and than runs producers and consumers.
func (mq *mq) reconnect() {
	notBusy := atomic.CompareAndSwapInt32(&mq.reconnectStatus, statusReadyForReconnect, statusReconnecting)
	if !notBusy {
		// There is no need to start a new reconnect if the previous one is not finished yet.
		return
	}

	defer func() {
		atomic.StoreInt32(&mq.reconnectStatus, statusReadyForReconnect)
	}()

	time.Sleep(mq.config.ReconnectDelay) // TODO Add incremental sleep.

	mq.stopProducersAndConsumers()

	if err := mq.connect(); err != nil {
		mq.internalErrorChannel <- err

		return
	}

	if err := mq.setupAfterReconnect(); err != nil {
		mq.internalErrorChannel <- err
	}
}

func (mq *mq) stopProducersAndConsumers() {
	mq.producers.GoEach(func(producer *producer) {
		producer.Stop()
	})

	mq.consumers.GoEach(func(consumer *consumer) {
		consumer.Stop()
	})
}
<|endoftext|>


<commit_before>package main

import (
	//"fmt"
	"image"
	"image/color"
	"image/png"
	"math"
	"math/rand"
	"os"
)

func f0(x, y, a, b, c, d, e, f float64) (float64, float64) {
	return x / 2, y / 2
}

func f1(x, y, a, b, c, d, e, f float64) (float64, float64) {
	return (x + 1) / 2, y / 2
}

func f2(x, y, a, b, c, d, e, f float64) (float64, float64) {
	return x / 2, (y + 1) / 2
}

func f3(x, y, a, b, c, d, e, f float64) (float64, float64) {
	return math.Sin(x), math.Sin(y)
}

func f4(x, y, a, b, c, d, e, f float64) (float64, float64) {
	return math.Cos(x), math.Cos(y)
}

func f5(x, y, a, b, c, d, e, f float64) (float64, float64) {
	return math.Cos(a*x + b*y + c), math.Cos(d*x + e*y + f)
}

func maxmx(arr [][]int) int {
	mx := 0
	snd := 0
	thrd := 0
	for _, row := range arr {
		for _, v := range row {
			if mx < v {
				thrd = snd
				snd = mx
				mx = v
			}
		}
	}
	return thrd
}

func flame(width, height, iters int) *image.RGBA {
	x := rand.Float64()*2 - 1
	y := rand.Float64()*2 - 1
	mx := make([][]int, height)
	for y := range mx {
		mx[y] = make([]int, width)
		for x := range mx[y] {
			mx[y][x] = 0
		}
	}
	var a, b, c, d, e, f float64
	a, b, c, d, e, f = 1, 2, 1, 1, 4, 5
	funcs := []func(float64, float64, float64, float64, float64, float64, float64, float64) (float64, float64){f1, f2, f3, f5}
	for at := 0; at < iters; at++ {
		//fmt.Println("before", x, y)
		x, y = funcs[rand.Intn(len(funcs))](x, y, a, b, c, d, e, f)
		if x < -1 {
			x = -1
			continue
		}
		if x > 1 {
			x = 1
			continue
		}
		if y < -1 {
			y = -1
			continue
		}
		if y > 1 {
			y = 1
			continue
		}
		//fmt.Println("after", x,y)
		if at < 20 {
			continue
		}
		mx[int((y+1)/2*float64(height-1))][int((x+1)/2*float64(width-1))] += 1
	}
	max := maxmx(mx)
	m := image.NewRGBA(image.Rect(0, 0, width, height))
	for x, row := range mx {
		for y, v := range row {
			val := uint8(255 * v / max)
			if val > 255 {
				val = 255
			}
			m.Set(x, y, color.RGBA{val, val * 100 / 255, val, 255})
		}
	}
	return m
}

func main() {
	m := flame(800, 800, 10000000)
	toimg, _ := os.Create("new1235.png")
	defer toimg.Close()

	png.Encode(toimg, m)
}
<commit_msg>cleanup<commit_after>package main

import (
	"os"
	"image"
	"image/png"
	"image/color"
	"math"
	"math/rand"
)

// Our functions
func f0(x, y, a, b, c, d, e, f float64) (float64, float64) {
	return x / 2, y / 2
}

func f1(x, y, a, b, c, d, e, f float64) (float64, float64) {
	return (x + 1) / 2, y / 2
}

func f2(x, y, a, b, c, d, e, f float64) (float64, float64) {
	return x / 2, (y + 1) / 2
}

func f3(x, y, a, b, c, d, e, f float64) (float64, float64) {
	return math.Sin(x), math.Sin(y)
}

func f4(x, y, a, b, c, d, e, f float64) (float64, float64) {
	return math.Cos(x), math.Cos(y)
}

func f5(x, y, a, b, c, d, e, f float64) (float64, float64) {
	return math.Cos(a*x + b*y + c), math.Cos(d*x + e*y + f)
}

// get the third-largest value in a matrix. I can probably do this better
func maxmx(arr [][]int) int {
	mx := 0
	snd := 0
	thrd := 0
	for _, row := range arr {
		for _, v := range row {
			if mx < v {
				thrd = snd
				snd = mx
				mx = v
			}
		}
	}
	return thrd
}

/*
(x, y) = a random point in the biunit square
iterate {
   i = a random integer from 0 to n  1 inclusive
   (x, y) = Fi(x, y)
   plot (x, y) except during the first 20 iterations
}
*/

func flame(width, height, iters int) *image.RGBA {
	x := rand.Float64()*2 - 1
	y := rand.Float64()*2 - 1
	mx := make([][]int, height)
	for y := range mx {
		mx[y] = make([]int, width)
		for x := range mx[y] {
			mx[y][x] = 0
		}
	}
	var a, b, c, d, e, f float64
	// these are our parameters
	a, b, c, d, e, f = 1, 2, 1, 1, 4, 5
	// and the F_i s that we'll be using
	funcs := []func(float64, float64, float64, float64, float64, float64, float64, float64) (float64, float64){f1, f2, f3, f5}
	for at := 0; at < iters; at++ {
		x, y = funcs[rand.Intn(len(funcs))](x, y, a, b, c, d, e, f)
		// I should probably refactor this
		if x < -1 {
			x = -1
			continue
		}
		if x > 1 {
			x = 1
			continue
		}
		if y < -1 {
			y = -1
			continue
		}
		if y > 1 {
			y = 1
			continue
		}
		//fmt.Println("after", x,y)
		if at < 20 {
			continue
		}
		// refactor, make more readable
		mx[int((y+1)/2*float64(height-1))][int((x+1)/2*float64(width-1))] += 1
	}
	max := maxmx(mx)
	m := image.NewRGBA(image.Rect(0, 0, width, height))
	// now write the values to an image, equalized by the 3rd-brightest point
	for x, row := range mx {
		for y, v := range row {
			val := uint8(255 * v / max)
			if val > 255 {
				val = 255
			}
			m.Set(x, y, color.RGBA{val, val * 100 / 255, val, 255})
		}
	}
	return m
}

func main() {
	m := flame(800, 800, 10000000)
	toimg, _ := os.Create("new1235.png")
	defer toimg.Close()

	png.Encode(toimg, m)
}
<|endoftext|>