text:
package kubelet

import (
	"fmt"
	"net/http"
	"reflect"
	"regexp"
	"strconv"
	"strings"
	"sync"
	"testing"
	"time"

	"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
	"github.com/GoogleCloudPlatform/kubernetes/pkg/health"
	"github.com/GoogleCloudPlatform/kubernetes/pkg/kubelet/dockertools"
	"github.com/GoogleCloudPlatform/kubernetes/pkg/tools"
	"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
	"github.com/GoogleCloudPlatform/kubernetes/pkg/volume"
	"github.com/fsouza/go-dockerclient"
	"github.com/google/cadvisor/info"
	"github.com/stretchr/testify/mock"
)

func newTestKubelet(t *testing.T) (*Kubelet, *tools.FakeEtcdClient, *dockertools.FakeDockerClient) {
	fakeEtcdClient := tools.NewFakeEtcdClient(t)
	fakeDocker := &dockertools.FakeDockerClient{}

	kubelet := &Kubelet{}
	kubelet.dockerClient = fakeDocker
	kubelet.dockerPuller = &dockertools.FakeDockerPuller{}
	kubelet.etcdClient = fakeEtcdClient
	kubelet.rootDirectory = "/tmp/kubelet"
	kubelet.podWorkers = newPodWorkers()
	return kubelet, fakeEtcdClient, fakeDocker
}

func verifyCalls(t *testing.T, fakeDocker *dockertools.FakeDockerClient, calls []string) {
	err := fakeDocker.AssertCalls(calls)
	if err != nil {
		t.Error(err)
	}
}

func verifyStringArrayEquals(t *testing.T, actual, expected []string) {
	invalid := len(actual) != len(expected)
	if !invalid {
		for ix, value := range actual {
			if expected[ix] != value {
				invalid = true
			}
		}
	}
	if invalid {
		t.Errorf("Expected: %#v, Actual: %#v", expected, actual)
	}
}

func verifyBoolean(t *testing.T, expected, value bool) {
	if expected != value {
		t.Errorf("Unexpected boolean.  Expected %t.  Found %t", expected, value)
	}
}

func TestKillContainerWithError(t *testing.T) {
	fakeDocker := &dockertools.FakeDockerClient{
		Err: fmt.Errorf("sample error"),
		ContainerList: []docker.APIContainers{
			{
				ID:    "1234",
				Names: []string{"/k8s_foo_qux_1234"},
			},
			{
				ID:    "5678",
				Names: []string{"/k8s_bar_qux_5678"},
			},
		},
	}
	kubelet, _, _ := newTestKubelet(t)
	kubelet.dockerClient = fakeDocker
	err := kubelet.killContainer(&fakeDocker.ContainerList[0])
	if err == nil {
		t.Errorf("expected error, found nil")
	}
	verifyCalls(t, fakeDocker, []string{"stop"})
}

func TestKillContainer(t *testing.T) {
	kubelet, _, fakeDocker := newTestKubelet(t)
	fakeDocker.ContainerList = []docker.APIContainers{
		{
			ID:    "1234",
			Names: []string{"/k8s_foo_qux_1234"},
		},
		{
			ID:    "5678",
			Names: []string{"/k8s_bar_qux_5678"},
		},
	}
	fakeDocker.Container = &docker.Container{
		Name: "foobar",
	}

	err := kubelet.killContainer(&fakeDocker.ContainerList[0])
	if err != nil {
		t.Errorf("unexpected error: %v", err)
	}
	verifyCalls(t, fakeDocker, []string{"stop"})
}

type channelReader struct {
	list [][]api.BoundPod
	wg   sync.WaitGroup
}

func startReading(channel <-chan interface{}) *channelReader {
	cr := &channelReader{}
	cr.wg.Add(1)
	go func() {
		for {
			update, ok := <-channel
			if !ok {
				break
			}
			cr.list = append(cr.list, update.(PodUpdate).Pods)
		}
		cr.wg.Done()
	}()
	return cr
}

func (cr *channelReader) GetList() [][]api.BoundPod {
	cr.wg.Wait()
	return cr.list
}

func TestSyncPodsDoesNothing(t *testing.T) {
	kubelet, _, fakeDocker := newTestKubelet(t)
	container := api.Container{Name: "bar"}
	fakeDocker.ContainerList = []docker.APIContainers{
		{
			// format is k8s_<container-id>_<pod-fullname>
			Names: []string{"/k8s_bar." + strconv.FormatUint(dockertools.HashContainer(&container), 16) + "_foo.new.test"},
			ID:    "1234",
		},
		{
			// network container
			Names: []string{"/k8s_net_foo.new.test_"},
			ID:    "9876",
		},
	}
	err := kubelet.SyncPods([]api.BoundPod{
		{
			ObjectMeta: api.ObjectMeta{
				Name:        "foo",
				Namespace:   "new",
				Annotations: map[string]string{ConfigSourceAnnotationKey: "test"},
			},
			Spec: api.PodSpec{
				Containers: []api.Container{
					container,
				},
			},
		},
	})
	if err != nil {
		t.Errorf("unexpected error: %v", err)
	}
	kubelet.drainWorkers()
	verifyCalls(t, fakeDocker, []string{"list", "list", "inspect_container", "inspect_container"})
}

func TestSyncPodsWithTerminationLog(t *testing.T) {
	kubelet, _, fakeDocker := newTestKubelet(t)
	container := api.Container{
		Name: "bar",
		TerminationMessagePath: "/dev/somepath",
	}
	fakeDocker.ContainerList = []docker.APIContainers{}
	err := kubelet.SyncPods([]api.BoundPod{
		{
			ObjectMeta: api.ObjectMeta{
				Name:        "foo",
				Namespace:   "new",
				Annotations: map[string]string{ConfigSourceAnnotationKey: "test"},
			},
			Spec: api.PodSpec{
				Containers: []api.Container{
					container,
				},
			},
		},
	})
	if err != nil {
		t.Errorf("unexpected error: %v", err)
	}
	kubelet.drainWorkers()
	verifyCalls(t, fakeDocker, []string{
		"list", "create", "start", "list", "inspect_container", "list", "create", "start"})

	fakeDocker.Lock()
	parts := strings.Split(fakeDocker.Container.HostConfig.Binds[0], ":")
	if fakeDocker.Container.HostConfig == nil ||
		!matchString(t, "/tmp/kubelet/foo/bar/k8s_bar\\.[a-f0-9]", parts[0]) ||
		parts[1] != "/dev/somepath" {
		t.Errorf("Unexpected containers created %v", fakeDocker.Container)
	}
	fakeDocker.Unlock()
}

// drainWorkers waits until all workers are done.  Should only used for testing.
func (kl *Kubelet) drainWorkers() {
	for {
		kl.podWorkers.lock.Lock()
		length := len(kl.podWorkers.workers)
		kl.podWorkers.lock.Unlock()
		if length == 0 {
			return
		}
		time.Sleep(time.Millisecond * 100)
	}
}

func matchString(t *testing.T, pattern, str string) bool {
	match, err := regexp.MatchString(pattern, str)
	if err != nil {
		t.Logf("unexpected error: %v", err)
	}
	return match
}

func TestSyncPodsCreatesNetAndContainer(t *testing.T) {
	kubelet, _, fakeDocker := newTestKubelet(t)
	kubelet.networkContainerImage = "custom_image_name"
	fakeDocker.ContainerList = []docker.APIContainers{}
	err := kubelet.SyncPods([]api.BoundPod{
		{
			ObjectMeta: api.ObjectMeta{
				Name:        "foo",
				Namespace:   "new",
				Annotations: map[string]string{ConfigSourceAnnotationKey: "test"},
			},
			Spec: api.PodSpec{
				Containers: []api.Container{
					{Name: "bar"},
				},
			},
		},
	})
	if err != nil {
		t.Errorf("unexpected error: %v", err)
	}
	kubelet.drainWorkers()

	verifyCalls(t, fakeDocker, []string{
		"list", "create", "start", "list", "inspect_container", "list", "create", "start"})

	fakeDocker.Lock()

	found := false
	for _, c := range fakeDocker.ContainerList {
		if c.Image == "custom_image_name" && strings.HasPrefix(c.Names[0], "/k8s_net") {
			found = true
		}
	}
	if !found {
		t.Errorf("Custom net container not found: %v", fakeDocker.ContainerList)
	}

	if len(fakeDocker.Created) != 2 ||
		!matchString(t, "k8s_net\\.[a-f0-9]+_foo.new.test_", fakeDocker.Created[0]) ||
		!matchString(t, "k8s_bar\\.[a-f0-9]+_foo.new.test_", fakeDocker.Created[1]) {
		t.Errorf("Unexpected containers created %v", fakeDocker.Created)
	}
	fakeDocker.Unlock()
}

func TestSyncPodsCreatesNetAndContainerPullsImage(t *testing.T) {
	kubelet, _, fakeDocker := newTestKubelet(t)
	puller := kubelet.dockerPuller.(*dockertools.FakeDockerPuller)
	puller.HasImages = []string{}
	kubelet.networkContainerImage = "custom_image_name"
	fakeDocker.ContainerList = []docker.APIContainers{}
	err := kubelet.SyncPods([]api.BoundPod{
		{
			ObjectMeta: api.ObjectMeta{
				Name:        "foo",
				Namespace:   "new",
				Annotations: map[string]string{ConfigSourceAnnotationKey: "test"},
			},
			Spec: api.PodSpec{
				Containers: []api.Container{
					{Name: "bar"},
				},
			},
		},
	})
	if err != nil {
		t.Errorf("unexpected error: %v", err)
	}
	kubelet.drainWorkers()

	verifyCalls(t, fakeDocker, []string{
		"list", "create", "start", "list", "inspect_container", "list", "create", "start"})

	fakeDocker.Lock()

	if !reflect.DeepEqual(puller.ImagesPulled, []string{"custom_image_name", ""}) {
		t.Errorf("Unexpected pulled containers: %v", puller.ImagesPulled)
	}

	if len(fakeDocker.Created) != 2 ||
		!matchString(t, "k8s_net\\.[a-f0-9]+_foo.new.test_", fakeDocker.Created[0]) ||
		!matchString(t, "k8s_bar\\.[a-f0-9]+_foo.new.test_", fakeDocker.Created[1]) {
		t.Errorf("Unexpected containers created %v", fakeDocker.Created)
	}
	fakeDocker.Unlock()
}

func TestSyncPodsWithNetCreatesContainer(t *testing.T) {
	kubelet, _, fakeDocker := newTestKubelet(t)
	fakeDocker.ContainerList = []docker.APIContainers{
		{
			// network container
			Names: []string{"/k8s_net_foo.new.test_"},
			ID:    "9876",
		},
	}
	err := kubelet.SyncPods([]api.BoundPod{
		{
			ObjectMeta: api.ObjectMeta{
				Name:        "foo",
				Namespace:   "new",
				Annotations: map[string]string{ConfigSourceAnnotationKey: "test"},
			},
			Spec: api.PodSpec{
				Containers: []api.Container{
					{Name: "bar"},
				},
			},
		},
	})
	if err != nil {
		t.Errorf("unexpected error: %v", err)
	}
	kubelet.drainWorkers()

	verifyCalls(t, fakeDocker, []string{
		"list", "list", "inspect_container", "list", "create", "start"})

	fakeDocker.Lock()
	if len(fakeDocker.Created) != 1 ||
		!matchString(t, "k8s_bar\\.[a-f0-9]+_foo.new.test_", fakeDocker.Created[0]) {
		t.Errorf("Unexpected containers created %v", fakeDocker.Created)
	}
	fakeDocker.Unlock()
}

func TestSyncPodsWithNetCreatesContainerCallsHandler(t *testing.T) {
	kubelet, _, fakeDocker := newTestKubelet(t)
	fakeHttp := fakeHTTP{}
	kubelet.httpClient = &fakeHttp
	fakeDocker.ContainerList = []docker.APIContainers{
		{
			// network container
			Names: []string{"/k8s_net_foo.new.test_"},
			ID:    "9876",
		},
	}
	err := kubelet.SyncPods([]api.BoundPod{
		{
			ObjectMeta: api.ObjectMeta{
				Name:        "foo",
				Namespace:   "new",
				Annotations: map[string]string{ConfigSourceAnnotationKey: "test"},
			},
			Spec: api.PodSpec{
				Containers: []api.Container{
					{
						Name: "bar",
						Lifecycle: &api.Lifecycle{
							PostStart: &api.Handler{
								HTTPGet: &api.HTTPGetAction{
									Host: "foo",
									Port: util.IntOrString{IntVal: 8080, Kind: util.IntstrInt},
									Path: "bar",
								},
							},
						},
					},
				},
			},
		},
	})
	if err != nil {
		t.Errorf("unexpected error: %v", err)
	}
	kubelet.drainWorkers()

	verifyCalls(t, fakeDocker, []string{
		"list", "list", "inspect_container", "list", "create", "start"})

	fakeDocker.Lock()
	if len(fakeDocker.Created) != 1 ||
		!matchString(t, "k8s_bar\\.[a-f0-9]+_foo.new.test_", fakeDocker.Created[0]) {
		t.Errorf("Unexpected containers created %v", fakeDocker.Created)
	}
	fakeDocker.Unlock()
	if fakeHttp.url != "http://foo:8080/bar" {
		t.Errorf("Unexpected handler: %s", fakeHttp.url)
	}
}

