<commit_before>package cli

import (
	"flag"
	"testing"

	rpcpb "github.com/google/shipshape/shipshape/proto/shipshape_rpc_proto"
	"github.com/google/shipshape/shipshape/util/docker"
)

var (
	// There are two ways to specify test flags when using Bazel:
	// 1) In the BUILD file with an args stanza in the _test rule.
	// 2) On the command line using --test_arg (i.e. bazel test --test_arg=-shipshape_test_docker_tag=TAG ...).
	//
	// As of 9 Oct 2015, there are multiple Bazel targets that use --shipshape_test_docker_tag (:shipshape_test_prod
	// and :shipshape_test_local) but there are no targets that set local Kythe.
	dockerTag  = flag.String("shipshape_test_docker_tag", "", "the docker tag for the images to use for testing")
	localKythe = flag.Bool("shipshape_test_local_kythe", false, "if true, don't pull the Kythe docker image")
)

func countFailures(resp rpcpb.ShipshapeResponse) int {
	failures := 0
	for _, analyzeResp := range resp.AnalyzeResponse {
		failures += len(analyzeResp.Failure)
	}
	return failures
}

func countNotes(resp rpcpb.ShipshapeResponse) int {
	notes := 0
	for _, analyzeResp := range resp.AnalyzeResponse {
		notes += len(analyzeResp.Note)
	}
	return notes
}

func countCategoryNotes(resp rpcpb.ShipshapeResponse, category string) int {
	notes := 0
	for _, analyzeResp := range resp.AnalyzeResponse {
		for _, note := range analyzeResp.Note {
			if *note.Category == category {
				notes += 1
			}
		}
	}
	return notes
}

func TestExternalAnalyzers(t *testing.T) {
	// Replaces part of the e2e test
	// Create a fake maven project with android failures

	// Run CLI using a .shipshape file
}

func TestBuiltInAnalyzersPreBuild(t *testing.T) {
	options := Options{
		File:                "shipshape/cli/testdata/workspace1",
		ThirdPartyAnalyzers: []string{},
		Build:               "",
		TriggerCats:         []string{"PostMessage", "JSHint", "go vet", "PyLint"},
		Dind:                false,
		Event:               DefaultEvent,
		Repo:                DefaultRepo,
		StayUp:              true,
		Tag:                 *dockerTag,
		LocalKythe:          *localKythe,
	}
	var allResponses rpcpb.ShipshapeResponse
	options.HandleResponse = func(shipshapeResp *rpcpb.ShipshapeResponse, _ string) error {
		allResponses.AnalyzeResponse = append(allResponses.AnalyzeResponse, shipshapeResp.AnalyzeResponse...)
		return nil
	}
	returnedNotesCount, err := New(options).Run()
	if err != nil {
		t.Fatal(err)
	}
	testName := "TestBuiltInAnalyzerPreBuild"

	if got, want := countFailures(allResponses), 0; got != want {
		t.Errorf("%v: Wrong number of failures; got %v, want %v (proto data: %v)", testName, got, want, allResponses)
	}
	if countedNotes := countNotes(allResponses); returnedNotesCount != countedNotes {
		t.Errorf("%v: Inconsistent note count: returned %v, counted %v (proto data: %v", testName, returnedNotesCount, countedNotes, allResponses)
	}
	if got, want := returnedNotesCount, 39; got != want {
		t.Errorf("%v: Wrong number of notes; got %v, want %v (proto data: %v)", testName, got, want, allResponses)
	}
	if got, want := countCategoryNotes(allResponses, "PostMessage"), 2; got != want {
		t.Errorf("%v: Wrong number of PostMessage notes; got %v, want %v (proto data: %v)", testName, got, want, allResponses)
	}
	if got, want := countCategoryNotes(allResponses, "JSHint"), 3; got != want {
		t.Errorf("%v: Wrong number of JSHint notes; got %v, want %v (proto data: %v)", testName, got, want, allResponses)
	}
	if got, want := countCategoryNotes(allResponses, "go vet"), 1; got != want {
		t.Errorf("%v: Wrong number of go vet notes; got %v, want %v (proto data: %v)", testName, got, want, allResponses)
	}
	if got, want := countCategoryNotes(allResponses, "PyLint"), 33; got != want {
		t.Errorf("%v: Wrong number of PyLint notes; got %v, want %v (proto data: %v)", testName, got, want, allResponses)
	}
}

func TestBuiltInAnalyzersPostBuild(t *testing.T) {
	// Replaces part of the e2e test
	// Test with a kythe maven build
	// PostMessage and ErrorProne
}

func TestStreamsMode(t *testing.T) {
	// Test whether it works in streams mode
	// Before creating this, ensure that streams mode
	// is actually still something we need to support.
}

func TestChangingDirs(t *testing.T) {
	tests := []struct {
		name           string
		file           string
		expectedJSHint int
		expectedGovet  int
		expectedPyLint int
	}{
		{
			name:           "ChildDir",
			file:           "shipshape/cli/testdata/workspace2/subworkspace1",
			expectedJSHint: 0,
			expectedGovet:  1,
			expectedPyLint: 0,
		},
		{
			name:           "SiblingDir",
			file:           "shipshape/cli/testdata/workspace2/subworkspace2",
			expectedJSHint: 0,
			expectedGovet:  0,
			expectedPyLint: 22,
		},
		{
			name:           "ParentDir",
			file:           "shipshape/cli/testdata/workspace2",
			expectedJSHint: 3,
			expectedGovet:  1,
			expectedPyLint: 22,
		},
		{
			name:           "File",
			file:           "shipshape/cli/testdata/workspace2/test.js",
			expectedJSHint: 3,
			expectedGovet:  0,
			expectedPyLint: 0,
		},
	}

	// Clean up the docker state
	container := "shipping_container"
	exists, err := docker.ContainerExists(container)
	if err != nil {
		t.Fatalf("Problem checking docker state; err: %v", err)
	}
	if exists {
		if result := docker.Stop(container, 0, true); result.Err != nil {
			t.Fatalf("Problem cleaning up the docker state; err: %v", result.Err)
		}
	}

	for _, test := range tests {
		options := Options{
			File:                test.file,
			ThirdPartyAnalyzers: []string{},
			Build:               "",
			TriggerCats:         []string{"PostMessage", "JSHint", "go vet", "PyLint"},
			Dind:                false,
			Event:               DefaultEvent,
			Repo:                DefaultRepo,
			StayUp:              true,
			Tag:                 *dockerTag,
			LocalKythe:          *localKythe,
		}
		var allResponses rpcpb.ShipshapeResponse
		options.HandleResponse = func(shipshapeResp *rpcpb.ShipshapeResponse, _ string) error {
			allResponses.AnalyzeResponse =
				append(allResponses.AnalyzeResponse, shipshapeResp.AnalyzeResponse...)
			return nil
		}
		testName := test.name
		if _, err := New(options).Run(); err != nil {
			t.Fatalf("%v: Failure on service call; err: %v", testName, err)
		}
		if got, want := countFailures(allResponses), 0; got != want {
			t.Errorf("%v: Wrong number of failures; got %v, want %v (proto data: %v)",
				testName, got, want, allResponses)
		}
		if got, want := countCategoryNotes(allResponses, "JSHint"), test.expectedJSHint; got != want {
			t.Errorf("%v: Wrong number of JSHint notes; got %v, want %v (proto data: %v)",
				testName, got, want, allResponses)
		}
		if got, want := countCategoryNotes(allResponses, "go vet"), test.expectedGovet; got != want {
			t.Errorf("%v: Wrong number of go vet notes; got %v, want %v (proto data: %v)",
				testName, got, want, allResponses)
		}
		if got, want := countCategoryNotes(allResponses, "PyLint"), test.expectedPyLint; got != want {
			t.Errorf("%v: Wrong number of PyLint notes; got %v, want %v (proto data: %v)",
				testName, got, want, allResponses)
		}
	}
}

func dumpLogs() {

}

func checkOutput(category string, numResults int) {

}
<commit_msg>Added a regression test about running the same test twice in a row<commit_after>package cli

import (
	"flag"
	"testing"

	rpcpb "github.com/google/shipshape/shipshape/proto/shipshape_rpc_proto"
	"github.com/google/shipshape/shipshape/util/docker"
)

var (
	// There are two ways to specify test flags when using Bazel:
	// 1) In the BUILD file with an args stanza in the _test rule.
	// 2) On the command line using --test_arg (i.e. bazel test --test_arg=-shipshape_test_docker_tag=TAG ...).
	//
	// As of 9 Oct 2015, there are multiple Bazel targets that use --shipshape_test_docker_tag (:shipshape_test_prod
	// and :shipshape_test_local) but there are no targets that set local Kythe.
	dockerTag  = flag.String("shipshape_test_docker_tag", "", "the docker tag for the images to use for testing")
	localKythe = flag.Bool("shipshape_test_local_kythe", false, "if true, don't pull the Kythe docker image")
)

func countFailures(resp rpcpb.ShipshapeResponse) int {
	failures := 0
	for _, analyzeResp := range resp.AnalyzeResponse {
		failures += len(analyzeResp.Failure)
	}
	return failures
}

func countNotes(resp rpcpb.ShipshapeResponse) int {
	notes := 0
	for _, analyzeResp := range resp.AnalyzeResponse {
		notes += len(analyzeResp.Note)
	}
	return notes
}

func countCategoryNotes(resp rpcpb.ShipshapeResponse, category string) int {
	notes := 0
	for _, analyzeResp := range resp.AnalyzeResponse {
		for _, note := range analyzeResp.Note {
			if *note.Category == category {
				notes += 1
			}
		}
	}
	return notes
}

func TestExternalAnalyzers(t *testing.T) {
	// Replaces part of the e2e test
	// Create a fake maven project with android failures

	// Run CLI using a .shipshape file
}

func TestBuiltInAnalyzersPreBuild(t *testing.T) {
	options := Options{
		File:                "shipshape/cli/testdata/workspace1",
		ThirdPartyAnalyzers: []string{},
		Build:               "",
		TriggerCats:         []string{"PostMessage", "JSHint", "go vet", "PyLint"},
		Dind:                false,
		Event:               DefaultEvent,
		Repo:                DefaultRepo,
		StayUp:              true,
		Tag:                 *dockerTag,
		LocalKythe:          *localKythe,
	}
	var allResponses rpcpb.ShipshapeResponse
	options.HandleResponse = func(shipshapeResp *rpcpb.ShipshapeResponse, _ string) error {
		allResponses.AnalyzeResponse = append(allResponses.AnalyzeResponse, shipshapeResp.AnalyzeResponse...)
		return nil
	}
	returnedNotesCount, err := New(options).Run()
	if err != nil {
		t.Fatal(err)
	}
	testName := "TestBuiltInAnalyzerPreBuild"

	if got, want := countFailures(allResponses), 0; got != want {
		t.Errorf("%v: Wrong number of failures; got %v, want %v (proto data: %v)", testName, got, want, allResponses)
	}
	if countedNotes := countNotes(allResponses); returnedNotesCount != countedNotes {
		t.Errorf("%v: Inconsistent note count: returned %v, counted %v (proto data: %v", testName, returnedNotesCount, countedNotes, allResponses)
	}
	if got, want := returnedNotesCount, 39; got != want {
		t.Errorf("%v: Wrong number of notes; got %v, want %v (proto data: %v)", testName, got, want, allResponses)
	}
	if got, want := countCategoryNotes(allResponses, "PostMessage"), 2; got != want {
		t.Errorf("%v: Wrong number of PostMessage notes; got %v, want %v (proto data: %v)", testName, got, want, allResponses)
	}
	if got, want := countCategoryNotes(allResponses, "JSHint"), 3; got != want {
		t.Errorf("%v: Wrong number of JSHint notes; got %v, want %v (proto data: %v)", testName, got, want, allResponses)
	}
	if got, want := countCategoryNotes(allResponses, "go vet"), 1; got != want {
		t.Errorf("%v: Wrong number of go vet notes; got %v, want %v (proto data: %v)", testName, got, want, allResponses)
	}
	if got, want := countCategoryNotes(allResponses, "PyLint"), 33; got != want {
		t.Errorf("%v: Wrong number of PyLint notes; got %v, want %v (proto data: %v)", testName, got, want, allResponses)
	}
}