func TestSyncPodsDeletesWithNoNetContainer(t *testing.T) {
	kubelet, _, fakeDocker := newTestKubelet(t)
	fakeDocker.ContainerList = []docker.APIContainers{
		{
			// format is k8s_<container-id>_<pod-fullname>
			Names: []string{"/k8s_bar_foo.new.test"},
			ID:    "1234",
		},
	}
	err := kubelet.SyncPods([]api.BoundPod{
		{
			ObjectMeta: api.ObjectMeta{
				Name:        "foo",
				Namespace:   "new",
				Annotations: map[string]string{ConfigSourceAnnotationKey: "test"},
			},
			Spec: api.PodSpec{
				Containers: []api.Container{
					{Name: "bar"},
				},
			},
		},
	})
	if err != nil {
		t.Errorf("unexpected error: %v", err)
	}
	kubelet.drainWorkers()

	verifyCalls(t, fakeDocker, []string{
		"list", "stop", "create", "start", "list", "list", "inspect_container", "list", "create", "start"})

	// A map iteration is used to delete containers, so must not depend on
	// order here.
	expectedToStop := map[string]bool{
		"1234": true,
	}
	fakeDocker.Lock()
	if len(fakeDocker.Stopped) != 1 || !expectedToStop[fakeDocker.Stopped[0]] {
		t.Errorf("Wrong containers were stopped: %v", fakeDocker.Stopped)
	}
	fakeDocker.Unlock()
}

func TestSyncPodsDeletes(t *testing.T) {
	kubelet, _, fakeDocker := newTestKubelet(t)
	fakeDocker.ContainerList = []docker.APIContainers{
		{
			// the k8s prefix is required for the kubelet to manage the container
			Names: []string{"/k8s_foo_bar.new.test"},
			ID:    "1234",
		},
		{
			// network container
			Names: []string{"/k8s_net_foo.new.test_"},
			ID:    "9876",
		},
		{
			Names: []string{"foo"},
			ID:    "4567",
		},
	}
	err := kubelet.SyncPods([]api.BoundPod{})
	if err != nil {
		t.Errorf("unexpected error: %v", err)
	}

	verifyCalls(t, fakeDocker, []string{"list", "stop", "stop"})

	// A map iteration is used to delete containers, so must not depend on
	// order here.
	expectedToStop := map[string]bool{
		"1234": true,
		"9876": true,
	}
	if len(fakeDocker.Stopped) != 2 ||
		!expectedToStop[fakeDocker.Stopped[0]] ||
		!expectedToStop[fakeDocker.Stopped[1]] {
		t.Errorf("Wrong containers were stopped: %v", fakeDocker.Stopped)
	}
}

func TestSyncPodDeletesDuplicate(t *testing.T) {
	kubelet, _, fakeDocker := newTestKubelet(t)
	dockerContainers := dockertools.DockerContainers{
		"1234": &docker.APIContainers{
			// the k8s prefix is required for the kubelet to manage the container
			Names: []string{"/k8s_foo_bar.new.test_1"},
			ID:    "1234",
		},
		"9876": &docker.APIContainers{
			// network container
			Names: []string{"/k8s_net_bar.new.test_"},
			ID:    "9876",
		},
		"4567": &docker.APIContainers{
			// Duplicate for the same container.
			Names: []string{"/k8s_foo_bar.new.test_2"},
			ID:    "4567",
		},
		"2304": &docker.APIContainers{
			// Container for another pod, untouched.
			Names: []string{"/k8s_baz_fiz.new.test_6"},
			ID:    "2304",
		},
	}
	err := kubelet.syncPod(&api.BoundPod{
		ObjectMeta: api.ObjectMeta{
			Name:        "bar",
			Namespace:   "new",
			Annotations: map[string]string{ConfigSourceAnnotationKey: "test"},
		},
		Spec: api.PodSpec{
			Containers: []api.Container{
				{Name: "foo"},
			},
		},
	}, dockerContainers)
	if err != nil {
		t.Errorf("unexpected error: %v", err)
	}

	verifyCalls(t, fakeDocker, []string{"list", "stop"})

	// Expect one of the duplicates to be killed.
	if len(fakeDocker.Stopped) != 1 || (len(fakeDocker.Stopped) != 0 && fakeDocker.Stopped[0] != "1234" && fakeDocker.Stopped[0] != "4567") {
		t.Errorf("Wrong containers were stopped: %v", fakeDocker.Stopped)
	}
}

type FalseHealthChecker struct{}

func (f *FalseHealthChecker) HealthCheck(podFullName, podUUID string, state api.PodState, container api.Container) (health.Status, error) {
	return health.Unhealthy, nil
}

func (f *FalseHealthChecker) CanCheck(probe *api.LivenessProbe) bool {
	return true
}

func TestSyncPodBadHash(t *testing.T) {
	kubelet, _, fakeDocker := newTestKubelet(t)
	kubelet.healthChecker = &FalseHealthChecker{}
	dockerContainers := dockertools.DockerContainers{
		"1234": &docker.APIContainers{
			// the k8s prefix is required for the kubelet to manage the container
			Names: []string{"/k8s_bar.1234_foo.new.test"},
			ID:    "1234",
		},
		"9876": &docker.APIContainers{
			// network container
			Names: []string{"/k8s_net_foo.new.test_"},
			ID:    "9876",
		},
	}
	err := kubelet.syncPod(&api.BoundPod{
		ObjectMeta: api.ObjectMeta{
			Name:        "foo",
			Namespace:   "new",
			Annotations: map[string]string{ConfigSourceAnnotationKey: "test"},
		},
		Spec: api.PodSpec{
			Containers: []api.Container{
				{Name: "bar"},
			},
		},
	}, dockerContainers)
	if err != nil {
		t.Errorf("unexpected error: %v", err)
	}

	verifyCalls(t, fakeDocker, []string{"list", "stop", "stop", "list", "create", "start"})

	// A map interation is used to delete containers, so must not depend on
	// order here.
	expectedToStop := map[string]bool{
		"1234": true,
		"9876": true,
	}
	if len(fakeDocker.Stopped) != 2 ||
		(!expectedToStop[fakeDocker.Stopped[0]] &&
			!expectedToStop[fakeDocker.Stopped[1]]) {
		t.Errorf("Wrong containers were stopped: %v", fakeDocker.Stopped)
	}
}

func TestSyncPodUnhealthy(t *testing.T) {
	kubelet, _, fakeDocker := newTestKubelet(t)
	kubelet.healthChecker = &FalseHealthChecker{}
	dockerContainers := dockertools.DockerContainers{
		"1234": &docker.APIContainers{
			// the k8s prefix is required for the kubelet to manage the container
			Names: []string{"/k8s_bar_foo.new.test"},
			ID:    "1234",
		},
		"9876": &docker.APIContainers{
			// network container
			Names: []string{"/k8s_net_foo.new.test_"},
			ID:    "9876",
		},
	}
	err := kubelet.syncPod(&api.BoundPod{
		ObjectMeta: api.ObjectMeta{
			Name:        "foo",
			Namespace:   "new",
			Annotations: map[string]string{ConfigSourceAnnotationKey: "test"},
		},
		Spec: api.PodSpec{
			Containers: []api.Container{
				{Name: "bar",
					LivenessProbe: &api.LivenessProbe{
					// Always returns healthy == false
					},
				},
			},
		},
	}, dockerContainers)
	if err != nil {
		t.Errorf("unexpected error: %v", err)
	}

	verifyCalls(t, fakeDocker, []string{"list", "stop", "stop", "list", "create", "start"})

	// A map interation is used to delete containers, so must not depend on
	// order here.
	expectedToStop := map[string]bool{
		"1234": true,
		"9876": true,
	}
	if len(fakeDocker.Stopped) != 2 ||
		(!expectedToStop[fakeDocker.Stopped[0]] &&
			expectedToStop[fakeDocker.Stopped[0]]) {
		t.Errorf("Wrong containers were stopped: %v", fakeDocker.Stopped)
	}
}

func TestMakeEnvVariables(t *testing.T) {
	container := api.Container{
		Env: []api.EnvVar{
			{
				Name:  "foo",
				Value: "bar",
			},
			{
				Name:  "baz",
				Value: "blah",
			},
		},
	}
	vars := makeEnvironmentVariables(&container)
	if len(vars) != len(container.Env) {
		t.Errorf("Vars don't match.  Expected: %#v Found: %#v", container.Env, vars)
	}
	for ix, env := range container.Env {
		value := fmt.Sprintf("%s=%s", env.Name, env.Value)
		if value != vars[ix] {
			t.Errorf("Unexpected value: %s.  Expected: %s", vars[ix], value)
		}
	}
}

func TestMountExternalVolumes(t *testing.T) {
	kubelet, _, _ := newTestKubelet(t)
	pod := api.BoundPod{
		ObjectMeta: api.ObjectMeta{
			Name:      "foo",
			Namespace: "test",
		},
		Spec: api.PodSpec{
			Volumes: []api.Volume{
				{
					Name: "host-dir",
					Source: &api.VolumeSource{
						HostDir: &api.HostDir{"/dir/path"},
					},
				},
			},
		},
	}
	podVolumes, _ := kubelet.mountExternalVolumes(&pod)
	expectedPodVolumes := make(volumeMap)
	expectedPodVolumes["host-dir"] = &volume.HostDir{"/dir/path"}
	if len(expectedPodVolumes) != len(podVolumes) {
		t.Errorf("Unexpected volumes. Expected %#v got %#v.  Manifest was: %#v", expectedPodVolumes, podVolumes, pod)
	}
	for name, expectedVolume := range expectedPodVolumes {
		if _, ok := podVolumes[name]; !ok {
			t.Errorf("api.BoundPod volumes map is missing key: %s. %#v", expectedVolume, podVolumes)
		}
	}
}

func TestMakeVolumesAndBinds(t *testing.T) {
	container := api.Container{
		VolumeMounts: []api.VolumeMount{
			{
				MountPath: "/mnt/path",
				Name:      "disk",
				ReadOnly:  false,
			},
			{
				MountPath: "/mnt/path3",
				Name:      "disk",
				ReadOnly:  true,
			},
			{
				MountPath: "/mnt/path4",
				Name:      "disk4",
				ReadOnly:  false,
			},
			{
				MountPath: "/mnt/path5",
				Name:      "disk5",
				ReadOnly:  false,
			},
		},
	}

	pod := api.BoundPod{
		ObjectMeta: api.ObjectMeta{
			Name:      "pod",
			Namespace: "test",
		},
	}

	podVolumes := volumeMap{
		"disk":  &volume.HostDir{"/mnt/disk"},
		"disk4": &volume.HostDir{"/mnt/host"},
		"disk5": &volume.EmptyDir{"disk5", "podID", "/var/lib/kubelet"},
	}

	binds := makeBinds(&pod, &container, podVolumes)

	expectedBinds := []string{
		"/mnt/disk:/mnt/path",
		"/mnt/disk:/mnt/path3:ro",
		"/mnt/host:/mnt/path4",
		"/var/lib/kubelet/podID/volumes/empty/disk5:/mnt/path5",
	}

	if len(binds) != len(expectedBinds) {
		t.Errorf("Unexpected binds: Expected %#v got %#v.  Container was: %#v", expectedBinds, binds, container)
	}
	verifyStringArrayEquals(t, binds, expectedBinds)
}

func TestMakePortsAndBindings(t *testing.T) {
	container := api.Container{
		Ports: []api.Port{
			{
				ContainerPort: 80,
				HostPort:      8080,
				HostIP:        "127.0.0.1",
			},
			{
				ContainerPort: 443,
				HostPort:      443,
				Protocol:      "tcp",
			},
			{
				ContainerPort: 444,
				HostPort:      444,
				Protocol:      "udp",
			},
			{
				ContainerPort: 445,
				HostPort:      445,
				Protocol:      "foobar",
			},
		},
	}
	exposedPorts, bindings := makePortsAndBindings(&container)
	if len(container.Ports) != len(exposedPorts) ||
		len(container.Ports) != len(bindings) {
		t.Errorf("Unexpected ports and bindings, %#v %#v %#v", container, exposedPorts, bindings)
	}
	for key, value := range bindings {
		switch value[0].HostPort {
		case "8080":
			if !reflect.DeepEqual(docker.Port("80/tcp"), key) {
				t.Errorf("Unexpected docker port: %#v", key)
			}
			if value[0].HostIp != "127.0.0.1" {
				t.Errorf("Unexpected host IP: %s", value[0].HostIp)
			}
		case "443":
			if !reflect.DeepEqual(docker.Port("443/tcp"), key) {
				t.Errorf("Unexpected docker port: %#v", key)
			}
			if value[0].HostIp != "" {
				t.Errorf("Unexpected host IP: %s", value[0].HostIp)
			}
		case "444":
			if !reflect.DeepEqual(docker.Port("444/udp"), key) {
				t.Errorf("Unexpected docker port: %#v", key)
			}
			if value[0].HostIp != "" {
				t.Errorf("Unexpected host IP: %s", value[0].HostIp)
			}
		case "445":
			if !reflect.DeepEqual(docker.Port("445/tcp"), key) {
				t.Errorf("Unexpected docker port: %#v", key)
			}
			if value[0].HostIp != "" {
				t.Errorf("Unexpected host IP: %s", value[0].HostIp)
			}
		}
	}
}

func TestCheckHostPortConflicts(t *testing.T) {
	successCaseAll := []api.BoundPod{
		{Spec: api.PodSpec{Containers: []api.Container{{Ports: []api.Port{{HostPort: 80}}}}}},
		{Spec: api.PodSpec{Containers: []api.Container{{Ports: []api.Port{{HostPort: 81}}}}}},
		{Spec: api.PodSpec{Containers: []api.Container{{Ports: []api.Port{{HostPort: 82}}}}}},
	}
	successCaseNew := api.BoundPod{
		Spec: api.PodSpec{Containers: []api.Container{{Ports: []api.Port{{HostPort: 83}}}}},
	}
	expected := append(successCaseAll, successCaseNew)
	if actual := filterHostPortConflicts(expected); !reflect.DeepEqual(actual, expected) {
		t.Errorf("Expected %#v, Got %#v", expected, actual)
	}

	failureCaseAll := []api.BoundPod{
		{Spec: api.PodSpec{Containers: []api.Container{{Ports: []api.Port{{HostPort: 80}}}}}},
		{Spec: api.PodSpec{Containers: []api.Container{{Ports: []api.Port{{HostPort: 81}}}}}},
		{Spec: api.PodSpec{Containers: []api.Container{{Ports: []api.Port{{HostPort: 82}}}}}},
	}
	failureCaseNew := api.BoundPod{
		Spec: api.PodSpec{Containers: []api.Container{{Ports: []api.Port{{HostPort: 81}}}}},
	}
	if actual := filterHostPortConflicts(append(failureCaseAll, failureCaseNew)); !reflect.DeepEqual(failureCaseAll, actual) {
		t.Errorf("Expected %#v, Got %#v", expected, actual)
	}
}

type mockCadvisorClient struct {
	mock.Mock
}

// ContainerInfo is a mock implementation of CadvisorInterface.ContainerInfo.
func (c *mockCadvisorClient) ContainerInfo(name string, req *info.ContainerInfoRequest) (*info.ContainerInfo, error) {
	args := c.Called(name, req)
	return args.Get(0).(*info.ContainerInfo), args.Error(1)
}

// DockerContainer is a mock implementation of CadvisorInterface.DockerContainer.
func (c *mockCadvisorClient) DockerContainer(name string, req *info.ContainerInfoRequest) (info.ContainerInfo, error) {
	args := c.Called(name, req)
	return args.Get(0).(info.ContainerInfo), args.Error(1)
}

// MachineInfo is a mock implementation of CadvisorInterface.MachineInfo.
func (c *mockCadvisorClient) MachineInfo() (*info.MachineInfo, error) {
	args := c.Called()
	return args.Get(0).(*info.MachineInfo), args.Error(1)
}

func TestGetContainerInfo(t *testing.T) {
	containerID := "ab2cdf"
	containerPath := fmt.Sprintf("/docker/%v", containerID)
	containerInfo := info.ContainerInfo{
		ContainerReference: info.ContainerReference{
			Name: containerPath,
		},
	}

	mockCadvisor := &mockCadvisorClient{}
	cadvisorReq := &info.ContainerInfoRequest{}
	mockCadvisor.On("DockerContainer", containerID, cadvisorReq).Return(containerInfo, nil)

	kubelet, _, fakeDocker := newTestKubelet(t)
	kubelet.cadvisorClient = mockCadvisor
	fakeDocker.ContainerList = []docker.APIContainers{
		{
			ID: containerID,
			// pod id: qux
			// container id: foo
			Names: []string{"/k8s_foo_qux_1234"},
		},
	}

	stats, err := kubelet.GetContainerInfo("qux", "", "foo", cadvisorReq)
	if err != nil {
		t.Errorf("unexpected error: %v", err)
	}
	if stats == nil {
		t.Fatalf("stats should not be nil")
	}
	mockCadvisor.AssertExpectations(t)
}

func TestGetRootInfo(t *testing.T) {
	containerPath := "/"
	containerInfo := &info.ContainerInfo{
		ContainerReference: info.ContainerReference{
			Name: containerPath,
		},
	}
	fakeDocker := dockertools.FakeDockerClient{}

	mockCadvisor := &mockCadvisorClient{}
	cadvisorReq := &info.ContainerInfoRequest{}
	mockCadvisor.On("ContainerInfo", containerPath, cadvisorReq).Return(containerInfo, nil)

	kubelet := Kubelet{
		dockerClient:   &fakeDocker,
		dockerPuller:   &dockertools.FakeDockerPuller{},
		cadvisorClient: mockCadvisor,
		podWorkers:     newPodWorkers(),
	}

	// If the container name is an empty string, then it means the root container.
	_, err := kubelet.GetRootInfo(cadvisorReq)
	if err != nil {
		t.Errorf("unexpected error: %v", err)
	}
	mockCadvisor.AssertExpectations(t)
}

func TestGetContainerInfoWithoutCadvisor(t *testing.T) {
	kubelet, _, fakeDocker := newTestKubelet(t)
	fakeDocker.ContainerList = []docker.APIContainers{
		{
			ID: "foobar",
			// pod id: qux
			// container id: foo
			Names: []string{"/k8s_foo_qux_uuid_1234"},
		},
	}

	stats, _ := kubelet.GetContainerInfo("qux", "uuid", "foo", nil)
	// When there's no cAdvisor, the stats should be either nil or empty
	if stats == nil {
		return
	}
}

func TestGetContainerInfoWhenCadvisorFailed(t *testing.T) {
	containerID := "ab2cdf"

	containerInfo := info.ContainerInfo{}
	mockCadvisor := &mockCadvisorClient{}
	cadvisorReq := &info.ContainerInfoRequest{}
	expectedErr := fmt.Errorf("some error")
	mockCadvisor.On("DockerContainer", containerID, cadvisorReq).Return(containerInfo, expectedErr)

	kubelet, _, fakeDocker := newTestKubelet(t)
	kubelet.cadvisorClient = mockCadvisor
	fakeDocker.ContainerList = []docker.APIContainers{
		{
			ID: containerID,
			// pod id: qux
			// container id: foo
			Names: []string{"/k8s_foo_qux_uuid_1234"},
		},
	}

	stats, err := kubelet.GetContainerInfo("qux", "uuid", "foo", cadvisorReq)
	if stats != nil {
		t.Errorf("non-nil stats on error")
	}
	if err == nil {
		t.Errorf("expect error but received nil error")
		return
	}
	if err.Error() != expectedErr.Error() {
		t.Errorf("wrong error message. expect %v, got %v", err, expectedErr)
	}
	mockCadvisor.AssertExpectations(t)
}

func TestGetContainerInfoOnNonExistContainer(t *testing.T) {
	mockCadvisor := &mockCadvisorClient{}

	kubelet, _, fakeDocker := newTestKubelet(t)
	kubelet.cadvisorClient = mockCadvisor
	fakeDocker.ContainerList = []docker.APIContainers{}

	stats, _ := kubelet.GetContainerInfo("qux", "", "foo", nil)
	if stats != nil {
		t.Errorf("non-nil stats on non exist container")
	}
	mockCadvisor.AssertExpectations(t)
}

type fakeContainerCommandRunner struct {
	Cmd []string
	ID  string
	E   error
}

func (f *fakeContainerCommandRunner) RunInContainer(id string, cmd []string) ([]byte, error) {
	f.Cmd = cmd
	f.ID = id
	return []byte{}, f.E
}

func TestRunInContainerNoSuchPod(t *testing.T) {
	fakeCommandRunner := fakeContainerCommandRunner{}
	kubelet, _, fakeDocker := newTestKubelet(t)
	fakeDocker.ContainerList = []docker.APIContainers{}
	kubelet.runner = &fakeCommandRunner

	podName := "podFoo"
	podNamespace := "etcd"
	containerName := "containerFoo"
	output, err := kubelet.RunInContainer(
		GetPodFullName(&api.BoundPod{ObjectMeta: api.ObjectMeta{Name: podName, Namespace: podNamespace}}),
		"",
		containerName,
		[]string{"ls"})
	if output != nil {
		t.Errorf("unexpected non-nil command: %v", output)
	}
	if err == nil {
		t.Error("unexpected non-error")
	}
}

func TestRunInContainer(t *testing.T) {
	fakeCommandRunner := fakeContainerCommandRunner{}
	kubelet, _, fakeDocker := newTestKubelet(t)
	kubelet.runner = &fakeCommandRunner

	containerID := "abc1234"
	podName := "podFoo"
	podNamespace := "etcd"
	containerName := "containerFoo"

	fakeDocker.ContainerList = []docker.APIContainers{
		{
			ID:    containerID,
			Names: []string{"/k8s_" + containerName + "_" + podName + "." + podNamespace + ".test_1234"},
		},
	}

	cmd := []string{"ls"}
	_, err := kubelet.RunInContainer(
		GetPodFullName(&api.BoundPod{
			ObjectMeta: api.ObjectMeta{
				Name:        podName,
				Namespace:   podNamespace,
				Annotations: map[string]string{ConfigSourceAnnotationKey: "test"},
			},
		}),
		"",
		containerName,
		cmd)
	if fakeCommandRunner.ID != containerID {
		t.Errorf("unexected Name: %s", fakeCommandRunner.ID)
	}
	if !reflect.DeepEqual(fakeCommandRunner.Cmd, cmd) {
		t.Errorf("unexpected commnd: %s", fakeCommandRunner.Cmd)
	}
	if err != nil {
		t.Errorf("unexpected error: %v", err)
	}
}

func TestRunHandlerExec(t *testing.T) {
	fakeCommandRunner := fakeContainerCommandRunner{}
	kubelet, _, fakeDocker := newTestKubelet(t)
	kubelet.runner = &fakeCommandRunner

	containerID := "abc1234"
	podName := "podFoo"
	podNamespace := "etcd"
	containerName := "containerFoo"

	fakeDocker.ContainerList = []docker.APIContainers{
		{
			ID:    containerID,
			Names: []string{"/k8s_" + containerName + "_" + podName + "." + podNamespace + "_1234"},
		},
	}

	container := api.Container{
		Name: containerName,
		Lifecycle: &api.Lifecycle{
			PostStart: &api.Handler{
				Exec: &api.ExecAction{
					Command: []string{"ls", "-a"},
				},
			},
		},
	}
	err := kubelet.runHandler(podName+"."+podNamespace, "", &container, container.Lifecycle.PostStart)
	if err != nil {
		t.Errorf("unexpected error: %v", err)
	}
	if fakeCommandRunner.ID != containerID ||
		!reflect.DeepEqual(container.Lifecycle.PostStart.Exec.Command, fakeCommandRunner.Cmd) {
		t.Errorf("unexpected commands: %v", fakeCommandRunner)
	}
}

type fakeHTTP struct {
	url string
	err error
}

func (f *fakeHTTP) Get(url string) (*http.Response, error) {
	f.url = url
	return nil, f.err
}

func TestRunHandlerHttp(t *testing.T) {
	fakeHttp := fakeHTTP{}

	kubelet, _, _ := newTestKubelet(t)
	kubelet.httpClient = &fakeHttp

	podName := "podFoo"
	podNamespace := "etcd"
	containerName := "containerFoo"

	container := api.Container{
		Name: containerName,
		Lifecycle: &api.Lifecycle{
			PostStart: &api.Handler{
				HTTPGet: &api.HTTPGetAction{
					Host: "foo",
					Port: util.IntOrString{IntVal: 8080, Kind: util.IntstrInt},
					Path: "bar",
				},
			},
		},
	}
	err := kubelet.runHandler(podName+"."+podNamespace, "", &container, container.Lifecycle.PostStart)
	if err != nil {
		t.Errorf("unexpected error: %v", err)
	}
	if fakeHttp.url != "http://foo:8080/bar" {
		t.Errorf("unexpected url: %s", fakeHttp.url)
	}
}

func TestNewHandler(t *testing.T) {
	kubelet, _, _ := newTestKubelet(t)
	handler := &api.Handler{
		HTTPGet: &api.HTTPGetAction{
			Host: "foo",
			Port: util.IntOrString{IntVal: 8080, Kind: util.IntstrInt},
			Path: "bar",
		},
	}
	actionHandler := kubelet.newActionHandler(handler)
	if actionHandler == nil {
		t.Error("unexpected nil action handler.")
	}

	handler = &api.Handler{
		Exec: &api.ExecAction{
			Command: []string{"ls", "-l"},
		},
	}
	actionHandler = kubelet.newActionHandler(handler)
	if actionHandler == nil {
		t.Error("unexpected nil action handler.")
	}

	handler = &api.Handler{}
	actionHandler = kubelet.newActionHandler(handler)
	if actionHandler != nil {
		t.Errorf("unexpected non-nil action handler: %v", actionHandler)
	}
}