// This is a regression test to ensure that when we run the exact same thing twice, it still works.
func TestTwoRunsExactlySame(t *testing.T) {
	TestBuiltInAnalyzersPreBuild(t)
	TestBuiltInAnalyzersPreBuild(t)
}

func TestBuiltInAnalyzersPostBuild(t *testing.T) {
	// Replaces part of the e2e test
	// Test with a kythe maven build
	// PostMessage and ErrorProne
}

<<<<<<< HEAD
func TestStreamsMode(t *testing.T) {
	// Test whether it works in streams mode
	// Before creating this, ensure that streams mode
	// is actually still something we need to support.
}

func TestChangingDirs(t *testing.T) {
	tests := []struct {
		name           string
		file           string
		expectedJSHint int
		expectedGovet  int
		expectedPyLint int
	}{
		{
			name:           "ChildDir",
			file:           "shipshape/cli/testdata/workspace2/subworkspace1",
			expectedJSHint: 0,
			expectedGovet:  1,
			expectedPyLint: 0,
		},
		{
			name:           "SiblingDir",
			file:           "shipshape/cli/testdata/workspace2/subworkspace2",
			expectedJSHint: 0,
			expectedGovet:  0,
			expectedPyLint: 22,
		},
		{
			name:           "ParentDir",
			file:           "shipshape/cli/testdata/workspace2",
			expectedJSHint: 3,
			expectedGovet:  1,
			expectedPyLint: 22,
		},
		{
			name:           "File",
			file:           "shipshape/cli/testdata/workspace2/test.js",
			expectedJSHint: 3,
			expectedGovet:  0,
			expectedPyLint: 0,
		},
	}

	// Clean up the docker state
	container := "shipping_container"
	exists, err := docker.ContainerExists(container)
	if err != nil {
		t.Fatalf("Problem checking docker state; err: %v", err)
	}
	if exists {
		if result := docker.Stop(container, 0, true); result.Err != nil {
			t.Fatalf("Problem cleaning up the docker state; err: %v", result.Err)
		}
	}

	for _, test := range tests {
		options := Options{
			File:                test.file,
			ThirdPartyAnalyzers: []string{},
			Build:               "",
			TriggerCats:         []string{"PostMessage", "JSHint", "go vet", "PyLint"},
			Dind:                false,
			Event:               DefaultEvent,
			Repo:                DefaultRepo,
			StayUp:              true,
			Tag:                 *dockerTag,
			LocalKythe:          *localKythe,
		}
		var allResponses rpcpb.ShipshapeResponse
		options.HandleResponse = func(shipshapeResp *rpcpb.ShipshapeResponse, _ string) error {
			allResponses.AnalyzeResponse =
				append(allResponses.AnalyzeResponse, shipshapeResp.AnalyzeResponse...)
			return nil
		}
		testName := test.name
		if _, err := New(options).Run(); err != nil {
			t.Fatalf("%v: Failure on service call; err: %v", testName, err)
		}
		if got, want := countFailures(allResponses), 0; got != want {
			t.Errorf("%v: Wrong number of failures; got %v, want %v (proto data: %v)",
				testName, got, want, allResponses)
		}
		if got, want := countCategoryNotes(allResponses, "JSHint"), test.expectedJSHint; got != want {
			t.Errorf("%v: Wrong number of JSHint notes; got %v, want %v (proto data: %v)",
				testName, got, want, allResponses)
		}
		if got, want := countCategoryNotes(allResponses, "go vet"), test.expectedGovet; got != want {
			t.Errorf("%v: Wrong number of go vet notes; got %v, want %v (proto data: %v)",
				testName, got, want, allResponses)
		}
		if got, want := countCategoryNotes(allResponses, "PyLint"), test.expectedPyLint; got != want {
			t.Errorf("%v: Wrong number of PyLint notes; got %v, want %v (proto data: %v)",
				testName, got, want, allResponses)
		}
	}
=======
func TestChangingDirectories(t *testing.T) {
	// Replaces the changedir test
	// Make sure to test changing down, changing up, running on the same directory, running on a single file in the same directory, and changing to a sibling
>>>>>>> Added a regression test about running the same test twice in a row
}

func dumpLogs() {

}

func checkOutput(category string, numResults int) {

}
<|endoftext|>


<commit_before>// Copyright 2010 GoDCCP Authors. All rights reserved.
// Use of this source code is governed by a
// license that can be found in the LICENSE file.

package dccp

import ()

// Conn
type Conn struct {
	hc    HeaderConn
	cc    CongestionControl
	Mutex // Protects access to socket
	socket
	readApp      chan []byte  // readLoop() sends application data to Read()
	writeData    chan []byte  // Write() sends application data to writeLoop()
	writeNonData chan *Header // inject() sends wire-format non-Data packets (higher priority) to writeLoop()
}

func newConn(hc HeaderConn, cc CongestionControl) *Conn {
	c := &Conn{
		hc:           hc,
		cc:           cc,
		readApp:      make(chan []byte, 3),
		writeData:    make(chan []byte),
		writeNonData: make(chan *Header, 3),
	}

	c.Lock()
	// Currently, CCID is not negotiated, rather both sides use the same
	c.socket.SetCCIDA(cc.GetID())
	c.socket.SetCCIDB(cc.GetID())
	c.updateSocketLink()
	c.updateSocketCongestionControl()
	c.Unlock()

	return c
}

func newConnServer(hc HeaderConn, cc CongestionControl) *Conn {
	c := newConn(hc, cc)

	c.Lock()
	c.socket.SetState(LISTEN)
	c.Unlock()

	go c.writeLoop()
	go c.readLoop()
	return c
}

func newConnClient(hc HeaderConn, cc CongestionControl, serviceCode uint32) *Conn {
	c := newConn(hc, cc)

	c.Lock()
	c.socket.SetState(REQUEST)
	c.socket.SetServiceCode(h.ServiceCode)
	iss := c.socket.ChooseISS()
	c.socket.SetGAR(iss)  // ???
	c.inject(c.generateRequest(serviceCode))
	c.Unlock()

	// Exponential backoff if not response

	// A client in the REQUEST state SHOULD use an exponential-backoff timer to send new
	// DCCP-Request packets if no response is received.  The first retransmission should occur
	// after approximately one second, backing off to not less than one packet every 64 seconds;
	// Each new DCCP-Request MUST increment the Sequence Number by one and MUST contain the same
	// Service Code and application data as the original DCCP-Request.

	// A client MAY give up on its DCCP-Requests after some time (3 minutes, for example).  When
	// it does, it SHOULD send a DCCP-Reset packet to the server with Reset Code 2, "Aborted",
	// to clean up state in case one or more of the Requests actually arrived.  A client in
	// REQUEST state has never received an initial sequence number from its peer, so the
	// DCCP-Reset's Acknowledgement Number MUST be set to zero.

	go c.writeLoop()
	go c.readLoop()
	return c
}
<commit_msg>missed a file<commit_after>// Copyright 2010 GoDCCP Authors. All rights reserved.
// Use of this source code is governed by a
// license that can be found in the LICENSE file.

package dccp

import ()

// Conn
type Conn struct {
	hc    HeaderConn
	cc    CongestionControl
	Mutex // Protects access to socket
	socket
	readApp      chan []byte  // readLoop() sends application data to Read()
	writeData    chan []byte  // Write() sends application data to writeLoop()
	writeNonData chan *Header // inject() sends wire-format non-Data packets (higher priority) to writeLoop()
}

func newConn(hc HeaderConn, cc CongestionControl) *Conn {
	c := &Conn{
		hc:           hc,
		cc:           cc,
		readApp:      make(chan []byte, 3),
		writeData:    make(chan []byte),
		writeNonData: make(chan *Header, 3),
	}

	c.Lock()
	// Currently, CCID is not negotiated, rather both sides use the same
	c.socket.SetCCIDA(cc.GetID())
	c.socket.SetCCIDB(cc.GetID())
	c.updateSocketLink()
	c.updateSocketCongestionControl()
	c.Unlock()

	return c
}

func newConnServer(hc HeaderConn, cc CongestionControl) *Conn {
	c := newConn(hc, cc)

	c.Lock()
	c.socket.SetState(LISTEN)
	c.Unlock()

	go c.writeLoop()
	go c.readLoop()
	return c
}

func newConnClient(hc HeaderConn, cc CongestionControl, serviceCode uint32) *Conn {
	c := newConn(hc, cc)

	c.Lock()
	c.socket.SetState(REQUEST)
	c.socket.SetServiceCode(serviceCode)
	iss := c.socket.ChooseISS()
	c.socket.SetGAR(iss)  // ???
	c.inject(c.generateRequest(serviceCode))
	c.Unlock()

	// Exponential backoff if not response

	// A client in the REQUEST state SHOULD use an exponential-backoff timer to send new
	// DCCP-Request packets if no response is received.  The first retransmission should occur
	// after approximately one second, backing off to not less than one packet every 64 seconds;
	// Each new DCCP-Request MUST increment the Sequence Number by one and MUST contain the same
	// Service Code and application data as the original DCCP-Request.

	// A client MAY give up on its DCCP-Requests after some time (3 minutes, for example).  When
	// it does, it SHOULD send a DCCP-Reset packet to the server with Reset Code 2, "Aborted",
	// to clean up state in case one or more of the Requests actually arrived.  A client in
	// REQUEST state has never received an initial sequence number from its peer, so the
	// DCCP-Reset's Acknowledgement Number MUST be set to zero.

	go c.writeLoop()
	go c.readLoop()
	return c
}
<|endoftext|>


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

package gitlab

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

// MergeRequestsService handles communication with the merge requests related
// methods of the GitLab API.
//
// GitLab API docs: http://doc.gitlab.com/ce/api/merge_requests.html
type MergeRequestsService struct {
	client *Client
}

// MergeRequest represents a GitLab merge request.
//
// GitLab API docs: http://doc.gitlab.com/ce/api/merge_requests.html
type MergeRequest struct {
	ID             int        `json:"id"`
	IID            int        `json:"iid"`
	ProjectID      int        `json:"project_id"`
	Title          string     `json:"title"`
	Description    string     `json:"description"`
	WorkInProgress bool       `json:"work_in_progress"`
	State          string     `json:"state"`
	CreatedAt      *time.Time `json:"created_at"`
	UpdatedAt      *time.Time `json:"updated_at"`
	TargetBranch   string     `json:"target_branch"`
	SourceBranch   string     `json:"source_branch"`
	Upvotes        int        `json:"upvotes"`
	Downvotes      int        `json:"downvotes"`
	Author         struct {
		Name      string `json:"name"`
		Username  string `json:"username"`
		ID        int    `json:"id"`
		State     string `json:"state"`
		AvatarURL string `json:"avatar_url"`
	} `json:"author"`
	Assignee struct {
		Name      string `json:"name"`
		Username  string `json:"username"`
		ID        int    `json:"id"`
		State     string `json:"state"`
		AvatarURL string `json:"avatar_url"`
	} `json:"assignee"`
	SourceProjectID int      `json:"source_project_id"`
	TargetProjectID int      `json:"target_project_id"`
	Labels          []string `json:"labels"`
	Milestone       struct {
		ID          int        `json:"id"`
		Iid         int        `json:"iid"`
		ProjectID   int        `json:"project_id"`
		Title       string     `json:"title"`
		Description string     `json:"description"`
		State       string     `json:"state"`
		CreatedAt   *time.Time `json:"created_at"`
		UpdatedAt   *time.Time `json:"updated_at"`
		DueDate     string     `json:"due_date"`
	} `json:"milestone"`
	MergeWhenBuildSucceeds  bool   `json:"merge_when_build_succeeds"`
	MergeStatus             string `json:"merge_status"`
	Subscribed              bool   `json:"subscribed"`
	UserNotesCount          int    `json:"user_notes_count"`
	SouldRemoveSourceBranch bool   `json:"should_remove_source_branch"`
	ForceRemoveSourceBranch bool   `json:"force_remove_source_branch"`
	Changes                 []struct {
		OldPath     string `json:"old_path"`
		NewPath     string `json:"new_path"`
		AMode       string `json:"a_mode"`
		BMode       string `json:"b_mode"`
		Diff        string `json:"diff"`
		NewFile     bool   `json:"new_file"`
		RenamedFile bool   `json:"renamed_file"`
		DeletedFile bool   `json:"deleted_file"`
	} `json:"changes"`
}

func (m MergeRequest) String() string {
	return Stringify(m)
}

// ListMergeRequestsOptions represents the available ListMergeRequests()
// options.
//
// GitLab API docs:
// http://doc.gitlab.com/ce/api/merge_requests.html#list-merge-requests
type ListMergeRequestsOptions struct {
	ListOptions
	IID     *int    `url:"iid,omitempty" json:"iid,omitempty"`
	State   *string `url:"state,omitempty" json:"state,omitempty"`
	OrderBy *string `url:"order_by,omitempty" json:"order_by,omitempty"`
	Sort    *string `url:"sort,omitempty" json:"sort,omitempty"`
}

// ListMergeRequests gets all merge requests for this project. The state
// parameter can be used to get only merge requests with a given state (opened,
// closed, or merged) or all of them (all). The pagination parameters page and
// per_page can be used to restrict the list of merge requests.
//
// GitLab API docs:
// http://doc.gitlab.com/ce/api/merge_requests.html#list-merge-requests
func (s *MergeRequestsService) ListMergeRequests(
	pid interface{},
	opt *ListMergeRequestsOptions) ([]*MergeRequest, *Response, error) {
	project, err := parseID(pid)
	if err != nil {
		return nil, nil, err
	}
	u := fmt.Sprintf("projects/%s/merge_requests", url.QueryEscape(project))

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

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

	return m, resp, err
}

// GetMergeRequest shows information about a single merge request.
//
// GitLab API docs:
// http://doc.gitlab.com/ce/api/merge_requests.html#get-single-mr
func (s *MergeRequestsService) GetMergeRequest(
	pid interface{},
	mergeRequest int) (*MergeRequest, *Response, error) {
	project, err := parseID(pid)
	if err != nil {
		return nil, nil, err
	}
	u := fmt.Sprintf("projects/%s/merge_request/%d", url.QueryEscape(project), mergeRequest)

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

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

	return m, resp, err
}

// GetMergeRequestChanges shows information about the merge request including
// its files and changes.
//
// GitLab API docs:
// http://doc.gitlab.com/ce/api/merge_requests.html#get-single-mr-changes
func (s *MergeRequestsService) GetMergeRequestChanges(
	pid interface{},
	mergeRequest int) (*MergeRequest, *Response, error) {
	project, err := parseID(pid)
	if err != nil {
		return nil, nil, err
	}
	u := fmt.Sprintf("projects/%s/merge_request/%d/changes", url.QueryEscape(project), mergeRequest)

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

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

	return m, resp, err
}

// CreateMergeRequestOptions represents the available CreateMergeRequest()
// options.
//
// GitLab API docs:
// http://doc.gitlab.com/ce/api/merge_requests.html#create-mr
type CreateMergeRequestOptions struct {
	Title           *string `url:"title,omitempty" json:"title,omitempty"`
	Description     *string `url:"description,omitempty" json:"description,omitempty"`
	SourceBranch    *string `url:"source_branch,omitemtpy" json:"source_branch,omitemtpy"`
	TargetBranch    *string `url:"target_branch,omitemtpy" json:"target_branch,omitemtpy"`
	AssigneeID      *int    `url:"assignee_id,omitempty" json:"assignee_id,omitempty"`
	TargetProjectID *int    `url:"target_project_id,omitempty" json:"target_project_id,omitempty"`
}

// CreateMergeRequest creates a new merge request.
//
// GitLab API docs:
// http://doc.gitlab.com/ce/api/merge_requests.html#create-mr
func (s *MergeRequestsService) CreateMergeRequest(
	pid interface{},
	opt *CreateMergeRequestOptions) (*MergeRequest, *Response, error) {
	project, err := parseID(pid)
	if err != nil {
		return nil, nil, err
	}
	u := fmt.Sprintf("projects/%s/merge_requests", url.QueryEscape(project))

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

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

	return m, resp, err
}

// UpdateMergeRequestOptions represents the available UpdateMergeRequest()
// options.
//
// GitLab API docs:
// http://doc.gitlab.com/ce/api/merge_requests.html#update-mr
type UpdateMergeRequestOptions struct {
	Title        *string `url:"title,omitempty" json:"title,omitempty"`
	Description  *string `url:"description,omitempty" json:"description,omitempty"`
	TargetBranch *string `url:"target_branch,omitemtpy" json:"target_branch,omitemtpy"`
	AssigneeID   *int    `url:"assignee_id,omitempty" json:"assignee_id,omitempty"`
	StateEvent   *string `url:"state_event,omitempty" json:"state_event,omitempty"`
}

// UpdateMergeRequest updates an existing project milestone.
//
// GitLab API docs:
// http://doc.gitlab.com/ce/api/merge_requests.html#update-mr
func (s *MergeRequestsService) UpdateMergeRequest(
	pid interface{},
	mergeRequest int,
	opt *UpdateMergeRequestOptions) (*MergeRequest, *Response, error) {
	project, err := parseID(pid)
	if err != nil {
		return nil, nil, err
	}
	u := fmt.Sprintf("projects/%s/merge_request/%d", url.QueryEscape(project), mergeRequest)

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

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

	return m, resp, err
}

// AcceptMergeRequest merges changes submitted with MR using this API. If merge
// success you get 200 OK. If it has some conflicts and can not be merged - you
// get 405 and error message 'Branch cannot be merged'. If merge request is
// already merged or closed - you get 405 and error message 'Method Not Allowed'
//
// GitLab API docs:
// http://doc.gitlab.com/ce/api/merge_requests.html#accept-mr
func (s *MergeRequestsService) AcceptMergeRequest(
	pid interface{},
	mergeRequest int) (*MergeRequest, *Response, error) {
	project, err := parseID(pid)
	if err != nil {
		return nil, nil, err
	}
	u := fmt.Sprintf("projects/%s/merge_request/%d/merge", url.QueryEscape(project), mergeRequest)

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

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

	return m, resp, err
}

// MergeRequestComment represents a GitLab merge request comment.
//
// GitLab API docs: http://doc.gitlab.com/ce/api/merge_requests.html
type MergeRequestComment struct {
	Note   string `json:"note"`
	Author struct {
		ID        int        `json:"id"`
		Username  string     `json:"username"`
		Email     string     `json:"email"`
		Name      string     `json:"name"`
		State     string     `json:"state"`
		CreatedAt *time.Time `json:"created_at"`
	} `json:"author"`
}

func (m MergeRequestComment) String() string {
	return Stringify(m)
}

// GetMergeRequestCommentsOptions represents the available GetMergeRequestComments()
// options.
//
// GitLab API docs:
// http://doc.gitlab.com/ce/api/merge_requests.html#get-the-comments-on-a-mr
type GetMergeRequestCommentsOptions struct {
	ListOptions
}

// GetMergeRequestComments gets all the comments associated with a merge
// request.
//
// GitLab API docs:
// http://doc.gitlab.com/ce/api/merge_requests.html#get-the-comments-on-a-mr
func (s *MergeRequestsService) GetMergeRequestComments(
	pid interface{},
	mergeRequest int,
	opt *GetMergeRequestCommentsOptions) ([]*MergeRequestComment, *Response, error) {
	project, err := parseID(pid)
	if err != nil {
		return nil, nil, err
	}
	u := fmt.Sprintf("projects/%s/merge_request/%d/comments", url.QueryEscape(project), mergeRequest)

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

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

	return c, resp, err
}

// PostMergeRequestCommentOptions represents the available
// PostMergeRequestComment() options.
//
// GitLab API docs:
// http://doc.gitlab.com/ce/api/commits.html#post-comment-to-mr
type PostMergeRequestCommentOptions struct {
	Note *string `url:"note,omitempty" json:"note,omitempty"`
}

// PostMergeRequestComment dds a comment to a merge request.
//
// GitLab API docs:
// http://doc.gitlab.com/ce/api/commits.html#post-comment-to-mr
func (s *MergeRequestsService) PostMergeRequestComment(
	pid interface{},
	mergeRequest int,
	opt *PostMergeRequestCommentOptions) (*MergeRequestComment, *Response, error) {
	project, err := parseID(pid)
	if err != nil {
		return nil, nil, err
	}
	u := fmt.Sprintf("projects/%s/merge_request/%d/comments", url.QueryEscape(project), mergeRequest)

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

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

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

package gitlab

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

// MergeRequestsService handles communication with the merge requests related
// methods of the GitLab API.
//
// GitLab API docs: http://doc.gitlab.com/ce/api/merge_requests.html
type MergeRequestsService struct {
	client *Client
}

// MergeRequest represents a GitLab merge request.
//
// GitLab API docs: http://doc.gitlab.com/ce/api/merge_requests.html
type MergeRequest struct {
	ID             int        `json:"id"`
	IID            int        `json:"iid"`
	ProjectID      int        `json:"project_id"`
	Title          string     `json:"title"`
	Description    string     `json:"description"`
	WorkInProgress bool       `json:"work_in_progress"`
	State          string     `json:"state"`
	CreatedAt      *time.Time `json:"created_at"`
	UpdatedAt      *time.Time `json:"updated_at"`
	TargetBranch   string     `json:"target_branch"`
	SourceBranch   string     `json:"source_branch"`
	Upvotes        int        `json:"upvotes"`
	Downvotes      int        `json:"downvotes"`
	Author         struct {
		Name      string `json:"name"`
		Username  string `json:"username"`
		ID        int    `json:"id"`
		State     string `json:"state"`
		AvatarURL string `json:"avatar_url"`
	} `json:"author"`
	Assignee struct {
		Name      string `json:"name"`
		Username  string `json:"username"`
		ID        int    `json:"id"`
		State     string `json:"state"`
		AvatarURL string `json:"avatar_url"`
	} `json:"assignee"`
	SourceProjectID int      `json:"source_project_id"`
	TargetProjectID int      `json:"target_project_id"`
	Labels          []string `json:"labels"`
	Milestone       struct {
		ID          int        `json:"id"`
		Iid         int        `json:"iid"`
		ProjectID   int        `json:"project_id"`
		Title       string     `json:"title"`
		Description string     `json:"description"`
		State       string     `json:"state"`
		CreatedAt   *time.Time `json:"created_at"`
		UpdatedAt   *time.Time `json:"updated_at"`
		DueDate     string     `json:"due_date"`
	} `json:"milestone"`
	MergeWhenBuildSucceeds  bool   `json:"merge_when_build_succeeds"`
	MergeStatus             string `json:"merge_status"`
	Subscribed              bool   `json:"subscribed"`
	UserNotesCount          int    `json:"user_notes_count"`
	SouldRemoveSourceBranch bool   `json:"should_remove_source_branch"`
	ForceRemoveSourceBranch bool   `json:"force_remove_source_branch"`
	Changes                 []struct {
		OldPath     string `json:"old_path"`
		NewPath     string `json:"new_path"`
		AMode       string `json:"a_mode"`
		BMode       string `json:"b_mode"`
		Diff        string `json:"diff"`
		NewFile     bool   `json:"new_file"`
		RenamedFile bool   `json:"renamed_file"`
		DeletedFile bool   `json:"deleted_file"`
	} `json:"changes"`
}

func (m MergeRequest) String() string {
	return Stringify(m)
}

// ListMergeRequestsOptions represents the available ListMergeRequests()
// options.
//
// GitLab API docs:
// http://doc.gitlab.com/ce/api/merge_requests.html#list-merge-requests
type ListMergeRequestsOptions struct {
	ListOptions
	IID     *int    `url:"iid,omitempty" json:"iid,omitempty"`
	State   *string `url:"state,omitempty" json:"state,omitempty"`
	OrderBy *string `url:"order_by,omitempty" json:"order_by,omitempty"`
	Sort    *string `url:"sort,omitempty" json:"sort,omitempty"`
}

// ListMergeRequests gets all merge requests for this project. The state
// parameter can be used to get only merge requests with a given state (opened,
// closed, or merged) or all of them (all). The pagination parameters page and
// per_page can be used to restrict the list of merge requests.
//
// GitLab API docs:
// http://doc.gitlab.com/ce/api/merge_requests.html#list-merge-requests
func (s *MergeRequestsService) ListMergeRequests(
	pid interface{},
	opt *ListMergeRequestsOptions) ([]*MergeRequest, *Response, error) {
	project, err := parseID(pid)
	if err != nil {
		return nil, nil, err
	}
	u := fmt.Sprintf("projects/%s/merge_requests", url.QueryEscape(project))

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

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

	return m, resp, err
}

// GetMergeRequest shows information about a single merge request.
//
// GitLab API docs:
// http://doc.gitlab.com/ce/api/merge_requests.html#get-single-mr
func (s *MergeRequestsService) GetMergeRequest(
	pid interface{},
	mergeRequest int) (*MergeRequest, *Response, error) {
	project, err := parseID(pid)
	if err != nil {
		return nil, nil, err
	}
	u := fmt.Sprintf("projects/%s/merge_request/%d", url.QueryEscape(project), mergeRequest)

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

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

	return m, resp, err
}

// GetMergeRequestChanges shows information about the merge request including
// its files and changes.
//
// GitLab API docs:
// http://doc.gitlab.com/ce/api/merge_requests.html#get-single-mr-changes
func (s *MergeRequestsService) GetMergeRequestChanges(
	pid interface{},
	mergeRequest int) (*MergeRequest, *Response, error) {
	project, err := parseID(pid)
	if err != nil {
		return nil, nil, err
	}
	u := fmt.Sprintf("projects/%s/merge_request/%d/changes", url.QueryEscape(project), mergeRequest)

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

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

	return m, resp, err
}

// CreateMergeRequestOptions represents the available CreateMergeRequest()
// options.
//
// GitLab API docs:
// http://doc.gitlab.com/ce/api/merge_requests.html#create-mr
type CreateMergeRequestOptions struct {
	Title           *string `url:"title,omitempty" json:"title,omitempty"`
	Description     *string `url:"description,omitempty" json:"description,omitempty"`
	SourceBranch    *string `url:"source_branch,omitemtpy" json:"source_branch,omitemtpy"`
	TargetBranch    *string `url:"target_branch,omitemtpy" json:"target_branch,omitemtpy"`
	AssigneeID      *int    `url:"assignee_id,omitempty" json:"assignee_id,omitempty"`
	TargetProjectID *int    `url:"target_project_id,omitempty" json:"target_project_id,omitempty"`
}

// CreateMergeRequest creates a new merge request.
//
// GitLab API docs:
// http://doc.gitlab.com/ce/api/merge_requests.html#create-mr
func (s *MergeRequestsService) CreateMergeRequest(
	pid interface{},
	opt *CreateMergeRequestOptions) (*MergeRequest, *Response, error) {
	project, err := parseID(pid)
	if err != nil {
		return nil, nil, err
	}
	u := fmt.Sprintf("projects/%s/merge_requests", url.QueryEscape(project))

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

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

	return m, resp, err
}

// UpdateMergeRequestOptions represents the available UpdateMergeRequest()
// options.
//
// GitLab API docs:
// http://doc.gitlab.com/ce/api/merge_requests.html#update-mr
type UpdateMergeRequestOptions struct {
	Title        *string `url:"title,omitempty" json:"title,omitempty"`
	Description  *string `url:"description,omitempty" json:"description,omitempty"`
	TargetBranch *string `url:"target_branch,omitemtpy" json:"target_branch,omitemtpy"`
	AssigneeID   *int    `url:"assignee_id,omitempty" json:"assignee_id,omitempty"`
	StateEvent   *string `url:"state_event,omitempty" json:"state_event,omitempty"`
}

// UpdateMergeRequest updates an existing project milestone.
//
// GitLab API docs:
// http://doc.gitlab.com/ce/api/merge_requests.html#update-mr
func (s *MergeRequestsService) UpdateMergeRequest(
	pid interface{},
	mergeRequest int,
	opt *UpdateMergeRequestOptions) (*MergeRequest, *Response, error) {
	project, err := parseID(pid)
	if err != nil {
		return nil, nil, err
	}
	u := fmt.Sprintf("projects/%s/merge_request/%d", url.QueryEscape(project), mergeRequest)

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

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

	return m, resp, err
}

// AcceptMergeRequestOptions represents the available AcceptMergeRequest()
// options.
//
// GitLab API docs:
// http://doc.gitlab.com/ce/api/merge_requests.html#accept-mr
type AcceptMergeRequestOptions struct {
	MergeCommitMessage       *string `url:"merge_commit_message,omitempty" json:"merge_commit_message,omitempty"`
	ShouldRemoveSourceBranch *bool   `url:"should_remove_source_branch,omitempty" json:"should_remove_source_branch,omitempty"`
	MergeWhenBuildSucceeds   *bool   `url:"merge_when_build_succeeds,omitempty" json:"merge_when_build_succeeds,omitempty"`
	Sha                      *string `url:"sha,omitempty" json:"sha,omitempty"`
}

// AcceptMergeRequest merges changes submitted with MR using this API. If merge
// success you get 200 OK. If it has some conflicts and can not be merged - you
// get 405 and error message 'Branch cannot be merged'. If merge request is
// already merged or closed - you get 405 and error message 'Method Not Allowed'
//
// GitLab API docs:
// http://doc.gitlab.com/ce/api/merge_requests.html#accept-mr
func (s *MergeRequestsService) AcceptMergeRequest(
	pid interface{},
	mergeRequest int,
	opt *AcceptMergeRequestOptions) (*MergeRequest, *Response, error) {
	project, err := parseID(pid)
	if err != nil {
		return nil, nil, err
	}
	u := fmt.Sprintf("projects/%s/merge_request/%d/merge", url.QueryEscape(project), mergeRequest)

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

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

	return m, resp, err
}

// MergeRequestComment represents a GitLab merge request comment.
//
// GitLab API docs: http://doc.gitlab.com/ce/api/merge_requests.html
type MergeRequestComment struct {
	Note   string `json:"note"`
	Author struct {
		ID        int        `json:"id"`
		Username  string     `json:"username"`
		Email     string     `json:"email"`
		Name      string     `json:"name"`
		State     string     `json:"state"`
		CreatedAt *time.Time `json:"created_at"`
	} `json:"author"`
}

func (m MergeRequestComment) String() string {
	return Stringify(m)
}

// GetMergeRequestCommentsOptions represents the available GetMergeRequestComments()
// options.
//
// GitLab API docs:
// http://doc.gitlab.com/ce/api/merge_requests.html#get-the-comments-on-a-mr
type GetMergeRequestCommentsOptions struct {
	ListOptions
}

// GetMergeRequestComments gets all the comments associated with a merge
// request.
//
// GitLab API docs:
// http://doc.gitlab.com/ce/api/merge_requests.html#get-the-comments-on-a-mr
func (s *MergeRequestsService) GetMergeRequestComments(
	pid interface{},
	mergeRequest int,
	opt *GetMergeRequestCommentsOptions) ([]*MergeRequestComment, *Response, error) {
	project, err := parseID(pid)
	if err != nil {
		return nil, nil, err
	}
	u := fmt.Sprintf("projects/%s/merge_request/%d/comments", url.QueryEscape(project), mergeRequest)

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

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

	return c, resp, err
}

// PostMergeRequestCommentOptions represents the available
// PostMergeRequestComment() options.
//
// GitLab API docs:
// http://doc.gitlab.com/ce/api/commits.html#post-comment-to-mr
type PostMergeRequestCommentOptions struct {
	Note *string `url:"note,omitempty" json:"note,omitempty"`
}

// PostMergeRequestComment dds a comment to a merge request.
//
// GitLab API docs:
// http://doc.gitlab.com/ce/api/commits.html#post-comment-to-mr
func (s *MergeRequestsService) PostMergeRequestComment(
	pid interface{},
	mergeRequest int,
	opt *PostMergeRequestCommentOptions) (*MergeRequestComment, *Response, error) {
	project, err := parseID(pid)
	if err != nil {
		return nil, nil, err
	}
	u := fmt.Sprintf("projects/%s/merge_request/%d/comments", url.QueryEscape(project), mergeRequest)

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

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

	return c, resp, err
}
<|endoftext|>


<commit_before>package main

import (
	"github.com/putsi/paparazzo.go"
	"time"
)

func main() {

	// Local server settings
	imgPath := "/img.jpg"
	addr := ":8080"

	// MJPEG-stream settings
	user := ""
	pass := ""
	timeout := 5 * time.Second
	mjpegStream := "http://westunioncam.studentaffairs.duke.edu/mjpg/video.mjpg"

	mp := mjpegproxy.NewMjpegproxy()

	mp.StartCrawling(mjpegStream, user, pass, timeout)
	mp.Serve(imgPath, addr)

	block := make(chan bool)

	// time.Sleep(time.Second * 30)
	// mp.StopServing()
	// mp.StopCrawling()
	<-block

}
<commit_msg>Update demo.go<commit_after>package main

import (
	"github.com/putsi/paparazzogo"
	"time"
)

func main() {

	// Local server settings
	imgPath := "/img.jpg"
	addr := ":8080"

	// MJPEG-stream settings
	user := ""
	pass := ""
	timeout := 5 * time.Second
	mjpegStream := "http://westunioncam.studentaffairs.duke.edu/mjpg/video.mjpg"

	mp := mjpegproxy.NewMjpegproxy()

	mp.StartCrawling(mjpegStream, user, pass, timeout)
	mp.Serve(imgPath, addr)

	block := make(chan bool)

	// time.Sleep(time.Second * 30)
	// mp.StopServing()
	// mp.StopCrawling()
	<-block

}
<|endoftext|>


<commit_before><commit_msg>rename opt volumesPerStep<commit_after><|endoftext|>


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

/*
The gob package manages streams of gobs - binary values exchanged between an
Encoder (transmitter) and a Decoder (receiver).  A typical use is transporting
arguments and results of remote procedure calls (RPCs) such as those provided by
package "rpc".

A stream of gobs is self-describing.  Each data item in the stream is preceded by
a specification of its type, expressed in terms of a small set of predefined
types.  Pointers are not transmitted, but the things they point to are
transmitted; that is, the values are flattened.  Recursive types work fine, but
recursive values (data with cycles) are problematic.  This may change.

To use gobs, create an Encoder and present it with a series of data items as
values or addresses that can be dereferenced to values.  The Encoder makes sure
all type information is sent before it is needed.  At the receive side, a
Decoder retrieves values from the encoded stream and unpacks them into local
variables.

The source and destination values/types need not correspond exactly.  For structs,
fields (identified by name) that are in the source but absent from the receiving
variable will be ignored.  Fields that are in the receiving variable but missing
from the transmitted type or value will be ignored in the destination.  If a field
with the same name is present in both, their types must be compatible. Both the
receiver and transmitter will do all necessary indirection and dereferencing to
convert between gobs and actual Go values.  For instance, a gob type that is
schematically,

	struct { a, b int }

can be sent from or received into any of these Go types:

	struct { a, b int }	// the same
	*struct { a, b int }	// extra indirection of the struct
	struct { *a, **b int }	// extra indirection of the fields
	struct { a, b int64 }	// different concrete value type; see below

It may also be received into any of these:

	struct { a, b int }	// the same
	struct { b, a int }	// ordering doesn't matter; matching is by name
	struct { a, b, c int }	// extra field (c) ignored
	struct { b int }	// missing field (a) ignored; data will be dropped
	struct { b, c int }	// missing field (a) ignored; extra field (c) ignored.

Attempting to receive into these types will draw a decode error:

	struct { a int; b uint }	// change of signedness for b
	struct { a int; b float }	// change of type for b
	struct { }			// no field names in common
	struct { c, d int }		// no field names in common

Integers are transmitted two ways: arbitrary precision signed integers or
arbitrary precision unsigned integers.  There is no int8, int16 etc.
discrimination in the gob format; there are only signed and unsigned integers.  As
described below, the transmitter sends the value in a variable-length encoding;
the receiver accepts the value and stores it in the destination variable.
Floating-point numbers are always sent using IEEE-754 64-bit precision (see
below).

Signed integers may be received into any signed integer variable: int, int16, etc.;
unsigned integers may be received into any unsigned integer variable; and floating
point values may be received into any floating point variable.  However,
the destination variable must be able to represent the value or the decode
operation will fail.

Structs, arrays and slices are also supported.  Strings and arrays of bytes are
supported with a special, efficient representation (see below).

Interfaces, functions, and channels cannot be sent in a gob.  Attempting
to encode a value that contains one will fail.

The rest of this comment documents the encoding, details that are not important
for most users.  Details are presented bottom-up.

An unsigned integer is sent one of two ways.  If it is less than 128, it is sent
as a byte with that value.  Otherwise it is sent as a minimal-length big-endian
(high byte first) byte stream holding the value, preceded by one byte holding the
byte count, negated.  Thus 0 is transmitted as (00), 7 is transmitted as (07) and
256 is transmitted as (FE 01 00).

A boolean is encoded within an unsigned integer: 0 for false, 1 for true.

A signed integer, i, is encoded within an unsigned integer, u.  Within u, bits 1
upward contain the value; bit 0 says whether they should be complemented upon
receipt.  The encode algorithm looks like this:

	uint u;
	if i < 0 {
		u = (^i << 1) | 1	// complement i, bit 0 is 1
	} else {
		u = (i << 1)	// do not complement i, bit 0 is 0
	}
	encodeUnsigned(u)

The low bit is therefore analogous to a sign bit, but making it the complement bit
instead guarantees that the largest negative integer is not a special case.  For
example, -129=^128=(^256>>1) encodes as (FE 01 01).

Floating-point numbers are always sent as a representation of a float64 value.
That value is converted to a uint64 using math.Float64bits.  The uint64 is then
byte-reversed and sent as a regular unsigned integer.  The byte-reversal means the
exponent and high-precision part of the mantissa go first.  Since the low bits are
often zero, this can save encoding bytes.  For instance, 17.0 is encoded in only
three bytes (FE 31 40).

Strings and slices of bytes are sent as an unsigned count followed by that many
uninterpreted bytes of the value.

All other slices and arrays are sent as an unsigned count followed by that many
elements using the standard gob encoding for their type, recursively.

Structs are sent as a sequence of (field number, field value) pairs.  The field
value is sent using the standard gob encoding for its type, recursively.  If a
field has the zero value for its type, it is omitted from the transmission.  The
field number is defined by the type of the encoded struct: the first field of the
encoded type is field 0, the second is field 1, etc.  When encoding a value, the
field numbers are delta encoded for efficiency and the fields are always sent in
order of increasing field number; the deltas are therefore unsigned.  The
initialization for the delta encoding sets the field number to -1, so an unsigned
integer field 0 with value 7 is transmitted as unsigned delta = 1, unsigned value
= 7 or (01 07).  Finally, after all the fields have been sent a terminating mark
denotes the end of the struct.  That mark is a delta=0 value, which has
representation (00).

Interface types are not checked for compatibility; all interface types are
treated, for transmission, as members of a single "interface" type, analogous to
int or []byte - in effect they're all treated as interface{}.  Interface values
are transmitted as a string identifying the concrete type being sent (a name
that must be pre-defined by calling Register()), followed by the usual encoding
of concrete (dynamic) value stored in the interface value.  (A nil interface
value is identified by the empty string and transmits no value.) Upon receipt,
the decoder verifies that the unpacked concrete item satisfies the interface of
the receiving variable.

The representation of types is described below.  When a type is defined on a given
connection between an Encoder and Decoder, it is assigned a signed integer type
id.  When Encoder.Encode(v) is called, it makes sure there is an id assigned for
the type of v and all its elements and then it sends the pair (typeid, encoded-v)
where typeid is the type id of the encoded type of v and encoded-v is the gob
encoding of the value v.

To define a type, the encoder chooses an unused, positive type id and sends the
pair (-type id, encoded-type) where encoded-type is the gob encoding of a wireType
description, constructed from these types:

	type wireType struct {
		s structType
	}
	type arrayType struct {
		commonType
		Elem typeId
		Len  int
	}
	type commonType {
		name string // the name of the struct type
		_id  int    // the id of the type, repeated for so it's inside the type
	}
	type sliceType struct {
		commonType
		Elem typeId
	}
	type structType struct {
		commonType
		field []*fieldType // the fields of the struct.
	}
	type fieldType struct {
		name string // the name of the field.
		id   int    // the type id of the field, which must be already defined
	}
	type mapType struct {
		commonType
		Key  typeId
		Elem typeId
	}

If there are nested type ids, the types for all inner type ids must be defined
before the top-level type id is used to describe an encoded-v.

For simplicity in setup, the connection is defined to understand these types a
priori, as well as the basic gob types int, uint, etc.  Their ids are:

	bool        1
	int         2
	uint        3
	float       4
	[]byte      5
	string      6
	complex     7
	interface   8
	// gap for reserved ids.
	wireType    16
	arrayType   17
	commonType  18
	sliceType   19
	structType  20
	fieldType   21
	// 22 is slice of fieldType.
	mapType     23

In summary, a gob stream looks like

	((-type id, encoding of a wireType)* (type id, encoding of a value))*

where * signifies zero or more repetitions and the type id of a value must
be predefined or be defined before the value in the stream.
*/
package gob

/*
For implementers and the curious, here is an encoded example.  Given
	type Point struct {x, y int}
and the value
	p := Point{22, 33}
the bytes transmitted that encode p will be:
	1f ff 81 03 01 01 05 50 6f 69 6e 74 01 ff 82 00
	01 02 01 01 78 01 04 00 01 01 79 01 04 00 00 00
	07 ff 82 01 2c 01 42 00
They are determined as follows.

Since this is the first transmission of type Point, the type descriptor
for Point itself must be sent before the value.  This is the first type
we've sent on this Encoder, so it has type id 65 (0 through 64 are
reserved).

	1f	// This item (a type descriptor) is 31 bytes long.
	ff 81	// The negative of the id for the type we're defining, -65.
		// This is one byte (indicated by FF = -1) followed by
		// ^-65<<1 | 1.  The low 1 bit signals to complement the
		// rest upon receipt.

	// Now we send a type descriptor, which is itself a struct (wireType).
	// The type of wireType itself is known (it's built in, as is the type of
	// all its components), so we just need to send a *value* of type wireType
	// that represents type "Point".
	// Here starts the encoding of that value.
	// Set the field number implicitly to -1; this is done at the beginning
	// of every struct, including nested structs.
	03	// Add 3 to field number; now 2 (wireType.structType; this is a struct).
		// structType starts with an embedded commonType, which appears
		// as a regular structure here too.
	01	// add 1 to field number (now 0); start of embedded commonType.
	01	// add 1 to field number (now 0, the name of the type)
	05	// string is (unsigned) 5 bytes long
	50 6f 69 6e 74	// wireType.structType.commonType.name = "Point"
	01	// add 1 to field number (now 1, the id of the type)
	ff 82	// wireType.structType.commonType._id = 65
	00	// end of embedded wiretype.structType.commonType struct
	01	// add 1 to field number (now 1, the field array in wireType.structType)
	02	// There are two fields in the type (len(structType.field))
	01	// Start of first field structure; add 1 to get field number 0: field[0].name
	01	// 1 byte
	78	// structType.field[0].name = "x"
	01	// Add 1 to get field number 1: field[0].id
	04	// structType.field[0].typeId is 2 (signed int).
	00	// End of structType.field[0]; start structType.field[1]; set field number to -1.
	01	// Add 1 to get field number 0: field[1].name
	01	// 1 byte
	79	// structType.field[1].name = "y"
	01	// Add 1 to get field number 1: field[0].id
	04	// struct.Type.field[1].typeId is 2 (signed int).
	00	// End of structType.field[1]; end of structType.field.
	00	// end of wireType.structType structure
	00	// end of wireType structure

Now we can send the Point value.  Again the field number resets to -1:

	07	// this value is 7 bytes long
	ff 82	// the type number, 65 (1 byte (-FF) followed by 65<<1)
	01	// add one to field number, yielding field 0
	2c	// encoding of signed "22" (0x22 = 44 = 22<<1); Point.x = 22
	01	// add one to field number, yielding field 1
	42	// encoding of signed "33" (0x42 = 66 = 33<<1); Point.y = 33
	00	// end of structure

The type encoding is long and fairly intricate but we send it only once.
If p is transmitted a second time, the type is already known so the
output will be just:

	07 ff 82 01 2c 01 42 00

A single non-struct value at top level is transmitted like a field with
delta tag 0.  For instance, a signed integer with value 3 presented as
the argument to Encode will emit:

	03 04 00 06

Which represents:

	03	// this value is 3 bytes long
	04	// the type number, 2, represents an integer
	00	// tag delta 0
	06	// value 3

*/
<commit_msg>gob: update documentation about wire format for interfaces.<commit_after>// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

/*
The gob package manages streams of gobs - binary values exchanged between an
Encoder (transmitter) and a Decoder (receiver).  A typical use is transporting
arguments and results of remote procedure calls (RPCs) such as those provided by
package "rpc".

A stream of gobs is self-describing.  Each data item in the stream is preceded by
a specification of its type, expressed in terms of a small set of predefined
types.  Pointers are not transmitted, but the things they point to are
transmitted; that is, the values are flattened.  Recursive types work fine, but
recursive values (data with cycles) are problematic.  This may change.

To use gobs, create an Encoder and present it with a series of data items as
values or addresses that can be dereferenced to values.  The Encoder makes sure
all type information is sent before it is needed.  At the receive side, a
Decoder retrieves values from the encoded stream and unpacks them into local
variables.

The source and destination values/types need not correspond exactly.  For structs,
fields (identified by name) that are in the source but absent from the receiving
variable will be ignored.  Fields that are in the receiving variable but missing
from the transmitted type or value will be ignored in the destination.  If a field
with the same name is present in both, their types must be compatible. Both the
receiver and transmitter will do all necessary indirection and dereferencing to
convert between gobs and actual Go values.  For instance, a gob type that is
schematically,

	struct { a, b int }

can be sent from or received into any of these Go types:

	struct { a, b int }	// the same
	*struct { a, b int }	// extra indirection of the struct
	struct { *a, **b int }	// extra indirection of the fields
	struct { a, b int64 }	// different concrete value type; see below

It may also be received into any of these:

	struct { a, b int }	// the same
	struct { b, a int }	// ordering doesn't matter; matching is by name
	struct { a, b, c int }	// extra field (c) ignored
	struct { b int }	// missing field (a) ignored; data will be dropped
	struct { b, c int }	// missing field (a) ignored; extra field (c) ignored.

Attempting to receive into these types will draw a decode error:

	struct { a int; b uint }	// change of signedness for b
	struct { a int; b float }	// change of type for b
	struct { }			// no field names in common
	struct { c, d int }		// no field names in common

Integers are transmitted two ways: arbitrary precision signed integers or
arbitrary precision unsigned integers.  There is no int8, int16 etc.
discrimination in the gob format; there are only signed and unsigned integers.  As
described below, the transmitter sends the value in a variable-length encoding;
the receiver accepts the value and stores it in the destination variable.
Floating-point numbers are always sent using IEEE-754 64-bit precision (see
below).

Signed integers may be received into any signed integer variable: int, int16, etc.;
unsigned integers may be received into any unsigned integer variable; and floating
point values may be received into any floating point variable.  However,
the destination variable must be able to represent the value or the decode
operation will fail.

Structs, arrays and slices are also supported.  Strings and arrays of bytes are
supported with a special, efficient representation (see below).

Interfaces, functions, and channels cannot be sent in a gob.  Attempting
to encode a value that contains one will fail.

The rest of this comment documents the encoding, details that are not important
for most users.  Details are presented bottom-up.

An unsigned integer is sent one of two ways.  If it is less than 128, it is sent
as a byte with that value.  Otherwise it is sent as a minimal-length big-endian
(high byte first) byte stream holding the value, preceded by one byte holding the
byte count, negated.  Thus 0 is transmitted as (00), 7 is transmitted as (07) and
256 is transmitted as (FE 01 00).

A boolean is encoded within an unsigned integer: 0 for false, 1 for true.

A signed integer, i, is encoded within an unsigned integer, u.  Within u, bits 1
upward contain the value; bit 0 says whether they should be complemented upon
receipt.  The encode algorithm looks like this:

	uint u;
	if i < 0 {
		u = (^i << 1) | 1	// complement i, bit 0 is 1
	} else {
		u = (i << 1)	// do not complement i, bit 0 is 0
	}
	encodeUnsigned(u)

The low bit is therefore analogous to a sign bit, but making it the complement bit
instead guarantees that the largest negative integer is not a special case.  For
example, -129=^128=(^256>>1) encodes as (FE 01 01).

Floating-point numbers are always sent as a representation of a float64 value.
That value is converted to a uint64 using math.Float64bits.  The uint64 is then
byte-reversed and sent as a regular unsigned integer.  The byte-reversal means the
exponent and high-precision part of the mantissa go first.  Since the low bits are
often zero, this can save encoding bytes.  For instance, 17.0 is encoded in only
three bytes (FE 31 40).

Strings and slices of bytes are sent as an unsigned count followed by that many
uninterpreted bytes of the value.

All other slices and arrays are sent as an unsigned count followed by that many
elements using the standard gob encoding for their type, recursively.

Structs are sent as a sequence of (field number, field value) pairs.  The field
value is sent using the standard gob encoding for its type, recursively.  If a
field has the zero value for its type, it is omitted from the transmission.  The
field number is defined by the type of the encoded struct: the first field of the
encoded type is field 0, the second is field 1, etc.  When encoding a value, the
field numbers are delta encoded for efficiency and the fields are always sent in
order of increasing field number; the deltas are therefore unsigned.  The
initialization for the delta encoding sets the field number to -1, so an unsigned
integer field 0 with value 7 is transmitted as unsigned delta = 1, unsigned value
= 7 or (01 07).  Finally, after all the fields have been sent a terminating mark
denotes the end of the struct.  That mark is a delta=0 value, which has
representation (00).

Interface types are not checked for compatibility; all interface types are
treated, for transmission, as members of a single "interface" type, analogous to
int or []byte - in effect they're all treated as interface{}.  Interface values
are transmitted as a string identifying the concrete type being sent (a name
that must be pre-defined by calling Register), followed by a byte count of the
length of the following data (so the value can be skipped if it cannot be
stored), followed by the usual encoding of concrete (dynamic) value stored in
the interface value.  (A nil interface value is identified by the empty string
and transmits a zero-length value.) Upon receipt, the decoder verifies that the
unpacked concrete item satisfies the interface of the receiving variable.

The representation of types is described below.  When a type is defined on a given
connection between an Encoder and Decoder, it is assigned a signed integer type
id.  When Encoder.Encode(v) is called, it makes sure there is an id assigned for
the type of v and all its elements and then it sends the pair (typeid, encoded-v)
where typeid is the type id of the encoded type of v and encoded-v is the gob
encoding of the value v.

To define a type, the encoder chooses an unused, positive type id and sends the
pair (-type id, encoded-type) where encoded-type is the gob encoding of a wireType
description, constructed from these types:

	type wireType struct {
		s structType
	}
	type arrayType struct {
		commonType
		Elem typeId
		Len  int
	}
	type commonType {
		name string // the name of the struct type
		_id  int    // the id of the type, repeated for so it's inside the type
	}
	type sliceType struct {
		commonType
		Elem typeId
	}
	type structType struct {
		commonType
		field []*fieldType // the fields of the struct.
	}
	type fieldType struct {
		name string // the name of the field.
		id   int    // the type id of the field, which must be already defined
	}
	type mapType struct {
		commonType
		Key  typeId
		Elem typeId
	}

If there are nested type ids, the types for all inner type ids must be defined
before the top-level type id is used to describe an encoded-v.

For simplicity in setup, the connection is defined to understand these types a
priori, as well as the basic gob types int, uint, etc.  Their ids are:

	bool        1
	int         2
	uint        3
	float       4
	[]byte      5
	string      6
	complex     7
	interface   8
	// gap for reserved ids.
	wireType    16
	arrayType   17
	commonType  18
	sliceType   19
	structType  20
	fieldType   21
	// 22 is slice of fieldType.
	mapType     23

In summary, a gob stream looks like

	((-type id, encoding of a wireType)* (type id, encoding of a value))*

where * signifies zero or more repetitions and the type id of a value must
be predefined or be defined before the value in the stream.
*/
package gob

/*
For implementers and the curious, here is an encoded example.  Given
	type Point struct {x, y int}
and the value
	p := Point{22, 33}
the bytes transmitted that encode p will be:
	1f ff 81 03 01 01 05 50 6f 69 6e 74 01 ff 82 00
	01 02 01 01 78 01 04 00 01 01 79 01 04 00 00 00
	07 ff 82 01 2c 01 42 00
They are determined as follows.

Since this is the first transmission of type Point, the type descriptor
for Point itself must be sent before the value.  This is the first type
we've sent on this Encoder, so it has type id 65 (0 through 64 are
reserved).

	1f	// This item (a type descriptor) is 31 bytes long.
	ff 81	// The negative of the id for the type we're defining, -65.
		// This is one byte (indicated by FF = -1) followed by
		// ^-65<<1 | 1.  The low 1 bit signals to complement the
		// rest upon receipt.

	// Now we send a type descriptor, which is itself a struct (wireType).
	// The type of wireType itself is known (it's built in, as is the type of
	// all its components), so we just need to send a *value* of type wireType
	// that represents type "Point".
	// Here starts the encoding of that value.
	// Set the field number implicitly to -1; this is done at the beginning
	// of every struct, including nested structs.
	03	// Add 3 to field number; now 2 (wireType.structType; this is a struct).
		// structType starts with an embedded commonType, which appears
		// as a regular structure here too.
	01	// add 1 to field number (now 0); start of embedded commonType.
	01	// add 1 to field number (now 0, the name of the type)
	05	// string is (unsigned) 5 bytes long
	50 6f 69 6e 74	// wireType.structType.commonType.name = "Point"
	01	// add 1 to field number (now 1, the id of the type)
	ff 82	// wireType.structType.commonType._id = 65
	00	// end of embedded wiretype.structType.commonType struct
	01	// add 1 to field number (now 1, the field array in wireType.structType)
	02	// There are two fields in the type (len(structType.field))
	01	// Start of first field structure; add 1 to get field number 0: field[0].name
	01	// 1 byte
	78	// structType.field[0].name = "x"
	01	// Add 1 to get field number 1: field[0].id
	04	// structType.field[0].typeId is 2 (signed int).
	00	// End of structType.field[0]; start structType.field[1]; set field number to -1.
	01	// Add 1 to get field number 0: field[1].name
	01	// 1 byte
	79	// structType.field[1].name = "y"
	01	// Add 1 to get field number 1: field[0].id
	04	// struct.Type.field[1].typeId is 2 (signed int).
	00	// End of structType.field[1]; end of structType.field.
	00	// end of wireType.structType structure
	00	// end of wireType structure

Now we can send the Point value.  Again the field number resets to -1:

	07	// this value is 7 bytes long
	ff 82	// the type number, 65 (1 byte (-FF) followed by 65<<1)
	01	// add one to field number, yielding field 0
	2c	// encoding of signed "22" (0x22 = 44 = 22<<1); Point.x = 22
	01	// add one to field number, yielding field 1
	42	// encoding of signed "33" (0x42 = 66 = 33<<1); Point.y = 33
	00	// end of structure

The type encoding is long and fairly intricate but we send it only once.
If p is transmitted a second time, the type is already known so the
output will be just:

	07 ff 82 01 2c 01 42 00

A single non-struct value at top level is transmitted like a field with
delta tag 0.  For instance, a signed integer with value 3 presented as
the argument to Encode will emit:

	03 04 00 06

Which represents:

	03	// this value is 3 bytes long
	04	// the type number, 2, represents an integer
	00	// tag delta 0
	06	// value 3

*/
<|endoftext|>


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

// HTTP file system request handler

package http

import (
	"fmt"
	"io"
	"mime"
	"os"
	"path"
	"path/filepath"
	"strconv"
	"strings"
	"time"
	"utf8"
)

// A Dir implements http.FileSystem using the native file
// system restricted to a specific directory tree.
type Dir string

func (d Dir) Open(name string) (File, os.Error) {
	if filepath.Separator != '/' && strings.IndexRune(name, filepath.Separator) >= 0 {
		return nil, os.NewError("http: invalid character in file path")
	}
	f, err := os.Open(filepath.Join(string(d), filepath.FromSlash(path.Clean("/"+name))))
	if err != nil {
		return nil, err
	}
	return f, nil
}

// A FileSystem implements access to a collection of named files.
// The elements in a file path are separated by slash ('/', U+002F)
// characters, regardless of host operating system convention.
type FileSystem interface {
	Open(name string) (File, os.Error)
}

// A File is returned by a FileSystem's Open method and can be
// served by the FileServer implementation.
type File interface {
	Close() os.Error
	Stat() (*os.FileInfo, os.Error)
	Readdir(count int) ([]os.FileInfo, os.Error)
	Read([]byte) (int, os.Error)
	Seek(offset int64, whence int) (int64, os.Error)
}

// Heuristic: b is text if it is valid UTF-8 and doesn't
// contain any unprintable ASCII or Unicode characters.
func isText(b []byte) bool {
	for len(b) > 0 && utf8.FullRune(b) {
		rune, size := utf8.DecodeRune(b)
		if size == 1 && rune == utf8.RuneError {
			// decoding error
			return false
		}
		if 0x7F <= rune && rune <= 0x9F {
			return false
		}
		if rune < ' ' {
			switch rune {
			case '\n', '\r', '\t':
				// okay
			default:
				// binary garbage
				return false
			}
		}
		b = b[size:]
	}
	return true
}

func dirList(w ResponseWriter, f File) {
	fmt.Fprintf(w, "
\n")
	for {
		dirs, err := f.Readdir(100)
		if err != nil || len(dirs) == 0 {
			break
		}
		for _, d := range dirs {
			name := d.Name
			if d.IsDirectory() {
				name += "/"
			}
			// TODO htmlescape
			fmt.Fprintf(w, "%s\n", name, name)
		}
	}
	fmt.Fprintf(w, "
\n")
}

// name is '/'-separated, not filepath.Separator.
func serveFile(w ResponseWriter, r *Request, fs FileSystem, name string, redirect bool) {
	const indexPage = "/index.html"

	// redirect .../index.html to .../
	if strings.HasSuffix(r.URL.Path, indexPage) {
		Redirect(w, r, r.URL.Path[0:len(r.URL.Path)-len(indexPage)+1], StatusMovedPermanently)
		return
	}

	f, err := fs.Open(name)
	if err != nil {
		// TODO expose actual error?
		NotFound(w, r)
		return
	}
	defer f.Close()

	d, err1 := f.Stat()
	if err1 != nil {
		// TODO expose actual error?
		NotFound(w, r)
		return
	}

	if redirect {
		// redirect to canonical path: / at end of directory url
		// r.URL.Path always begins with /
		url := r.URL.Path
		if d.IsDirectory() {
			if url[len(url)-1] != '/' {
				Redirect(w, r, url+"/", StatusMovedPermanently)
				return
			}
		} else {
			if url[len(url)-1] == '/' {
				Redirect(w, r, url[0:len(url)-1], StatusMovedPermanently)
				return
			}
		}
	}

	if t, _ := time.Parse(TimeFormat, r.Header.Get("If-Modified-Since")); t != nil && d.Mtime_ns/1e9 <= t.Seconds() {
		w.WriteHeader(StatusNotModified)
		return
	}
	w.Header().Set("Last-Modified", time.SecondsToUTC(d.Mtime_ns/1e9).Format(TimeFormat))

	// use contents of index.html for directory, if present
	if d.IsDirectory() {
		index := name + filepath.FromSlash(indexPage)
		ff, err := fs.Open(index)
		if err == nil {
			defer ff.Close()
			dd, err := ff.Stat()
			if err == nil {
				name = index
				d = dd
				f = ff
			}
		}
	}

	if d.IsDirectory() {
		dirList(w, f)
		return
	}

	// serve file
	size := d.Size
	code := StatusOK

	// If Content-Type isn't set, use the file's extension to find it.
	if w.Header().Get("Content-Type") == "" {
		ctype := mime.TypeByExtension(filepath.Ext(name))
		if ctype == "" {
			// read a chunk to decide between utf-8 text and binary
			var buf [1024]byte
			n, _ := io.ReadFull(f, buf[:])
			b := buf[:n]
			if isText(b) {
				ctype = "text/plain; charset=utf-8"
			} else {
				// generic binary
				ctype = "application/octet-stream"
			}
			f.Seek(0, os.SEEK_SET) // rewind to output whole file
		}
		w.Header().Set("Content-Type", ctype)
	}

	// handle Content-Range header.
	// TODO(adg): handle multiple ranges
	ranges, err := parseRange(r.Header.Get("Range"), size)
	if err == nil && len(ranges) > 1 {
		err = os.NewError("multiple ranges not supported")
	}
	if err != nil {
		Error(w, err.String(), StatusRequestedRangeNotSatisfiable)
		return
	}
	if len(ranges) == 1 {
		ra := ranges[0]
		if _, err := f.Seek(ra.start, os.SEEK_SET); err != nil {
			Error(w, err.String(), StatusRequestedRangeNotSatisfiable)
			return
		}
		size = ra.length
		code = StatusPartialContent
		w.Header().Set("Content-Range", fmt.Sprintf("bytes %d-%d/%d", ra.start, ra.start+ra.length-1, d.Size))
	}

	w.Header().Set("Accept-Ranges", "bytes")
	if w.Header().Get("Content-Encoding") == "" {
		w.Header().Set("Content-Length", strconv.Itoa64(size))
	}

	w.WriteHeader(code)

	if r.Method != "HEAD" {
		io.Copyn(w, f, size)
	}
}

// ServeFile replies to the request with the contents of the named file or directory.
func ServeFile(w ResponseWriter, r *Request, name string) {
	dir, file := filepath.Split(name)
	serveFile(w, r, Dir(dir), file, false)
}

type fileHandler struct {
	root FileSystem
}

// FileServer returns a handler that serves HTTP requests
// with the contents of the file system rooted at root.
//
// To use the operating system's file system implementation,
// use http.Dir:
//
//     http.Handle("/", http.FileServer(http.Dir("/tmp")))
func FileServer(root FileSystem) Handler {
	return &fileHandler{root}
}

func (f *fileHandler) ServeHTTP(w ResponseWriter, r *Request) {
	upath := r.URL.Path
	if !strings.HasPrefix(upath, "/") {
		upath = "/" + upath
		r.URL.Path = upath
	}
	serveFile(w, r, f.root, path.Clean(upath), true)
}

// httpRange specifies the byte range to be sent to the client.
type httpRange struct {
	start, length int64
}

// parseRange parses a Range header string as per RFC 2616.
func parseRange(s string, size int64) ([]httpRange, os.Error) {
	if s == "" {
		return nil, nil // header not present
	}
	const b = "bytes="
	if !strings.HasPrefix(s, b) {
		return nil, os.NewError("invalid range")
	}
	var ranges []httpRange
	for _, ra := range strings.Split(s[len(b):], ",") {
		i := strings.Index(ra, "-")
		if i < 0 {
			return nil, os.NewError("invalid range")
		}
		start, end := ra[:i], ra[i+1:]
		var r httpRange
		if start == "" {
			// If no start is specified, end specifies the
			// range start relative to the end of the file.
			i, err := strconv.Atoi64(end)
			if err != nil {
				return nil, os.NewError("invalid range")
			}
			if i > size {
				i = size
			}
			r.start = size - i
			r.length = size - r.start
		} else {
			i, err := strconv.Atoi64(start)
			if err != nil || i > size || i < 0 {
				return nil, os.NewError("invalid range")
			}
			r.start = i
			if end == "" {
				// If no end is specified, range extends to end of the file.
				r.length = size - r.start
			} else {
				i, err := strconv.Atoi64(end)
				if err != nil || r.start > i {
					return nil, os.NewError("invalid range")
				}
				if i >= size {
					i = size - 1
				}
				r.length = i - r.start + 1
			}
		}
		ranges = append(ranges, r)
	}
	return ranges, nil
}
<commit_msg>http: set content type for fileserver directory listings<commit_after>// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// HTTP file system request handler

package http

import (
	"fmt"
	"io"
	"mime"
	"os"
	"path"
	"path/filepath"
	"strconv"
	"strings"
	"time"
	"utf8"
)

// A Dir implements http.FileSystem using the native file
// system restricted to a specific directory tree.
type Dir string

func (d Dir) Open(name string) (File, os.Error) {
	if filepath.Separator != '/' && strings.IndexRune(name, filepath.Separator) >= 0 {
		return nil, os.NewError("http: invalid character in file path")
	}
	f, err := os.Open(filepath.Join(string(d), filepath.FromSlash(path.Clean("/"+name))))
	if err != nil {
		return nil, err
	}
	return f, nil
}

// A FileSystem implements access to a collection of named files.
// The elements in a file path are separated by slash ('/', U+002F)
// characters, regardless of host operating system convention.
type FileSystem interface {
	Open(name string) (File, os.Error)
}

// A File is returned by a FileSystem's Open method and can be
// served by the FileServer implementation.
type File interface {
	Close() os.Error
	Stat() (*os.FileInfo, os.Error)
	Readdir(count int) ([]os.FileInfo, os.Error)
	Read([]byte) (int, os.Error)
	Seek(offset int64, whence int) (int64, os.Error)
}

// Heuristic: b is text if it is valid UTF-8 and doesn't
// contain any unprintable ASCII or Unicode characters.
func isText(b []byte) bool {
	for len(b) > 0 && utf8.FullRune(b) {
		rune, size := utf8.DecodeRune(b)
		if size == 1 && rune == utf8.RuneError {
			// decoding error
			return false
		}
		if 0x7F <= rune && rune <= 0x9F {
			return false
		}
		if rune < ' ' {
			switch rune {
			case '\n', '\r', '\t':
				// okay
			default:
				// binary garbage
				return false
			}
		}
		b = b[size:]
	}
	return true
}

func dirList(w ResponseWriter, f File) {
	w.Header().Set("Content-Type", "text/html; charset=utf-8")
	fmt.Fprintf(w, "
\n")
	for {
		dirs, err := f.Readdir(100)
		if err != nil || len(dirs) == 0 {
			break
		}
		for _, d := range dirs {
			name := d.Name
			if d.IsDirectory() {
				name += "/"
			}
			// TODO htmlescape
			fmt.Fprintf(w, "%s\n", name, name)
		}
	}
	fmt.Fprintf(w, "
\n")
}

// name is '/'-separated, not filepath.Separator.
func serveFile(w ResponseWriter, r *Request, fs FileSystem, name string, redirect bool) {
	const indexPage = "/index.html"

	// redirect .../index.html to .../
	if strings.HasSuffix(r.URL.Path, indexPage) {
		Redirect(w, r, r.URL.Path[0:len(r.URL.Path)-len(indexPage)+1], StatusMovedPermanently)
		return
	}

	f, err := fs.Open(name)
	if err != nil {
		// TODO expose actual error?
		NotFound(w, r)
		return
	}
	defer f.Close()

	d, err1 := f.Stat()
	if err1 != nil {
		// TODO expose actual error?
		NotFound(w, r)
		return
	}

	if redirect {
		// redirect to canonical path: / at end of directory url
		// r.URL.Path always begins with /
		url := r.URL.Path
		if d.IsDirectory() {
			if url[len(url)-1] != '/' {
				Redirect(w, r, url+"/", StatusMovedPermanently)
				return
			}
		} else {
			if url[len(url)-1] == '/' {
				Redirect(w, r, url[0:len(url)-1], StatusMovedPermanently)
				return
			}
		}
	}

	if t, _ := time.Parse(TimeFormat, r.Header.Get("If-Modified-Since")); t != nil && d.Mtime_ns/1e9 <= t.Seconds() {
		w.WriteHeader(StatusNotModified)
		return
	}
	w.Header().Set("Last-Modified", time.SecondsToUTC(d.Mtime_ns/1e9).Format(TimeFormat))

	// use contents of index.html for directory, if present
	if d.IsDirectory() {
		index := name + filepath.FromSlash(indexPage)
		ff, err := fs.Open(index)
		if err == nil {
			defer ff.Close()
			dd, err := ff.Stat()
			if err == nil {
				name = index
				d = dd
				f = ff
			}
		}
	}

	if d.IsDirectory() {
		dirList(w, f)
		return
	}

	// serve file
	size := d.Size
	code := StatusOK

	// If Content-Type isn't set, use the file's extension to find it.
	if w.Header().Get("Content-Type") == "" {
		ctype := mime.TypeByExtension(filepath.Ext(name))
		if ctype == "" {
			// read a chunk to decide between utf-8 text and binary
			var buf [1024]byte
			n, _ := io.ReadFull(f, buf[:])
			b := buf[:n]
			if isText(b) {
				ctype = "text/plain; charset=utf-8"
			} else {
				// generic binary
				ctype = "application/octet-stream"
			}
			f.Seek(0, os.SEEK_SET) // rewind to output whole file
		}
		w.Header().Set("Content-Type", ctype)
	}

	// handle Content-Range header.
	// TODO(adg): handle multiple ranges
	ranges, err := parseRange(r.Header.Get("Range"), size)
	if err == nil && len(ranges) > 1 {
		err = os.NewError("multiple ranges not supported")
	}
	if err != nil {
		Error(w, err.String(), StatusRequestedRangeNotSatisfiable)
		return
	}
	if len(ranges) == 1 {
		ra := ranges[0]
		if _, err := f.Seek(ra.start, os.SEEK_SET); err != nil {
			Error(w, err.String(), StatusRequestedRangeNotSatisfiable)
			return
		}
		size = ra.length
		code = StatusPartialContent
		w.Header().Set("Content-Range", fmt.Sprintf("bytes %d-%d/%d", ra.start, ra.start+ra.length-1, d.Size))
	}

	w.Header().Set("Accept-Ranges", "bytes")
	if w.Header().Get("Content-Encoding") == "" {
		w.Header().Set("Content-Length", strconv.Itoa64(size))
	}

	w.WriteHeader(code)

	if r.Method != "HEAD" {
		io.Copyn(w, f, size)
	}
}

// ServeFile replies to the request with the contents of the named file or directory.
func ServeFile(w ResponseWriter, r *Request, name string) {
	dir, file := filepath.Split(name)
	serveFile(w, r, Dir(dir), file, false)
}

type fileHandler struct {
	root FileSystem
}

// FileServer returns a handler that serves HTTP requests
// with the contents of the file system rooted at root.
//
// To use the operating system's file system implementation,
// use http.Dir:
//
//     http.Handle("/", http.FileServer(http.Dir("/tmp")))
func FileServer(root FileSystem) Handler {
	return &fileHandler{root}
}

func (f *fileHandler) ServeHTTP(w ResponseWriter, r *Request) {
	upath := r.URL.Path
	if !strings.HasPrefix(upath, "/") {
		upath = "/" + upath
		r.URL.Path = upath
	}
	serveFile(w, r, f.root, path.Clean(upath), true)
}

// httpRange specifies the byte range to be sent to the client.
type httpRange struct {
	start, length int64
}

// parseRange parses a Range header string as per RFC 2616.
func parseRange(s string, size int64) ([]httpRange, os.Error) {
	if s == "" {
		return nil, nil // header not present
	}
	const b = "bytes="
	if !strings.HasPrefix(s, b) {
		return nil, os.NewError("invalid range")
	}
	var ranges []httpRange
	for _, ra := range strings.Split(s[len(b):], ",") {
		i := strings.Index(ra, "-")
		if i < 0 {
			return nil, os.NewError("invalid range")
		}
		start, end := ra[:i], ra[i+1:]
		var r httpRange
		if start == "" {
			// If no start is specified, end specifies the
			// range start relative to the end of the file.
			i, err := strconv.Atoi64(end)
			if err != nil {
				return nil, os.NewError("invalid range")
			}
			if i > size {
				i = size
			}
			r.start = size - i
			r.length = size - r.start
		} else {
			i, err := strconv.Atoi64(start)
			if err != nil || i > size || i < 0 {
				return nil, os.NewError("invalid range")
			}
			r.start = i
			if end == "" {
				// If no end is specified, range extends to end of the file.
				r.length = size - r.start
			} else {
				i, err := strconv.Atoi64(end)
				if err != nil || r.start > i {
					return nil, os.NewError("invalid range")
				}
				if i >= size {
					i = size - 1
				}
				r.length = i - r.start + 1
			}
		}
		ranges = append(ranges, r)
	}
	return ranges, nil
}
<|endoftext|>


<commit_before>package web

import (
	"doozer/store"
	"doozer/util"
	"http"
	"io"
	"json"
	"log"
	"net"
	"runtime"
	"strings"
	"template"
	"websocket"
)

var Store *store.Store
var ClusterName, evPrefix string

var (
	mainTpl  = template.MustParse(main_html, nil)
	statsTpl = template.MustParse(stats_html, nil)
)

type info struct {
	Path string
}

type stringHandler struct {
	contentType string
	body        string
}

func (sh stringHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	w.SetHeader("content-type", sh.contentType)
	io.WriteString(w, sh.body)
}

func Serve(listener net.Listener) {
	prefix := "/d/" + ClusterName
	evPrefix = "/events" + prefix

	http.Handle("/", http.RedirectHandler("/view/d/"+ClusterName+"/", 307))
	http.HandleFunc("/stats.html", statsHtml)
	http.HandleFunc("/view/", viewHtml)
	http.Handle("/main.js", stringHandler{"application/javascript", main_js})
	http.Handle("/main.css", stringHandler{"text/css", main_css})
	http.HandleFunc(evPrefix+"/", evServer)

	http.Serve(listener, nil)
}

func send(ws *websocket.Conn, path string, evs <-chan store.Event, logger *log.Logger) {
	defer close(evs)
	l := len(path) - 1
	for ev := range evs {
		ev.Getter = nil // don't marshal the entire snapshot
		ev.Path = ev.Path[l:]
		logger.Println("sending", ev)
		b, err := json.Marshal(ev)
		if err != nil {
			logger.Println(err)
			return
		}
		_, err = ws.Write(b)
		if err != nil {
			logger.Println(err)
			return
		}
	}
}

func evServer(w http.ResponseWriter, r *http.Request) {
	wevs := make(chan store.Event)
	logger := util.NewLogger(w.RemoteAddr())
	path := r.URL.Path[len(evPrefix):]
	logger.Println("new", path)

	glob, err := store.CompileGlob(path + "**")
	if err != nil {
		w.WriteHeader(400)
		return
	}

	wt := store.NewWatch(Store, glob)

	// TODO convert store.Snapshot to json and use that
	go func() {
		walk(path, Store, wevs)
		close(wevs)
	}()

	websocket.Handler(func(ws *websocket.Conn) {
		send(ws, path, wevs, logger)
		send(ws, path, wt.C, logger)
		wt.Stop()
		ws.Close()
	}).ServeHTTP(w, r)
}

func viewHtml(w http.ResponseWriter, r *http.Request) {
	if !strings.HasSuffix(r.URL.Path, "/") {
		w.WriteHeader(404)
		return
	}
	var x info
	x.Path = r.URL.Path[len("/view"):]
	w.SetHeader("content-type", "text/html")
	mainTpl.Execute(w, x)
}

func statsHtml(w http.ResponseWriter, r *http.Request) {
	w.SetHeader("content-type", "text/html")
	statsTpl.Execute(w, runtime.MemStats)
}

func walk(path string, st *store.Store, ch chan store.Event) {
	for path != "/" && strings.HasSuffix(path, "/") {
		// TODO generalize and factor this into pkg store.
		path = path[0 : len(path)-1]
	}
	v, cas := st.Get(path)
	if cas != store.Dir {
		ch <- store.Event{0, path, v[0], cas, "", nil, nil}
		return
	}
	if path == "/" {
		path = ""
	}
	for _, ent := range v {
		walk(path+"/"+ent, st, ch)
	}
}
<commit_msg>web: don't close the event chan<commit_after>package web

import (
	"doozer/store"
	"doozer/util"
	"http"
	"io"
	"json"
	"log"
	"net"
	"runtime"
	"strings"
	"template"
	"websocket"
)

var Store *store.Store
var ClusterName, evPrefix string

var (
	mainTpl  = template.MustParse(main_html, nil)
	statsTpl = template.MustParse(stats_html, nil)
)

type info struct {
	Path string
}

type stringHandler struct {
	contentType string
	body        string
}

func (sh stringHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	w.SetHeader("content-type", sh.contentType)
	io.WriteString(w, sh.body)
}

func Serve(listener net.Listener) {
	prefix := "/d/" + ClusterName
	evPrefix = "/events" + prefix

	http.Handle("/", http.RedirectHandler("/view/d/"+ClusterName+"/", 307))
	http.HandleFunc("/stats.html", statsHtml)
	http.HandleFunc("/view/", viewHtml)
	http.Handle("/main.js", stringHandler{"application/javascript", main_js})
	http.Handle("/main.css", stringHandler{"text/css", main_css})
	http.HandleFunc(evPrefix+"/", evServer)

	http.Serve(listener, nil)
}

func send(ws *websocket.Conn, path string, evs <-chan store.Event, logger *log.Logger) {
	l := len(path) - 1
	for ev := range evs {
		ev.Getter = nil // don't marshal the entire snapshot
		ev.Path = ev.Path[l:]
		logger.Println("sending", ev)
		b, err := json.Marshal(ev)
		if err != nil {
			logger.Println(err)
			return
		}
		_, err = ws.Write(b)
		if err != nil {
			logger.Println(err)
			return
		}
	}
}

func evServer(w http.ResponseWriter, r *http.Request) {
	wevs := make(chan store.Event)
	logger := util.NewLogger(w.RemoteAddr())
	path := r.URL.Path[len(evPrefix):]
	logger.Println("new", path)

	glob, err := store.CompileGlob(path + "**")
	if err != nil {
		w.WriteHeader(400)
		return
	}

	wt := store.NewWatch(Store, glob)

	// TODO convert store.Snapshot to json and use that
	go func() {
		walk(path, Store, wevs)
		close(wevs)
	}()

	websocket.Handler(func(ws *websocket.Conn) {
		send(ws, path, wevs, logger)
		send(ws, path, wt.C, logger)
		wt.Stop()
		ws.Close()
	}).ServeHTTP(w, r)
}

func viewHtml(w http.ResponseWriter, r *http.Request) {
	if !strings.HasSuffix(r.URL.Path, "/") {
		w.WriteHeader(404)
		return
	}
	var x info
	x.Path = r.URL.Path[len("/view"):]
	w.SetHeader("content-type", "text/html")
	mainTpl.Execute(w, x)
}

func statsHtml(w http.ResponseWriter, r *http.Request) {
	w.SetHeader("content-type", "text/html")
	statsTpl.Execute(w, runtime.MemStats)
}

func walk(path string, st *store.Store, ch chan store.Event) {
	for path != "/" && strings.HasSuffix(path, "/") {
		// TODO generalize and factor this into pkg store.
		path = path[0 : len(path)-1]
	}
	v, cas := st.Get(path)
	if cas != store.Dir {
		ch <- store.Event{0, path, v[0], cas, "", nil, nil}
		return
	}
	if path == "/" {
		path = ""
	}
	for _, ent := range v {
		walk(path+"/"+ent, st, ch)
	}
}
<|endoftext|>