func TestSyncPodEventHandlerFails(t *testing.T) {
	kubelet, _, fakeDocker := newTestKubelet(t)
	kubelet.httpClient = &fakeHTTP{
		err: fmt.Errorf("test error"),
	}
	dockerContainers := dockertools.DockerContainers{
		"9876": &docker.APIContainers{
			// network container
			Names: []string{"/k8s_net_foo.new.test_"},
			ID:    "9876",
		},
	}
	err := kubelet.syncPod(&api.BoundPod{
		ObjectMeta: api.ObjectMeta{
			Name:        "foo",
			Namespace:   "new",
			Annotations: map[string]string{ConfigSourceAnnotationKey: "test"},
		},
		Spec: api.PodSpec{
			Containers: []api.Container{
				{Name: "bar",
					Lifecycle: &api.Lifecycle{
						PostStart: &api.Handler{
							HTTPGet: &api.HTTPGetAction{
								Host: "does.no.exist",
								Port: util.IntOrString{IntVal: 8080, Kind: util.IntstrInt},
								Path: "bar",
							},
						},
					},
				},
			},
		},
	}, dockerContainers)
	if err != nil {
		t.Errorf("unexpected error: %v", err)
	}

	verifyCalls(t, fakeDocker, []string{"list", "list", "create", "start", "stop"})

	if len(fakeDocker.Stopped) != 1 {
		t.Errorf("Wrong containers were stopped: %v", fakeDocker.Stopped)
	}
}

func TestKubeletGarbageCollection(t *testing.T) {
	tests := []struct {
		containers       []docker.APIContainers
		containerDetails map[string]*docker.Container
		expectedRemoved  []string
	}{
		{
			containers: []docker.APIContainers{
				{
					// network container
					Names: []string{"/k8s_net_foo.new.test_.deadbeef"},
					ID:    "1876",
				},
				{
					// network container
					Names: []string{"/k8s_net_foo.new.test_.deadbeef"},
					ID:    "2876",
				},
				{
					// network container
					Names: []string{"/k8s_net_foo.new.test_.deadbeef"},
					ID:    "3876",
				},
				{
					// network container
					Names: []string{"/k8s_net_foo.new.test_.deadbeef"},
					ID:    "4876",
				},
				{
					// network container
					Names: []string{"/k8s_net_foo.new.test_.deadbeef"},
					ID:    "5876",
				},
				{
					// network container
					Names: []string{"/k8s_net_foo.new.test_.deadbeef"},
					ID:    "6876",
				},
			},
			containerDetails: map[string]*docker.Container{
				"1876": {
					State: docker.State{
						Running: false,
					},
					ID:      "1876",
					Created: time.Now(),
				},
			},
			expectedRemoved: []string{"1876"},
		},
		{
			containers: []docker.APIContainers{
				{
					// network container
					Names: []string{"/k8s_net_foo.new.test_.deadbeef"},
					ID:    "1876",
				},
				{
					// network container
					Names: []string{"/k8s_net_foo.new.test_.deadbeef"},
					ID:    "2876",
				},
				{
					// network container
					Names: []string{"/k8s_net_foo.new.test_.deadbeef"},
					ID:    "3876",
				},
				{
					// network container
					Names: []string{"/k8s_net_foo.new.test_.deadbeef"},
					ID:    "4876",
				},
				{
					// network container
					Names: []string{"/k8s_net_foo.new.test_.deadbeef"},
					ID:    "5876",
				},
				{
					// network container
					Names: []string{"/k8s_net_foo.new.test_.deadbeef"},
					ID:    "6876",
				},
				{
					// network container
					Names: []string{"/k8s_net_foo.new.test_.deadbeef"},
					ID:    "7876",
				},
			},
			containerDetails: map[string]*docker.Container{
				"1876": {
					State: docker.State{
						Running: true,
					},
					ID:      "1876",
					Created: time.Now(),
				},
				"2876": {
					State: docker.State{
						Running: false,
					},
					ID:      "2876",
					Created: time.Now(),
				},
			},
			expectedRemoved: []string{"2876"},
		},
		{
			containers: []docker.APIContainers{
				{
					// network container
					Names: []string{"/k8s_net_foo.new.test_.deadbeef"},
					ID:    "1876",
				},
			},
		},
	}
	for _, test := range tests {
		kubelet, _, fakeDocker := newTestKubelet(t)
		kubelet.maxContainerCount = 5
		fakeDocker.ContainerList = test.containers
		fakeDocker.ContainerMap = test.containerDetails
		fakeDocker.Container = &docker.Container{ID: "error", Created: time.Now()}
		err := kubelet.GarbageCollectContainers()
		if err != nil {
			t.Errorf("unexpected error: %v", err)
		}
		if !reflect.DeepEqual(fakeDocker.Removed, test.expectedRemoved) {
			t.Errorf("expected: %v, got: %v", test.expectedRemoved, fakeDocker.Removed)
		}
	}
}

func TestPurgeOldest(t *testing.T) {
	created := time.Now()
	tests := []struct {
		ids              []string
		containerDetails map[string]*docker.Container
		expectedRemoved  []string
	}{
		{
			ids: []string{"1", "2", "3", "4", "5"},
			containerDetails: map[string]*docker.Container{
				"1": {
					State: docker.State{
						Running: true,
					},
					ID:      "1",
					Created: created,
				},
				"2": {
					State: docker.State{
						Running: false,
					},
					ID:      "2",
					Created: created.Add(time.Second),
				},
				"3": {
					State: docker.State{
						Running: false,
					},
					ID:      "3",
					Created: created.Add(time.Second),
				},
				"4": {
					State: docker.State{
						Running: false,
					},
					ID:      "4",
					Created: created.Add(time.Second),
				},
				"5": {
					State: docker.State{
						Running: false,
					},
					ID:      "5",
					Created: created.Add(time.Second),
				},
			},
		},
		{
			ids: []string{"1", "2", "3", "4", "5", "6"},
			containerDetails: map[string]*docker.Container{
				"1": {
					State: docker.State{
						Running: false,
					},
					ID:      "1",
					Created: created.Add(time.Second),
				},
				"2": {
					State: docker.State{
						Running: false,
					},
					ID:      "2",
					Created: created.Add(time.Millisecond),
				},
				"3": {
					State: docker.State{
						Running: false,
					},
					ID:      "3",
					Created: created.Add(time.Second),
				},
				"4": {
					State: docker.State{
						Running: false,
					},
					ID:      "4",
					Created: created.Add(time.Second),
				},
				"5": {
					State: docker.State{
						Running: false,
					},
					ID:      "5",
					Created: created.Add(time.Second),
				},
				"6": {
					State: docker.State{
						Running: false,
					},
					ID:      "6",
					Created: created.Add(time.Second),
				},
			},
			expectedRemoved: []string{"2"},
		},
		{
			ids: []string{"1", "2", "3", "4", "5", "6", "7"},
			containerDetails: map[string]*docker.Container{
				"1": {
					State: docker.State{
						Running: false,
					},
					ID:      "1",
					Created: created.Add(time.Second),
				},
				"2": {
					State: docker.State{
						Running: false,
					},
					ID:      "2",
					Created: created.Add(time.Millisecond),
				},
				"3": {
					State: docker.State{
						Running: false,
					},
					ID:      "3",
					Created: created.Add(time.Second),
				},
				"4": {
					State: docker.State{
						Running: false,
					},
					ID:      "4",
					Created: created.Add(time.Second),
				},
				"5": {
					State: docker.State{
						Running: false,
					},
					ID:      "5",
					Created: created.Add(time.Second),
				},
				"6": {
					State: docker.State{
						Running: false,
					},
					ID:      "6",
					Created: created.Add(time.Microsecond),
				},
				"7": {
					State: docker.State{
						Running: false,
					},
					ID:      "7",
					Created: created.Add(time.Second),
				},
			},
			expectedRemoved: []string{"2", "6"},
		},
	}
	for _, test := range tests {
		kubelet, _, fakeDocker := newTestKubelet(t)
		kubelet.maxContainerCount = 5
		fakeDocker.ContainerMap = test.containerDetails
		kubelet.purgeOldest(test.ids)
		if !reflect.DeepEqual(fakeDocker.Removed, test.expectedRemoved) {
			t.Errorf("expected: %v, got: %v", test.expectedRemoved, fakeDocker.Removed)
		}
	}
}

func TestSyncPodsWithPullPolicy(t *testing.T) {
	kubelet, _, fakeDocker := newTestKubelet(t)
	puller := kubelet.dockerPuller.(*dockertools.FakeDockerPuller)
	puller.HasImages = []string{"existing_one", "want:latest"}
	kubelet.networkContainerImage = "custom_image_name"
	fakeDocker.ContainerList = []docker.APIContainers{}
	err := kubelet.SyncPods([]api.BoundPod{
		{
			ObjectMeta: api.ObjectMeta{
				Name:        "foo",
				Namespace:   "new",
				Annotations: map[string]string{ConfigSourceAnnotationKey: "test"},
			},
			Spec: api.PodSpec{
				Containers: []api.Container{
					{Name: "bar", Image: "pull_always_image", ImagePullPolicy: api.PullAlways},
					{Name: "bar1", Image: "pull_never_image", ImagePullPolicy: api.PullNever},
					{Name: "bar2", Image: "pull_if_not_present_image", ImagePullPolicy: api.PullIfNotPresent},
					{Name: "bar3", Image: "existing_one", ImagePullPolicy: api.PullIfNotPresent},
					{Name: "bar4", Image: "want:latest", ImagePullPolicy: api.PullIfNotPresent},
				},
			},
		},
	})
	if err != nil {
		t.Errorf("unexpected error: %v", err)
	}
	kubelet.drainWorkers()

	fakeDocker.Lock()

	if !reflect.DeepEqual(puller.ImagesPulled, []string{"custom_image_name", "pull_always_image", "pull_if_not_present_image", "want:latest"}) {
		t.Errorf("Unexpected pulled containers: %v", puller.ImagesPulled)
	}

	if len(fakeDocker.Created) != 6 {
		t.Errorf("Unexpected containers created %v", fakeDocker.Created)
	}
	fakeDocker.Unlock()
}


text:
package com.garyhu.citypickerdemo.widget.third;

import android.content.Context;
import android.support.v7.widget.LinearLayoutManager;

/**
 * 用来控制recyclerView可否滑动
 * Created by wing on 12/7/16.
 */
public class CtrlLinearLayoutManager extends LinearLayoutManager {
  private boolean isScrollEnabled = true;

  public CtrlLinearLayoutManager(Context context) {
    super(context);
  }

  public void setScrollEnabled(boolean flag) {
    this.isScrollEnabled = flag;
  }

  @Override
  public boolean canScrollVertically() {
    //Similarly you can customize "canScrollHorizontally()" for managing horizontal scroll
    return isScrollEnabled && super.canScrollVertically();
  }
}

redpajama_set_name: RedPajamaGithub


text:
package org.apache.hyracks.algebricks.core.algebra.base;

public interface OperatorAnnotations {
    // hints
    public static final String USE_HASH_GROUP_BY = "USE_HASH_GROUP_BY"; // -->
    public static final String USE_EXTERNAL_GROUP_BY = "USE_EXTERNAL_GROUP_BY"; // -->
    public static final String USE_STATIC_RANGE = "USE_STATIC_RANGE"; // -->
    public static final String USE_DYNAMIC_RANGE = "USE_DYNAMIC_RANGE";
    // Boolean
    public static final String CARDINALITY = "CARDINALITY"; // -->
    // Integer
    public static final String MAX_NUMBER_FRAMES = "MAX_NUMBER_FRAMES"; // -->
    // Integer
}


text:
using System;
using System.Runtime.InteropServices;

namespace Vanara.PInvoke
{
	public static partial class Shell32
	{
		/// One or more of the following flags used to support design mode, debugging, and testing scenarios.
		[PInvokeData("shobjidl_core.h", MSDNShortId = "NF:shobjidl_core.IApplicationActivationManager.ActivateApplication")]
		[Flags]
		public enum ACTIVATEOPTIONS
		{
			/// No flags are set.
			AO_NONE = 0,

			///
			/// The app is being activated for design mode, so it can't create its normal window. The creation of the app's window must be
			/// done by design tools that load the necessary components by communicating with a designer-specified service on the site chain
			/// established through the activation manager. Note that this means that the splash screen seen during regular activations
			/// won't be seen.
			/// <para>Note that you must enable debug mode on the app's package to succesfully use design mode.</para>
			///
			AO_DESIGNMODE = 0x1,

			/// Do not display an error dialog if the app fails to activate.
			AO_NOERRORUI = 0x2,

			///
			/// Do not display the app's splash screen when the app is activated. You must enable debug mode on the app's package when you
			/// use this flag; otherwise, the PLM will terminate the app after a few seconds.
			///
			AO_NOSPLASHSCREEN = 0x4,

			/// The application is being activated in prelaunch mode. This value is supported starting in Windows 10.
			AO_PRELAUNCH = 0x2000000
		}

		///
		/// Provides methods which activate Windows Store apps for the Launch, File, and Protocol extensions. You will normally use this
		/// interface in debuggers and design tools.
		///
		/// <remarks>
		/// <para>When to Implement</para>
		/// <para>
		/// Do not implement this interface yourself. Windows provides an implementation as part of the CApplicationActivationManager class.
		/// To get an instance of this class, call CoCreateInstance with the CLSID_ApplicationActivationManager class ID.
		/// </para>
		/// <para>Usage notes</para>
		/// <para>
		/// An <c>IApplicationActivationManager</c> object creates a thread in its host process to serve any activated event arguments
		/// objects (LaunchActivatedEventArgs, FileActivatedEventArgs, and ProtocolActivatedEventArgs) that are passed to the app. If the
		/// calling process is long-lived, you can create this object in-proc, based on the assumption that the event arguments will exist
		/// long enough for the target app to use them. However, if the calling process is spawned only to launch the target app, it should
		/// create the <c>IApplicationActivationManager</c> object out-of-process, by using CLSCTX_LOCAL_SERVER. This causes the object to
		/// be created in a Dllhost.exe instance that automatically manages the object's lifetime based on outstanding references to the
		/// activated event argument objects.
		/// </para>
		/// </remarks>
		// https://docs.microsoft.com/en-us/windows/win32/api/shobjidl_core/nn-shobjidl_core-iapplicationactivationmanager
		[PInvokeData("shobjidl_core.h", MSDNShortId = "NN:shobjidl_core.IApplicationActivationManager")]
		[ComImport, Guid("2e941141-7f97-4756-ba1d-9decde894a3d"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown), CoClass(typeof(ApplicationActivationManager))]
		public interface IApplicationActivationManager
		{
			/// Activates the specified Windows Store app for the generic launch contract (Windows.Launch) in the current session.
			/// <param name="appUserModelId">The application user model ID of the Windows Store app.</param>
			/// <param name="arguments">A pointer to an optional, app-specific, argument string.</param>
			/// <param name="options">
			/// <para>One or more of the following flags used to support design mode, debugging, and testing scenarios.</para>
			/// <para>AO_NONE (0x00000000)</para>
			/// <para>No flags are set.</para>
			/// <para>AO_DESIGNMODE (0x00000001)</para>
			/// <para>
			/// The app is being activated for design mode, so it can't create its normal window. The creation of the app's window must be
			/// done by design tools that load the necessary components by communicating with a designer-specified service on the site chain
			/// established through the activation manager. Note that this means that the splash screen seen during regular activations
			/// won't be seen.
			/// </para>
			/// <para>Note that you must enable debug mode on the app's package to succesfully use design mode.</para>
			/// <para>AO_NOERRORUI (0x00000002)</para>
			/// <para>Do not display an error dialog if the app fails to activate.</para>
			/// <para>AO_NOSPLASHSCREEN (0x00000004)</para>
			/// <para>
			/// Do not display the app's splash screen when the app is activated. You must enable debug mode on the app's package when you
			/// use this flag; otherwise, the PLM will terminate the app after a few seconds.
			/// </para>
			/// <para>AO_PRELAUNCH (0x2000000)</para>
			/// <para>The application is being activated in prelaunch mode. This value is supported starting in Windows 10.</para>
			/// </param>
			/// <param name="processId">
			/// A pointer to a value that, when this method returns successfully, receives the process ID of the app instance that fulfils
			/// this contract.
			/// </param>
			/// <returns>If this method succeeds, it returns <c>S_OK</c>. Otherwise, it returns an <c>HRESULT</c> error code.</returns>
			// https://docs.microsoft.com/en-us/windows/win32/api/shobjidl_core/nf-shobjidl_core-iapplicationactivationmanager-activateapplication
			// HRESULT ActivateApplication( LPCWSTR appUserModelId, LPCWSTR arguments, ACTIVATEOPTIONS options, DWORD *processId );
			void ActivateApplication([MarshalAs(UnmanagedType.LPWStr)] string appUserModelId, [MarshalAs(UnmanagedType.LPWStr)] string arguments, ACTIVATEOPTIONS options, out uint processId);

			/// Activates the specified Windows Store app for the file contract (Windows.File).
			/// <param name="appUserModelId">The application user model ID of the Windows Store app.</param>
			/// <param name="itemArray">
			/// A pointer to an array of Shell items, each representing a file. This value is converted to a VectorView of StorageItem
			/// objects that is passed to the app through FileActivatedEventArgs.
			/// </param>
			/// <param name="verb">The verb being applied to the file or files specified by itemArray.</param>
			/// <param name="processId">
			/// A pointer to a value that, when this method returns successfully, receives the process ID of the app instance that fulfils
			/// this contract.
			/// </param>
			// https://docs.microsoft.com/en-us/windows/win32/api/shobjidl_core/nf-shobjidl_core-iapplicationactivationmanager-activateforfile
			// HRESULT ActivateForFile( LPCWSTR appUserModelId, IShellItemArray *itemArray, LPCWSTR verb, DWORD *processId );
			void ActivateForFile([MarshalAs(UnmanagedType.LPWStr)] string appUserModelId, IShellItemArray itemArray, [MarshalAs(UnmanagedType.LPWStr)] string verb, out uint processId);

			/// Activates the specified Windows Store app for the protocol contract (Windows.Protocol).
			/// <param name="appUserModelId">The application user model ID of the Windows Store app.</param>
			/// <param name="itemArray">
			/// A pointer to an array of a single Shell item. The first item in the array is converted into a Uri object that is passed to
			/// the app through ProtocolActivatedEventArgs. Any items in the array except for the first element are ignored.
			/// </param>
			/// <param name="processId">
			/// A pointer to a value that, when this method returns successfully, receives the process ID of the app instance that fulfils
			/// this contract.
			/// </param>
			// https://docs.microsoft.com/en-us/windows/win32/api/shobjidl_core/nf-shobjidl_core-iapplicationactivationmanager-activateforprotocol
			// HRESULT ActivateForProtocol( LPCWSTR appUserModelId, IShellItemArray *itemArray, DWORD *processId );
			void ActivateForProtocol([MarshalAs(UnmanagedType.LPWStr)] string appUserModelId, IShellItemArray itemArray, out uint processId);
		}

		/// CLSID_ApplicationActivationManager
		[PInvokeData("shobjidl_core.h", MSDNShortId = "NN:shobjidl_core.IDesktopWallpaper")]
		[ComImport, Guid("45BA127D-10A8-46EA-8AB7-56EA9078943C"), ClassInterface(ClassInterfaceType.None)]
		public class ApplicationActivationManager { }
	}
}


text:
package sha1

import (
	"crypto/sha1"
)

const (
	BlockSize = sha1.BlockSize
	Size      = sha1.Size
)

type Hasher interface {
	Write(data []byte) (n int, err error)
	Sum() ([Size]byte, error)
	Close()
}

func SHA1(data []byte) (result [Size]byte, err error) {
	hash, err := New()
	if err != nil {
		return result, err
	}
	defer hash.Close()
	if _, err := hash.Write(data); err != nil {
		return result, err
	}
	return hash.Sum()
}


text:
Packages Brython
================
_Nouveau en version 3.7.5_

Un "package Brython" peut être inséré dans la page HTML pour donner accès à
des modules importables. Il s'agit d'un fichier avec l'extension
__`.brython.js`__ qui contient les modules et packages à distribuer; on
l'insère par la syntaxe habituelle

```xml
<script src="http://anyhost/path/nom_package.brython.js"></script>
```

Les packages Brython peuvent être situés sur n'importe quel serveur, ce qui
rend leur déploiement et leur utilisation très simples.

Pour générer un "package Brython", il faut utiliser le package CPython
`brython` et, dans le répertoire où se situent les fichiers à inclure dans
le package, exécuter:

```console
brython-cli make_package <nom_package>
```

Si le répertoire contient un fichier __`__init.py__`__, les modules seront
relatifs à ce package. Par exemple si la structure du répertoire est

    __init__.py
    dialog.py
    menu.py

et qu'on veut générer le package __`widgets`__ à partir de ce répertoire,
alors les modules seront importés par

```python
import widgets.dialog
from widgets import menu
```

Si le répertoire ne contient pas __`__init__.py`__, les modules seront
importés par leur nom seul. Donc si le répertoire contient seulement

    dialog.py
    menu.py

les modules seront importés par
```python
import dialog
import menu
```


text:
({
    appDir: '.',

    baseUrl: 'lib',

    /**
     * Uncomment to turn off uglify minification.
     *
     * This can help for debugging templates...
     * /
    optimize: 'none',
    /**/

    dir: '../demo-build',

    paths: {
        tpl: '../../tpl'
    },

    /**
     * This removes the plugin from the build
     * As templates are functions and don't really need the plugin to work,
     * you can choose to exclude it and save some Ko
     *
     * The plugin will actually become an empty function and take about 64 bytes minified...
     *
     * Comment to turn off exclusion if you plan to use dynamic loading/compiling of templates
     *
     */
    pragmasOnSave: {
        excludeTpl: true
    },
    /**/

    modules: [
        {
            name: "main"
        }
    ]
})


text:
from keras.callbacks import Callback
from keras.models import Sequential
from sklearn.metrics import roc_auc_score, average_precision_score, \
    precision_score, recall_score

class EpochEvaluation(Callback):
    def __init__(self, validation_data=()):
        super(Callback, self).__init__()
        self.X_val, self.y_val = validation_data
        self.metrics = {}

    def on_epoch_begin(self, epoch, logs={}):
        if epoch > 0:
            print(" - ".join(["val_{:s}: {:.4f}".format(k, v)
                              for k, v in self.metrics.items()]))

    def on_epoch_end(self, epoch, logs={}):
        if isinstance(self.model, Sequential):
            predict = self.model.predict_proba
        else:
            predict = self.model.predict

        y_pred = predict(self.X_val, verbose=0)
        y_pred_bin = y_pred > 0.5

        y_true = self.y_val
        self.metrics['roc_auc'] = roc_auc_score(y_true, y_pred)
        self.metrics['pr_auc'] = average_precision_score(
            y_true, y_pred, average="micro")
        self.metrics['recall'] = recall_score(y_true, y_pred_bin)
        self.metrics['precision'] = precision_score(y_true, y_pred_bin)


text:
use std::os::raw::c_void;
use std::path::Path;

use libc;
use winapi::shared::minwindef::WORD;
use winapi::shared::windef::{HMENU, HWND};

use crate::{
    dpi::PhysicalSize,
    event::DeviceId,
    event_loop::EventLoop,
    monitor::MonitorHandle,
    platform_impl::{EventLoop as WindowsEventLoop, Parent, WinIcon},
    window::{BadIcon, Icon, Theme, Window, WindowBuilder},
};

/// Additional methods on `EventLoop` that are specific to Windows.
pub trait EventLoopExtWindows {
    /// Creates an event loop off of the main thread.
    ///
    /// # `Window` caveats
    ///
    /// Note that any `Window` created on the new thread will be destroyed when the thread
    /// terminates. Attempting to use a `Window` after its parent thread terminates has
    /// unspecified, although explicitly not undefined, behavior.
    fn new_any_thread() -> Self
    where
        Self: Sized;

    /// By default, winit on Windows will attempt to enable process-wide DPI awareness. If that's
    /// undesirable, you can create an `EventLoop` using this function instead.
    fn new_dpi_unaware() -> Self
    where
        Self: Sized;

    /// Creates a DPI-unaware event loop off of the main thread.
    ///
    /// The `Window` caveats in [`new_any_thread`](EventLoopExtWindows::new_any_thread) also apply here.
    fn new_dpi_unaware_any_thread() -> Self
    where
        Self: Sized;
}

impl<T> EventLoopExtWindows for EventLoop<T> {
    #[inline]
    fn new_any_thread() -> Self {
        EventLoop {
            event_loop: WindowsEventLoop::new_any_thread(),
            _marker: ::std::marker::PhantomData,
        }
    }

    #[inline]
    fn new_dpi_unaware() -> Self {
        EventLoop {
            event_loop: WindowsEventLoop::new_dpi_unaware(),
            _marker: ::std::marker::PhantomData,
        }
    }

    #[inline]
    fn new_dpi_unaware_any_thread() -> Self {
        EventLoop {
            event_loop: WindowsEventLoop::new_dpi_unaware_any_thread(),
            _marker: ::std::marker::PhantomData,
        }
    }
}

/// Additional methods on `Window` that are specific to Windows.
pub trait WindowExtWindows {
    /// Returns the HINSTANCE of the window
    fn hinstance(&self) -> *mut libc::c_void;
    /// Returns the native handle that is used by this window.
    ///
    /// The pointer will become invalid when the native window was destroyed.
    fn hwnd(&self) -> *mut libc::c_void;

    /// Enables or disables mouse and keyboard input to the specified window.
    ///
    /// A window must be enabled before it can be activated.
    /// If an application has create a modal dialog box by disabling its owner window
    /// (as described in [`WindowBuilderExtWindows::with_owner_window`]), the application must enable
    /// the owner window before destroying the dialog box.
    /// Otherwise, another window will receive the keyboard focus and be activated.
    ///
    /// If a child window is disabled, it is ignored when the system tries to determine which
    /// window should receive mouse messages.
    ///
    /// For more information, see <https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-enablewindow#remarks>
    /// and <https://docs.microsoft.com/en-us/windows/win32/winmsg/window-features#disabled-windows>
    fn set_enable(&self, enabled: bool);

    /// This sets `ICON_BIG`. A good ceiling here is 256x256.
    fn set_taskbar_icon(&self, taskbar_icon: Option<Icon>);

    /// Returns the current window theme.
    fn theme(&self) -> Theme;
}

impl WindowExtWindows for Window {
    #[inline]
    fn hinstance(&self) -> *mut libc::c_void {
        self.window.hinstance() as *mut _
    }

    #[inline]
    fn hwnd(&self) -> *mut libc::c_void {
        self.window.hwnd() as *mut _
    }

    #[inline]
    fn set_enable(&self, enabled: bool) {
        unsafe {
            winapi::um::winuser::EnableWindow(self.hwnd() as _, enabled as _);
        }
    }

    #[inline]
    fn set_taskbar_icon(&self, taskbar_icon: Option<Icon>) {
        self.window.set_taskbar_icon(taskbar_icon)
    }

    #[inline]
    fn theme(&self) -> Theme {
        self.window.theme()
    }
}

/// Additional methods on `WindowBuilder` that are specific to Windows.
pub trait WindowBuilderExtWindows {
    /// Sets a parent to the window to be created.
    ///
    /// A child window has the WS_CHILD style and is confined to the client area of its parent window.
    ///
    /// For more information, see <https://docs.microsoft.com/en-us/windows/win32/winmsg/window-features#child-windows>
    fn with_parent_window(self, parent: HWND) -> WindowBuilder;

    /// Set an owner to the window to be created. Can be used to create a dialog box, for example.
    /// Can be used in combination with [`WindowExtWindows::set_enable(false)`](WindowExtWindows::set_enable)
    /// on the owner window to create a modal dialog box.
    ///
    /// From MSDN:
    /// - An owned window is always above its owner in the z-order.
    /// - The system automatically destroys an owned window when its owner is destroyed.
    /// - An owned window is hidden when its owner is minimized.
    ///
    /// For more information, see <https://docs.microsoft.com/en-us/windows/win32/winmsg/window-features#owned-windows>
    fn with_owner_window(self, parent: HWND) -> WindowBuilder;

    /// Sets a menu on the window to be created.
    ///
    /// Parent and menu are mutually exclusive; a child window cannot have a menu!
    ///
    /// The menu must have been manually created beforehand with [`winapi::um::winuser::CreateMenu`] or similar.
    ///
    /// Note: Dark mode cannot be supported for win32 menus, it's simply not possible to change how the menus look.
    /// If you use this, it is recommended that you combine it with `with_theme(Some(Theme::Light))` to avoid a jarring effect.
    fn with_menu(self, menu: HMENU) -> WindowBuilder;

    /// This sets `ICON_BIG`. A good ceiling here is 256x256.
    fn with_taskbar_icon(self, taskbar_icon: Option<Icon>) -> WindowBuilder;

    /// This sets `WS_EX_NOREDIRECTIONBITMAP`.
    fn with_no_redirection_bitmap(self, flag: bool) -> WindowBuilder;

    /// Enables or disables drag and drop support (enabled by default). Will interfere with other crates
    /// that use multi-threaded COM API (`CoInitializeEx` with `COINIT_MULTITHREADED` instead of
    /// `COINIT_APARTMENTTHREADED`) on the same thread. Note that winit may still attempt to initialize
    /// COM API regardless of this option. Currently only fullscreen mode does that, but there may be more in the future.
    /// If you need COM API with `COINIT_MULTITHREADED` you must initialize it before calling any winit functions.
    /// See <https://docs.microsoft.com/en-us/windows/win32/api/objbase/nf-objbase-coinitialize#remarks> for more information.
    fn with_drag_and_drop(self, flag: bool) -> WindowBuilder;

    /// Forces a theme or uses the system settings if `None` was provided.
    fn with_theme(self, theme: Option<Theme>) -> WindowBuilder;
}

impl WindowBuilderExtWindows for WindowBuilder {
    #[inline]
    fn with_parent_window(mut self, parent: HWND) -> WindowBuilder {
        self.platform_specific.parent = Parent::ChildOf(parent);
        self
    }

    #[inline]
    fn with_owner_window(mut self, parent: HWND) -> WindowBuilder {
        self.platform_specific.parent = Parent::OwnedBy(parent);
        self
    }

    #[inline]
    fn with_menu(mut self, menu: HMENU) -> WindowBuilder {
        self.platform_specific.menu = Some(menu);
        self
    }

    #[inline]
    fn with_taskbar_icon(mut self, taskbar_icon: Option<Icon>) -> WindowBuilder {
        self.platform_specific.taskbar_icon = taskbar_icon;
        self
    }

    #[inline]
    fn with_no_redirection_bitmap(mut self, flag: bool) -> WindowBuilder {
        self.platform_specific.no_redirection_bitmap = flag;
        self
    }

    #[inline]
    fn with_drag_and_drop(mut self, flag: bool) -> WindowBuilder {
        self.platform_specific.drag_and_drop = flag;
        self
    }

    #[inline]
    fn with_theme(mut self, theme: Option<Theme>) -> WindowBuilder {
        self.platform_specific.preferred_theme = theme;
        self
    }
}

/// Additional methods on `MonitorHandle` that are specific to Windows.
pub trait MonitorHandleExtWindows {
    /// Returns the name of the monitor adapter specific to the Win32 API.
    fn native_id(&self) -> String;

    /// Returns the handle of the monitor - `HMONITOR`.
    fn hmonitor(&self) -> *mut c_void;
}

impl MonitorHandleExtWindows for MonitorHandle {
    #[inline]
    fn native_id(&self) -> String {
        self.inner.native_identifier()
    }

    #[inline]
    fn hmonitor(&self) -> *mut c_void {
        self.inner.hmonitor() as *mut _
    }
}

/// Additional methods on `DeviceId` that are specific to Windows.
pub trait DeviceIdExtWindows {
    /// Returns an identifier that persistently refers to this specific device.
    ///
    /// Will return `None` if the device is no longer available.
    fn persistent_identifier(&self) -> Option<String>;
}

impl DeviceIdExtWindows for DeviceId {
    #[inline]
    fn persistent_identifier(&self) -> Option<String> {
        self.0.persistent_identifier()
    }
}

/// Additional methods on `Icon` that are specific to Windows.
pub trait IconExtWindows: Sized {
    /// Create an icon from a file path.
    ///
    /// Specify `size` to load a specific icon size from the file, or `None` to load the default
    /// icon size from the file.
    ///
    /// In cases where the specified size does not exist in the file, Windows may perform scaling
    /// to get an icon of the desired size.
    fn from_path<P: AsRef<Path>>(path: P, size: Option<PhysicalSize<u32>>)
        -> Result<Self, BadIcon>;

    /// Create an icon from a resource embedded in this executable or library.
    ///
    /// Specify `size` to load a specific icon size from the file, or `None` to load the default
    /// icon size from the file.
    ///
    /// In cases where the specified size does not exist in the file, Windows may perform scaling
    /// to get an icon of the desired size.
    fn from_resource(ordinal: WORD, size: Option<PhysicalSize<u32>>) -> Result<Self, BadIcon>;
}

impl IconExtWindows for Icon {
    fn from_path<P: AsRef<Path>>(
        path: P,
        size: Option<PhysicalSize<u32>>,
    ) -> Result<Self, BadIcon> {
        let win_icon = WinIcon::from_path(path, size)?;
        Ok(Icon { inner: win_icon })
    }

    fn from_resource(ordinal: WORD, size: Option<PhysicalSize<u32>>) -> Result<Self, BadIcon> {
        let win_icon = WinIcon::from_resource(ordinal, size)?;
        Ok(Icon { inner: win_icon })
    }
}


text:
namespace common
{

// TODO: boost::path
inline Result<std::string, std::string>
read_file(char const* path)
{
  // Read the Vertex Shader code from the file
  std::stringstream sstream;
  {
    std::ifstream istream(path, std::ios::in);

    if (!istream.is_open()) {
      return Err("Error opening file at path '" + std::string{path} + "'");
    }

    std::string buffer;
    bool        first = true;
    while (std::getline(istream, buffer)) {
      if (!first) {
        sstream << "\n";
      }
      else {
        first = false;
      }
      sstream << buffer;
    }
    // explicit, dtor should do this.
    istream.close();
  }
  return Ok(sstream.str());
}

template <typename T>
auto
read_file(T const s)
{
  return read_file(s.c_str());
}

// TODO: boost::path
template <typename... Text>
void
write_file(std::experimental::filesystem::path const& path, Text const&... text)
{
  std::filebuf fb;
  fb.open(path.string().c_str(), std::ios::out);
  ON_SCOPE_EXIT([&fb]() { fb.close(); });

  std::ostream os(&fb);
  auto const   write_line = [&os](auto const& text) { os << text; };

  auto const tuple_view = std::make_tuple(text...);
  common::tuple_for_each(tuple_view, write_line);
}

} // namespace common


text:
#include "CTiglBSplineApproxInterp.h"

#include <CTiglError.h>
#include <CTiglBSplineAlgorithms.h>

#include <TColgp_Array1OfPnt.hxx>
#include <Geom_BSplineCurve.hxx>
#include "tiglcommonfunctions.h"
#include <TColStd_HArray1OfInteger.hxx>
#include <TColStd_HArray1OfReal.hxx>

#include <algorithm>
#include <BSplCLib.hxx>
#include <math_Matrix.hxx>
#include <math_Gauss.hxx>

namespace
{

class helper_function_find
{
public:
    helper_function_find(double val, double tolerance = 1e-15)
        : _val(val), _tol(tolerance)
    {}

    // helper function for std::unique
    bool operator()(double a)
    {
        return (fabs(_val - a) < _tol);
    }
private:
    double _val;
    double _tol;
};

void insertKnot(double knot, int count, int degree, std::vector<double>& knots, std::vector<int>& mults, double tol = 1e-5)
{
    if (knot < knots.front() || knot > knots.back()) {
        throw tigl::CTiglError("knot out of range");
    }

    size_t pos = std::find_if(knots.begin(), knots.end(), helper_function_find(knot, tol)) - knots.begin();
    if (pos >= knots.size()) {
        // knot not found, insert new one
        pos = 0;
        while (knots[pos] < knot) {
            pos++;
        }
        knots.insert(knots.begin() + pos, knot);
        mults.insert(mults.begin() + pos, std::min(count, degree));
    }
    else {
        // knot found, increase multiplicity
        mults[pos] = std::min(mults[pos] + count, degree);
    }
}

}

namespace tigl
{

/**
 * @brief Copies the curve points
 */
CTiglBSplineApproxInterp::CTiglBSplineApproxInterp(const TColgp_Array1OfPnt& points, int nControlPoints, int degree, bool continuous_if_closed)
    : m_pnts(1, points.Length())
    , m_indexOfApproximated(static_cast<size_t>(points.Length()))
    , m_degree(degree)
    , m_ncp(nControlPoints)
    , m_C2Continuous(continuous_if_closed)
{
    for (Standard_Integer i = 0; i < points.Length(); ++i) {
        size_t idx = static_cast<size_t>(i);
        m_indexOfApproximated[idx] = idx;
        m_pnts.SetValue(i + 1, points.Value(points.Lower() + i));
    }
}

void CTiglBSplineApproxInterp::InterpolatePoint(size_t pointIndex, bool withKink)
{
    std::vector<size_t>::iterator it = std::find(m_indexOfApproximated.begin(), m_indexOfApproximated.end(), pointIndex);
    if (it == m_indexOfApproximated.end()) {
        throw CTiglError("Invalid index in CTiglBSplineApproxInterp::InterpolatePoint", TIGL_INDEX_ERROR);
    }
    m_indexOfApproximated.erase(it);

    m_indexOfInterpolated.push_back(pointIndex);
    if (withKink) {
        m_indexOfKinks.push_back(pointIndex);
    }
}

double CTiglBSplineApproxInterp::maxDistanceOfBoundingBox(const TColgp_Array1OfPnt& points) const
{
    gp_Pnt max(-DBL_MAX, -DBL_MAX, -DBL_MAX);
    gp_Pnt min(DBL_MAX, DBL_MAX, DBL_MAX);
    for (int i = points.Lower(); i <= points.Upper(); ++i) {
        const gp_Pnt& p = points.Value(i);
        max.SetX(std::max(max.X(), p.X()));
        max.SetY(std::max(max.Y(), p.Y()));
        max.SetZ(std::max(max.Z(), p.Z()));

        min.SetX(std::min(min.X(), p.X()));
        min.SetY(std::min(min.Y(), p.Y()));
        min.SetZ(std::min(min.Z(), p.Z()));
    }
    return max.Distance(min);
}

bool CTiglBSplineApproxInterp::isClosed() const
{
    if (!m_C2Continuous) {
        return false;
    }
    double maxDistance = maxDistanceOfBoundingBox(m_pnts);
    double error = 1e-12*maxDistance;
    return m_pnts.Value(m_pnts.Lower()).IsEqual(m_pnts.Value(m_pnts.Upper()), error);
}

bool CTiglBSplineApproxInterp::firstAndLastInterpolated() const
{
    bool first = std::find(m_indexOfInterpolated.begin(), m_indexOfInterpolated.end(), 0) != m_indexOfInterpolated.end();
    bool last = std::find(m_indexOfInterpolated.begin(), m_indexOfInterpolated.end(), m_pnts.Length() - 1) != m_indexOfInterpolated.end();
    return first && last;
}

std::vector<double> CTiglBSplineApproxInterp::computeParameters(double alpha) const
{
    double sum = 0.0;
    std::vector<double> t;

    size_t nPoints = static_cast<size_t>(m_pnts.Length());
    t.resize(nPoints);

    t[0] = 0.0;
    // calc total arc length: dt^2 = dx^2 + dy^2
    for (size_t i = 1; i < nPoints; i++) {
        Standard_Integer idx = static_cast<Standard_Integer>(i);
        double len2 = m_pnts.Value(idx).SquareDistance(m_pnts.Value(idx + 1));
        sum += pow(len2, alpha / 2.);
        t[i] = sum;
    }

    // normalize parameter with maximum
    double tmax = t[nPoints - 1];
    for (size_t i = 1; i < nPoints; i++) {
        t[i] /= tmax;
    }

    // reset end value to achieve a better accuracy
    t[nPoints - 1] = 1.0;
    return t;
}

void CTiglBSplineApproxInterp::computeKnots(int ncp, const std::vector<double>& parms, std::vector<double>& knots, std::vector<int>& mults) const
{
    int order = m_degree + 1;
    if (ncp < order) {
        throw CTiglError("Number of control points to small!", TIGL_MATH_ERROR);
    }

    double umin = *std::min_element(parms.begin(), parms.end());
    double umax = *std::max_element(parms.begin(), parms.end());

    knots.resize(static_cast<size_t>(ncp - m_degree + 1));
    mults.resize(static_cast<size_t>(ncp - m_degree + 1));

    // fill multiplicity at start
    knots[0] = umin;
    mults[0] = order;

    // number of knots between the multiplicities
    size_t N = (static_cast<size_t>(ncp - order));
    // set uniform knot distribution
    for (size_t i = 1; i <= N; ++i ) {
        knots[i] = umin + (umax - umin) * double(i) / double(N + 1);
        mults[i] = 1;
    }

    // fill multiplicity at end
    knots[N + 1] = umax;
    mults[N + 1] = order;

    for (std::vector<size_t>::const_iterator it = m_indexOfKinks.begin(); it != m_indexOfKinks.end(); ++it) {
        size_t idx = *it;
        insertKnot(parms[idx], m_degree, m_degree, knots, mults, 1e-4);
    }
}

CTiglApproxResult CTiglBSplineApproxInterp::FitCurve(const std::vector<double>& initialParms) const
{
    std::vector<double> parms;
    // compute initial parameters, if initialParms emtpy
    if (initialParms.empty()) {
        parms = computeParameters(0.5);
    }
    else {
        parms = initialParms;
    }

    if (parms.size() != static_cast<size_t>(m_pnts.Length())) {
        throw CTiglError("Number of parameters don't match number of points");
    }

    // Compute knots from parameters
    std::vector<double> knots;
    std::vector<int> mults;
    computeKnots(m_ncp, parms,
                 knots, mults);

    // solve system
    return solve(parms, OccFArray(knots)->Array1(), OccIArray(mults)->Array1());
}

CTiglApproxResult CTiglBSplineApproxInterp::FitCurveOptimal(const std::vector<double>& initialParms, int maxIter) const
{
    std::vector<double> parms;
    // compute initial parameters, if initialParms emtpy
    if (initialParms.empty()) {
        parms = computeParameters(0.5);
    }
    else {
        parms = initialParms;
    }

    if (parms.size() != static_cast<size_t>(m_pnts.Length())) {
        throw CTiglError("Number of parameters don't match number of points");
    }

    // Compute knots from parameters
    std::vector<double> knots;
    std::vector<int> mults;
    computeKnots(m_ncp, parms,
                 knots, mults);

    auto occMults = OccIArray(mults);
    auto occKnots = OccFArray(knots);

    int iteration = 0;

    // solve system
    CTiglApproxResult result = solve(parms, occKnots->Array1(), occMults->Array1());
    double old_error = result.error * 2.;

    while(result.error > 0 && (old_error - result.error) / std::max(result.error, 1e-6) > 1e-3 && iteration < maxIter) {
        old_error = result.error;

        optimizeParameters(result.curve, parms);
        result = solve(parms, occKnots->Array1(), occMults->Array1());

        iteration++;
    }

    return result;
}

ProjectResult CTiglBSplineApproxInterp::projectOnCurve(const gp_Pnt& pnt, const Handle(Geom_Curve) &curve, double initial_Parm) const
{
    const int maxIter = 10; // maximum No of iterations
    const double eps  = 1.0E-6; // accuracy of arc length parameter

    double t = initial_Parm;

    // newton step
    double dt = 0;

    double f = 0;

    int iter = 0; // iteration counter
    do { // Newton iteration to get a better t parameter

        // Get the derivatives of the spline wrt parameter t
        gp_Vec p   = curve->DN(t, 0);
        gp_Vec dp  = curve->DN(t, 1);
        gp_Vec d2p = curve->DN(t, 2);

        // compute objective function and their derivative
        f = pnt.SquareDistance(p.XYZ());

        double df = (p.XYZ() - pnt.XYZ()).Dot(dp.XYZ());
        double d2f = (p.XYZ() - pnt.XYZ()).Dot(d2p.XYZ()) + dp.SquareMagnitude();

        // newton iterate
        dt = -df / d2f;
        double t_new = t + dt;

        // if parameter out of range reset it to the start value
        if (t_new < curve->FirstParameter() || t_new > curve->LastParameter()) {
            t_new = initial_Parm;
            dt = 0.;
        }
        t = t_new;

        iter++;
    }
    while (fabs(dt) > eps && iter < maxIter);

    return ProjectResult(t, sqrt(f));
}

math_Matrix CTiglBSplineApproxInterp::getContinuityMatrix(int nCtrPnts, int contin_cons, const std::vector<double>& params, const TColStd_Array1OfReal& flatKnots) const
{
    math_Matrix continuity_entries(1, contin_cons, 1, nCtrPnts);
    continuity_entries.Init(0.);
    TColStd_Array1OfReal continuity_params1(params[0], 1, 1);
    TColStd_Array1OfReal continuity_params2(params[params.size() - 1], 1, 1);

    math_Matrix diff1_1 = CTiglBSplineAlgorithms::bsplineBasisMat(m_degree, flatKnots, continuity_params1, 1);
    math_Matrix diff1_2 = CTiglBSplineAlgorithms::bsplineBasisMat(m_degree, flatKnots, continuity_params2, 1);

    math_Matrix diff2_1 = CTiglBSplineAlgorithms::bsplineBasisMat(m_degree, flatKnots, continuity_params1, 2);
    math_Matrix diff2_2 = CTiglBSplineAlgorithms::bsplineBasisMat(m_degree, flatKnots, continuity_params2, 2);

    // Set C1 condition
    continuity_entries.Set(1, 1, 1, nCtrPnts, diff1_1 - diff1_2);

    // Set C2 consition
    continuity_entries.Set(2, 2, 1, nCtrPnts, diff2_1 - diff2_2);
    if (!firstAndLastInterpolated()) {
        math_Matrix diff0_1 = CTiglBSplineAlgorithms::bsplineBasisMat(m_degree, flatKnots, continuity_params1, 0);
        math_Matrix diff0_2 = CTiglBSplineAlgorithms::bsplineBasisMat(m_degree, flatKnots, continuity_params2, 0);
        continuity_entries.Set(3, 3, 1, nCtrPnts, diff0_1 - diff0_2);
    }
    return continuity_entries;
}

CTiglApproxResult CTiglBSplineApproxInterp::solve(const std::vector<double>& params, const TColStd_Array1OfReal& knots, const TColStd_Array1OfInteger& mults) const
{

    // compute flat knots to solve system
    Standard_Integer nFlatKnots = BSplCLib::KnotSequenceLength(mults, m_degree, false);
    TColStd_Array1OfReal flatKnots(1, nFlatKnots);
    BSplCLib::KnotSequence(knots, mults, flatKnots);

    Standard_Integer n_apprxmated = static_cast<Standard_Integer>(m_indexOfApproximated.size());
    Standard_Integer n_intpolated = static_cast<Standard_Integer>(m_indexOfInterpolated.size());
    Standard_Integer n_continuityConditions = 0;

    bool makeClosed = isClosed();

    if (makeClosed) {
        // C0, C1, C2
        n_continuityConditions = 3;
        if (firstAndLastInterpolated()) {
            // Remove C0 as they are already equal by design
            n_continuityConditions--;
        }
    }

    // Number of control points required
    Standard_Integer nCtrPnts = flatKnots.Length() - m_degree - 1;

    if (nCtrPnts < n_intpolated + n_continuityConditions || nCtrPnts < m_degree + 1 + n_continuityConditions) {
        throw tigl::CTiglError("Too few control points for curve interpolation!");
    }

    if (n_apprxmated == 0 && nCtrPnts != n_intpolated + n_continuityConditions) {
        throw tigl::CTiglError("Wrong number of control points for curve interpolation!");
    }

    // Build left hand side of the equation
    Standard_Integer n_vars = nCtrPnts + n_intpolated + n_continuityConditions;
    math_Matrix lhs(1, n_vars, 1, n_vars);
    lhs.Init(0.);

    // Allocate right hand side
    math_Vector rhsx(1, n_vars);
    math_Vector rhsy(1, n_vars);
    math_Vector rhsz(1, n_vars);

    if (n_apprxmated > 0) {
        // Write b vector. These are the points to be approximated
        TColStd_Array1OfReal appParams(1, n_apprxmated);
        math_Vector bx(1, n_apprxmated);
        math_Vector by(1, n_apprxmated);
        math_Vector bz(1, n_apprxmated);

        Standard_Integer appIndex = 1;
        for (std::vector<size_t>::const_iterator it_idx = m_indexOfApproximated.begin(); it_idx != m_indexOfApproximated.end(); ++it_idx) {
            Standard_Integer ipnt = static_cast<Standard_Integer>(*it_idx + 1);
            const gp_Pnt& p = m_pnts.Value(ipnt);
            bx(appIndex) = p.X();
            by(appIndex) = p.Y();
            bz(appIndex) = p.Z();
            appParams(appIndex) = params[*it_idx];
            appIndex++;
        }

        // Solve constrained linear least squares
        // min(Ax - b) s.t. Cx = d
        // Create left hand side block matrix
        // A.T*A  C.T
        // C      0
        math_Matrix A = CTiglBSplineAlgorithms::bsplineBasisMat(m_degree, flatKnots, appParams);
        math_Matrix At = A.Transposed();

        lhs.Set(1, nCtrPnts, 1, nCtrPnts, At.Multiplied(A));

        rhsx.Set(1, nCtrPnts, At.Multiplied(bx));
        rhsy.Set(1, nCtrPnts, At.Multiplied(by));
        rhsz.Set(1, nCtrPnts, At.Multiplied(bz));
    }

    if (n_intpolated + n_continuityConditions > 0) {
        // Write d vector. These are the points that should be interpolated as well as the continuity constraints for closed curve
        math_Vector dx(1, n_intpolated + n_continuityConditions, 0.);
        math_Vector dy(1, n_intpolated + n_continuityConditions, 0.);
        math_Vector dz(1, n_intpolated + n_continuityConditions, 0.);
        if(n_intpolated > 0) {
            TColStd_Array1OfReal interpParams(1, n_intpolated);
            Standard_Integer intpIndex = 1;
            for (std::vector<size_t>::const_iterator it_idx = m_indexOfInterpolated.begin(); it_idx != m_indexOfInterpolated.end(); ++it_idx) {
                Standard_Integer ipnt = static_cast<Standard_Integer>(*it_idx + 1);
                const gp_Pnt& p = m_pnts.Value(ipnt);
                dx(intpIndex) = p.X();
                dy(intpIndex) = p.Y();
                dz(intpIndex) = p.Z();
                interpParams(intpIndex) = params[*it_idx];
                intpIndex++;
            }
            math_Matrix C = CTiglBSplineAlgorithms::bsplineBasisMat(m_degree, flatKnots, interpParams);
            math_Matrix Ct = C.Transposed();
            lhs.Set(1, nCtrPnts, nCtrPnts + 1, nCtrPnts + n_intpolated, Ct);
            lhs.Set(nCtrPnts + 1,  nCtrPnts + n_intpolated, 1, nCtrPnts, C);
        }

        // sets the C2 continuity constraints for closed curves on the left hand side if requested
        if (makeClosed) {
            math_Matrix continuity_entries = getContinuityMatrix(nCtrPnts, n_continuityConditions, params, flatKnots);
            lhs.Set(nCtrPnts + n_intpolated + 1, nCtrPnts + n_intpolated + n_continuityConditions, 1, nCtrPnts, continuity_entries);
            lhs.Set(1, nCtrPnts, nCtrPnts + n_intpolated + 1, nCtrPnts + n_intpolated + n_continuityConditions, continuity_entries.Transposed());
        }
        rhsx.Set(nCtrPnts + 1, n_vars, dx);
        rhsy.Set(nCtrPnts + 1, n_vars, dy);
        rhsz.Set(nCtrPnts + 1, n_vars, dz);
    }

    math_Gauss solver(lhs);

    math_Vector cp_x(1, n_vars);
    math_Vector cp_y(1, n_vars);
    math_Vector cp_z(1, n_vars);

    solver.Solve(rhsx, cp_x);
    if (!solver.IsDone()) {
        throw CTiglError("Singular Matrix", TIGL_MATH_ERROR);
    }

    solver.Solve(rhsy, cp_y);
    if (!solver.IsDone()) {
        throw CTiglError("Singular Matrix", TIGL_MATH_ERROR);
    }

    solver.Solve(rhsz, cp_z);
    if (!solver.IsDone()) {
        throw CTiglError("Singular Matrix", TIGL_MATH_ERROR);
    }

    TColgp_Array1OfPnt poles(1, nCtrPnts);
    for (Standard_Integer icp = 1; icp <= nCtrPnts; ++icp) {
        gp_Pnt pnt(cp_x.Value(icp), cp_y.Value(icp), cp_z.Value(icp));
        poles.SetValue(icp, pnt);
    }

    CTiglApproxResult result;
    result.curve = new Geom_BSplineCurve(poles, knots, mults, m_degree, false);

    // compute error
    double max_error = 0.;
    for (std::vector<size_t>::const_iterator it_idx = m_indexOfApproximated.begin(); it_idx != m_indexOfApproximated.end(); ++it_idx) {
        Standard_Integer ipnt = static_cast<Standard_Integer>(*it_idx + 1);
        const gp_Pnt& p = m_pnts.Value(ipnt);
        double par = params[*it_idx];

        double error = result.curve->Value(par).Distance(p);
        max_error = std::max(max_error, error);
    }
    result.error = max_error;

    return result;
}

/**
 * @brief Recalculates the curve parameters t_k after the
 * control points are fitted to achieve an even better fit.
 */
void CTiglBSplineApproxInterp::optimizeParameters(const Handle(Geom_Curve)& curve, std::vector<double>& m_t) const
{
    // optimize each parameter by finding it's position on the curve
    for (std::vector<size_t>::const_iterator it_idx = m_indexOfApproximated.begin(); it_idx != m_indexOfApproximated.end(); ++it_idx) {
        size_t idx = *it_idx;

        ProjectResult res = projectOnCurve(m_pnts.Value(static_cast<Standard_Integer>(idx + 1)), curve, m_t[idx]);

        // store optimised parameter
        m_t[idx] = res.parameter;
    }
}

} // namespace tigl


text:
<?xml version="1.0" encoding="UTF-8"?>
<article id="641">
	<title>Representation of Concept Relations Using the TOSAR System ofthe IDC: Treatise III on Information Retrieval Theory	</title>
	<author>Fugmann, RobertNickelsen, HerbertNickelsen, IngeborgWinter, Jakob H.	</author>
	<text>
		   Successful information retrieval from a mechanized file is heavily
		dependent on the fidelity of the representation of concepts in the
		particular language of the system and on the predictability of this
		representation..
		   If an index language is employed, predictability is guaranteed and
		the quality of the retrieval is predominantly governed by the fidelity
		of the representation, i.e., by the extent to which conceptual
		distortion of the concepts to be represented can be avoided.. The various
		index languages vary widely with respect to their fidelity.. Differences
		in their performance are correspondingly great..
		   The lack of fidelity in most of the present day indexing languages
		is due mainly to insufficient representation of the relationships
		among concepts.. We describe a new graphical method of storing and
		retrieving concept relations of various kinds.. The points of such a
		graph are occupied by concepts, and the connecting lines between these
		points represent concept relations.. In a special field of chemistry,
		these graphs also serve as a kind of presentation of the essentials of a
		document to the reader that is much more lucid than a natural language
		text..

	</text>
</article>


text:
require "spec_helper"

app_require "fever_api/read_items"

describe FeverAPI::ReadItems do
  let(:story_repository) { double("repo") }

  subject do
    FeverAPI::ReadItems.new(story_repository: story_repository)
  end

  it "returns a list of unread items including total count" do
    story_repository.should_receive(:unread).twice.and_return([
      double("story", as_fever_json: { id: 5 }),
      double("story", as_fever_json: { id: 7 }),
      double("story", as_fever_json: { id: 11 })
    ])
    subject.call("items" => nil).should == {
      items: [
        { id: 5 },
        { id: 7 },
        { id: 11 }
      ],
      total_items: 3
    }
  end

  it "returns a list of unread items since id including total count" do
    story_repository.should_receive(:unread_since_id).with(3).and_return([
      double("story", as_fever_json: { id: 5 }),
      double("story", as_fever_json: { id: 7 })
    ])
    story_repository.should_receive(:unread).and_return([
      double("story", as_fever_json: { id: 2 }),
      double("story", as_fever_json: { id: 5 }),
      double("story", as_fever_json: { id: 7 })
    ])
    subject.call("items" => nil, since_id: 3).should == {
      items: [
        { id: 5 },
        { id: 7 }
      ],
      total_items: 3
    }
  end

  it "returns a list of specified items including total count" do
    story_repository.should_receive(:fetch_by_ids).with(%w(5 11)).twice.and_return([
      double("story", as_fever_json: { id: 5 }),
      double("story", as_fever_json: { id: 11 })
    ])

    subject.call("items" => nil, with_ids: "5,11").should == {
      items: [
        { id: 5 },
        { id: 11 }
      ],
      total_items: 2
    }
  end

  it "returns an empty hash otherwise" do
    subject.call.should == {}
  end
end


text:
class Range
  include Enumerable

  def initialize(first, last, exclude_end = false)
    raise NameError, "`initialize' called twice" if @begin

    unless first.kind_of?(Fixnum) && last.kind_of?(Fixnum)
      begin
        raise ArgumentError, "bad value for range" unless first <=> last
      rescue
        raise ArgumentError, "bad value for range"
      end
    end

    @begin = first
    @end = last
    @excl = exclude_end
  end

  private :initialize

  def ==(other)
    return true if equal? other

    other.kind_of?(Range) and
      self.first == other.first and
      self.last == other.last and
      self.exclude_end? == other.exclude_end?

  end
  alias_method :eql?, :==

  def include?(value)
    # MRI uses <=> to compare, so must we.

    beg_compare = (@begin <=> value)
    return false unless beg_compare

    if Comparable.compare_int(beg_compare) <= 0
      end_compare = (value <=> @end)
      if @excl
        return true if Comparable.compare_int(end_compare) < 0
      else
        return true if Comparable.compare_int(end_compare) <= 0
      end
    end

    return false
  end
  alias_method :member?, :include?

  attr_reader_specific :excl, :exclude_end?

  def each(&block)
    return to_enum unless block_given?
    first, last = @begin, @end

    raise TypeError, "can't iterate from #{first.class}" unless can_iterate_from?(first)

    case first
    when Fixnum
      last -= 1 if @excl

      i = first
      while i <= last
        yield i
        i += 1
      end

    when String
      first.upto(last) do |s|
        yield s unless @excl && s == last
      end
    when Symbol
      current = first
      if @excl
        while (current <=> last) < 0
          yield current
          current = (current.to_s.bytes.to_a.last + 1).chr.to_sym
        end
      else
        while (c = current <=> last) && c <= 0
          yield current
          break if c == 0
          current = (current.to_s.bytes.to_a.last + 1).chr.to_sym
        end
      end
    else
      current = first
      if @excl
        while (current <=> last) < 0
          yield current
          current = current.succ
        end
      else
        while (c = current <=> last) && c <= 0
          yield current
          break if c == 0
          current = current.succ
        end
      end
    end
    return self
  end

  attr_reader :begin
  alias_method :first, :begin

  def hash
    excl = @excl ? 1 : 0
    hash = excl
    hash ^= @begin.hash << 1
    hash ^= @end.hash << 9
    hash ^= excl << 24;
    # Are we throwing away too much here for a good hash value distribution?
    return hash & Fixnum::MAX
  end

  def inspect
    "#{@begin.inspect}#{@excl ? "..." : ".."}#{@end.inspect}"
  end

  attr_reader :end
  alias_method :last, :end

  def step(step_size=1) # :yields: object
    return to_enum(:step, step_size) unless block_given?
    first = @begin
    last = @end

    if step_size.kind_of? Float or first.kind_of? Float or last.kind_of? Float
      # if any are floats they all must be
      begin
        step_size = Float(from = step_size)
        first     = Float(from = first)
        last      = Float(from = last)
      rescue ArgumentError
        raise TypeError, "no implicit conversion to float from #{from.class}"
      end
    else
      step_size = Integer(from = step_size)
      if ! step_size.kind_of? Integer
        raise TypeError, "can't convert #{from.class} to Integer (#{from.class}#to_int gives #{step_size.class})"
      end
    end

    if step_size <= 0
      raise ArgumentError, "step can't be negative" if step_size < 0
      raise ArgumentError, "step can't be 0"
    end

    if first.kind_of?(Float)
      err = (first.abs + last.abs + (last - first).abs) / step_size.abs * Float::EPSILON
      err = 0.5 if err > 0.5
      if @excl
        n = ((last - first) / step_size - err).floor
        n += 1 if n * step_size + first < last
      else
        n = ((last - first) / step_size + err).floor + 1
      end

      i = 0
      while i < n
        d = i * step_size + first
        d = last if last < d
        yield d
        i += 1
      end
    elsif first.kind_of?(Numeric)
      d = first
      while @excl ? d < last : d <= last
        yield d
        d += step_size
      end
    else
      counter = 0
      each do |o|
        yield o if counter % step_size == 0
        counter += 1
      end
    end

    return self
  end

  def to_s
    "#{@begin}#{@excl ? "..." : ".."}#{@end}"
  end

  def to_a
    if @begin.kind_of? Fixnum and @end.kind_of? Fixnum
      fin = @end
      fin += 1 unless @excl

      size = fin - @begin
      return [] if size <= 0

      ary = Array.new(size)
      i = 0
      while i < size
        ary[i] = @begin + i
        i += 1
      end

      return ary
    end

    super
  end
end


text:
package edu.stanford.slac.util.zplot.cartoon.model.widget;
import java.awt.Color;
import java.awt.Polygon;
import java.awt.Shape;
import java.awt.geom.Area;
import java.awt.geom.Rectangle2D;

public class VacuumValveWidget extends CartoonWidget {

		private static Shape createShape() {
			Shape rect = new Rectangle2D.Double(-REF_WIDTH/2, -2 * REF_HEIGHT, REF_WIDTH,
					REF_HEIGHT);

			// DR for now, until we can get a "bowtie" on a stick, modify the wire widget..
			// clockwise starting on the left, then at the top
			Shape topTriangle = new Polygon(new int[] { -REF_WIDTH/2 + 1,
					REF_WIDTH/2 - 1, -REF_WIDTH/2 + 1 }, new int[] {
					-2 * REF_HEIGHT - 1,
					-2 * REF_HEIGHT - 1,
					-3 * REF_HEIGHT / 2 - 1 }, 3);

			Shape middleTriangle = new Polygon(
					new int[] { -REF_WIDTH/2 + 1, REF_WIDTH/2 - 1,
							REF_WIDTH/2 - 1 },
					new int[] { -3 * REF_HEIGHT / 2, -2 * REF_HEIGHT, -REF_HEIGHT },
					3);

			Shape bottomTriangle = new Polygon(new int[] { -REF_WIDTH/2  + 1,
					REF_WIDTH/2 - 1, -REF_WIDTH/2 + 1 }, new int[] {
					-3 * REF_HEIGHT / 2 + 1,
					-REF_HEIGHT + 1, -REF_HEIGHT + 1 }, 3);

			Shape base = new Rectangle2D.Double(-REF_WIDTH/2, -REF_HEIGHT, REF_WIDTH, 1);

			Shape stick = new Rectangle2D.Double( - 1, -REF_HEIGHT, 2,
					REF_HEIGHT);

			Area result = new Area(rect);
			result.add(new Area(stick));
		//	result.subtract(new Area(topTriangle));
			result.subtract(new Area(middleTriangle));
		//	result.subtract(new Area(bottomTriangle));
			result.add(new Area(base));
			return result;

		}

		private static final Shape SHAPE = createShape();

		public VacuumValveWidget() {
			super(Color.LIGHT_GRAY);
		}

		@Override
		public Shape getShape(int length) {
			return SHAPE;
		}

	}