<commit_before>package api

// StorageVolumesPost represents the fields of a new LXD storage pool volume
//
// API extension: storage
type StorageVolumesPost struct {
	StorageVolumePut `yaml:",inline"`

	Name string `json:"name" yaml:"name"`
	Type string `json:"type" yaml:"type"`

	// API extension: storage_api_local_volume_handling
	Source StorageVolumeSource `json:"source" yaml:"source"`

	// API extension: custom_block_volumes
	ContentType string `json:"content_type" yaml:"content_type"`
}

// StorageVolumePost represents the fields required to rename a LXD storage pool volume
//
// API extension: storage_api_volume_rename
type StorageVolumePost struct {
	Name string `json:"name" yaml:"name"`

	// API extension: storage_api_local_volume_handling
	Pool string `json:"pool,omitempty" yaml:"pool,omitempty"`

	// API extension: storage_api_remote_volume_handling
	Migration bool `json:"migration" yaml:"migration"`

	// API extension: storage_api_remote_volume_handling
	Target *StorageVolumePostTarget `json:"target" yaml:"target"`

	// API extension: storage_api_remote_volume_snapshots
	VolumeOnly bool `json:"volume_only" yaml:"volume_only"`
}

// StorageVolumePostTarget represents the migration target host and operation
//
// API extension: storage_api_remote_volume_handling
type StorageVolumePostTarget struct {
	Certificate string            `json:"certificate" yaml:"certificate"`
	Operation   string            `json:"operation,omitempty" yaml:"operation,omitempty"`
	Websockets  map[string]string `json:"secrets,omitempty" yaml:"secrets,omitempty"`
}

// StorageVolume represents the fields of a LXD storage volume.
//
// API extension: storage
type StorageVolume struct {
	StorageVolumePut `yaml:",inline"`
	Name             string   `json:"name" yaml:"name"`
	Type             string   `json:"type" yaml:"type"`
	UsedBy           []string `json:"used_by" yaml:"used_by"`

	// API extension: clustering
	Location string `json:"location" yaml:"location"`

	// API extension: custom_block_volumes
	ContentType string `json:"content_type" yaml:"content_type"`
}

// StorageVolumePut represents the modifiable fields of a LXD storage volume.
//
// API extension: storage
type StorageVolumePut struct {
	Config map[string]string `json:"config" yaml:"config"`

	// API extension: entity_description
	Description string `json:"description" yaml:"description"`

	// API extension: storage_api_volume_snapshots
	Restore string `json:"restore,omitempty" yaml:"restore,omitempty"`
}

// StorageVolumeSource represents the creation source for a new storage volume.
//
// API extension: storage_api_local_volume_handling
type StorageVolumeSource struct {
	Name string `json:"name" yaml:"name"`
	Type string `json:"type" yaml:"type"`
	Pool string `json:"pool" yaml:"pool"`

	// API extension: storage_api_remote_volume_handling
	Certificate string            `json:"certificate" yaml:"certificate"`
	Mode        string            `json:"mode,omitempty" yaml:"mode,omitempty"`
	Operation   string            `json:"operation,omitempty" yaml:"operation,omitempty"`
	Websockets  map[string]string `json:"secrets,omitempty" yaml:"secrets,omitempty"`

	// API extension: storage_api_volume_snapshots
	VolumeOnly bool `json:"volume_only" yaml:"volume_only"`
}
<commit_msg>shared/api: Add swagger metadata to storage volumes<commit_after>package api

// StorageVolumesPost represents the fields of a new LXD storage pool volume
//
// swagger:model
//
// API extension: storage
type StorageVolumesPost struct {
	StorageVolumePut `yaml:",inline"`

	// Volume name
	// Example: foo
	Name string `json:"name" yaml:"name"`

	// Volume type (container, custom, image or virtual-machine)
	// Example: custom
	Type string `json:"type" yaml:"type"`

	// Migration source
	//
	// API extension: storage_api_local_volume_handling
	Source StorageVolumeSource `json:"source" yaml:"source"`

	// Volume content type (filesystem or block)
	// Example: filesystem
	//
	// API extension: custom_block_volumes
	ContentType string `json:"content_type" yaml:"content_type"`
}

// StorageVolumePost represents the fields required to rename a LXD storage pool volume
//
// swagger:model
//
// API extension: storage_api_volume_rename
type StorageVolumePost struct {
	// New volume name
	// Example: foo
	Name string `json:"name" yaml:"name"`

	// New storage pool
	// Example: remote
	//
	// API extension: storage_api_local_volume_handling
	Pool string `json:"pool,omitempty" yaml:"pool,omitempty"`

	// Initiate volume migration
	// Example: false
	//
	// API extension: storage_api_remote_volume_handling
	Migration bool `json:"migration" yaml:"migration"`

	// Migration target (for push mode)
	//
	// API extension: storage_api_remote_volume_handling
	Target *StorageVolumePostTarget `json:"target" yaml:"target"`

	// Whether snapshots should be discarded (migration only)
	// Example: false
	//
	// API extension: storage_api_remote_volume_snapshots
	VolumeOnly bool `json:"volume_only" yaml:"volume_only"`
}

// StorageVolumePostTarget represents the migration target host and operation
//
// swagger:model
//
// API extension: storage_api_remote_volume_handling
type StorageVolumePostTarget struct {
	// The certificate of the migration target
	// Example: X509 PEM certificate
	Certificate string `json:"certificate" yaml:"certificate"`

	// Remote operation URL (for migration)
	// Example: https://1.2.3.4:8443/1.0/operations/1721ae08-b6a8-416a-9614-3f89302466e1
	Operation string `json:"operation,omitempty" yaml:"operation,omitempty"`

	// Migration websockets credentials
	// Example: {"migration": "random-string"}
	Websockets map[string]string `json:"secrets,omitempty" yaml:"secrets,omitempty"`
}

// StorageVolume represents the fields of a LXD storage volume.
//
// swagger:model
//
// API extension: storage
type StorageVolume struct {
	StorageVolumePut `yaml:",inline"`

	// Volume name
	// Example: foo
	Name string `json:"name" yaml:"name"`

	// Volume type
	// Example: custom
	Type string `json:"type" yaml:"type"`

	// List of URLs of objects using this storage volume
	// Example: ["/1.0/instances/blah"]
	UsedBy []string `json:"used_by" yaml:"used_by"`

	// What cluster member this record was found on
	// Example: lxd01
	//
	// API extension: clustering
	Location string `json:"location" yaml:"location"`

	// Volume content type (filesystem or block)
	// Example: filesystem
	//
	// API extension: custom_block_volumes
	ContentType string `json:"content_type" yaml:"content_type"`
}

// StorageVolumePut represents the modifiable fields of a LXD storage volume
//
// swagger:model
//
// API extension: storage
type StorageVolumePut struct {
	// Storage volume configuration map (refer to doc/storage.md)
	// Example: {"zfs.remove_snapshots": "true", "size": "50GiB"}
	Config map[string]string `json:"config" yaml:"config"`

	// Description of the storage volume
	// Example: My custom volume
	//
	// API extension: entity_description
	Description string `json:"description" yaml:"description"`

	// Name of a snapshot to restore
	// Example: snap0
	//
	// API extension: storage_api_volume_snapshots
	Restore string `json:"restore,omitempty" yaml:"restore,omitempty"`
}

// StorageVolumeSource represents the creation source for a new storage volume
//
// swagger:model
//
// API extension: storage_api_local_volume_handling
type StorageVolumeSource struct {
	// Source volume name (for copy)
	// Example: foo
	Name string `json:"name" yaml:"name"`

	// Source type (copy or migration)
	// Example: copy
	Type string `json:"type" yaml:"type"`

	// Source storage pool (for copy)
	// Example: local
	Pool string `json:"pool" yaml:"pool"`

	// Certificate (for migration)
	// Example: X509 PEM certificate
	//
	// API extension: storage_api_remote_volume_handling
	Certificate string `json:"certificate" yaml:"certificate"`

	// Whether to use pull or push mode (for migration)
	// Example: pull
	//
	// API extension: storage_api_remote_volume_handling
	Mode string `json:"mode,omitempty" yaml:"mode,omitempty"`

	// Remote operation URL (for migration)
	// Example: https://1.2.3.4:8443/1.0/operations/1721ae08-b6a8-416a-9614-3f89302466e1
	//
	// API extension: storage_api_remote_volume_handling
	Operation string `json:"operation,omitempty" yaml:"operation,omitempty"`

	// Map of migration websockets (for migration)
	// Example: {"rsync": "RANDOM-STRING"}
	//
	// API extension: storage_api_remote_volume_handling
	Websockets map[string]string `json:"secrets,omitempty" yaml:"secrets,omitempty"`

	// Whether snapshots should be discarded (for migration)
	// Example: false
	//
	// API extension: storage_api_volume_snapshots
	VolumeOnly bool `json:"volume_only" yaml:"volume_only"`
}
<|endoftext|>


<commit_before>package riakpbc

import (
	"fmt"
	"github.com/bmizerany/assert"
	"log"
	"strings"
	"testing"
)

func ExampleRiakpbc() {
	riak, err := New("127.0.0.1:8087", 1e8, 1e8)
	if err != nil {
		log.Print(err.Error())
	}

	if err := riak.Dial(); err != nil {
		log.Print(err.Error())
	}

	data := []byte("{'data':'rules'}")

	_, err = riak.StoreObject("bucket", "data", data, "application/json", nil)
	if err != nil {
		log.Println(err.Error())
	}

	_, err = riak.SetClientId("coolio")
	if err != nil {
		log.Println(err.Error())
	}

	id, err := riak.GetClientId()
	if err != nil {
		log.Println(err.Error())
	}
	fmt.Println(string(id.GetClientId()))

	obj, err := riak.FetchObject("bucket", "data", nil)
	if err != nil {
		log.Println(err.Error())
	}
	fmt.Println(string(obj.GetContent()[0].GetValue()))
	// Output:
	// coolio
	// {'data':'rules'}

	riak.Close()
}

func setupConnection(t *testing.T) (conn *Conn) {
	conn, err := New("127.0.0.1:8087", 1e8, 1e8)
	conn.Dial()
	if err != nil {
		t.Error(err.Error())
	}
	assert.T(t, conn != nil)

	return conn
}

func setupData(t *testing.T, conn *Conn) {
	ok, err := conn.StoreObject("riakpbctestbucket", "testkey", []byte("{\"data\":\"is awesome!\"}"), "application/json", nil)
	if err != nil {
		t.Error(err.Error())
	}
	assert.T(t, len(ok.GetKey()) == 0)
}

func teardownData(t *testing.T, conn *Conn) {
	ok, err := conn.DeleteObject("riakpbctestbucket", "testkey", nil)
	if err != nil {
		t.Error(err.Error())
	}
	assert.T(t, string(ok) == "Success")
}

func TestListBuckets(t *testing.T) {
	riak := setupConnection(t)
	setupData(t, riak)

	buckets, err := riak.ListBuckets()
	if err != nil {
		t.Error(err.Error())
	}

	bucketString := fmt.Sprintf("%s", buckets)
	assert.T(t, strings.Contains(bucketString, "riakpbctestbucket"))

	teardownData(t, riak)
}

func TestFetchObject(t *testing.T) {
	riak := setupConnection(t)
	setupData(t, riak)

	object, err := riak.FetchObject("riakpbctestbucket", "testkey", nil)
	if err != nil {
		t.Error(err.Error())
	}
	stringObject := string(object.GetContent()[0].GetValue())

	data := "{\"data\":\"is awesome!\"}"
	if err != nil {
		t.Error(err.Error())
	}
	assert.T(t, stringObject == data)

	teardownData(t, riak)
}

func TestDeleteObject(t *testing.T) {
	riak := setupConnection(t)
	setupData(t, riak)

	object, err := riak.DeleteObject("riakpbctestbucket", "testkey", nil)
	if err != nil {
		t.Error(err.Error())
	}
	assert.T(t, string(object) == "Success")

	_, err = riak.FetchObject("riakpbctestbucket", "testkey", nil)
	assert.T(t, err.Error() == "object not found")

	teardownData(t, riak)
}
<commit_msg>named example correctly<commit_after>package riakpbc

import (
	"fmt"
	"github.com/bmizerany/assert"
	"log"
	"strings"
	"testing"
)

func ExampleConn() {
	riak, err := New("127.0.0.1:8087", 1e8, 1e8)
	if err != nil {
		log.Print(err.Error())
	}

	if err := riak.Dial(); err != nil {
		log.Print(err.Error())
	}

	data := []byte("{'data':'rules'}")

	_, err = riak.StoreObject("bucket", "data", data, "application/json", nil)
	if err != nil {
		log.Println(err.Error())
	}

	_, err = riak.SetClientId("coolio")
	if err != nil {
		log.Println(err.Error())
	}

	id, err := riak.GetClientId()
	if err != nil {
		log.Println(err.Error())
	}
	fmt.Println(string(id.GetClientId()))

	obj, err := riak.FetchObject("bucket", "data", nil)
	if err != nil {
		log.Println(err.Error())
	}
	fmt.Println(string(obj.GetContent()[0].GetValue()))
	// Output:
	// coolio
	// {'data':'rules'}

	riak.Close()
}

func setupConnection(t *testing.T) (conn *Conn) {
	conn, err := New("127.0.0.1:8087", 1e8, 1e8)
	conn.Dial()
	if err != nil {
		t.Error(err.Error())
	}
	assert.T(t, conn != nil)

	return conn
}

func setupData(t *testing.T, conn *Conn) {
	ok, err := conn.StoreObject("riakpbctestbucket", "testkey", []byte("{\"data\":\"is awesome!\"}"), "application/json", nil)
	if err != nil {
		t.Error(err.Error())
	}
	assert.T(t, len(ok.GetKey()) == 0)
}

func teardownData(t *testing.T, conn *Conn) {
	ok, err := conn.DeleteObject("riakpbctestbucket", "testkey", nil)
	if err != nil {
		t.Error(err.Error())
	}
	assert.T(t, string(ok) == "Success")
}

func TestListBuckets(t *testing.T) {
	riak := setupConnection(t)
	setupData(t, riak)

	buckets, err := riak.ListBuckets()
	if err != nil {
		t.Error(err.Error())
	}

	bucketString := fmt.Sprintf("%s", buckets)
	assert.T(t, strings.Contains(bucketString, "riakpbctestbucket"))

	teardownData(t, riak)
}

func TestFetchObject(t *testing.T) {
	riak := setupConnection(t)
	setupData(t, riak)

	object, err := riak.FetchObject("riakpbctestbucket", "testkey", nil)
	if err != nil {
		t.Error(err.Error())
	}
	stringObject := string(object.GetContent()[0].GetValue())

	data := "{\"data\":\"is awesome!\"}"
	if err != nil {
		t.Error(err.Error())
	}
	assert.T(t, stringObject == data)

	teardownData(t, riak)
}

func TestDeleteObject(t *testing.T) {
	riak := setupConnection(t)
	setupData(t, riak)

	object, err := riak.DeleteObject("riakpbctestbucket", "testkey", nil)
	if err != nil {
		t.Error(err.Error())
	}
	assert.T(t, string(object) == "Success")

	_, err = riak.FetchObject("riakpbctestbucket", "testkey", nil)
	assert.T(t, err.Error() == "object not found")

	teardownData(t, riak)
}
<|endoftext|>


<commit_before>package main

import (
	"log"
	"net/http"

	"github.com/gorilla/mux"
)

type Route struct {
	Name        string
	Method      string
	Pattern     string
	HandlerFunc http.HandlerFunc
}

type Routes []Route

func NewRouter() *mux.Router {
	r := mux.NewRouter().StrictSlash(true)

	r.Path("/login").
		Methods("GET").
		Name("Login").
		Handler(http.StripPrefix("/login", http.FileServer(http.Dir("./app/"))))
	r.Path("/login").
		Methods("POST").
		Name("LoginPOST").
		HandlerFunc(LoginUser)

	// API subrouter
	// Serves all JSON REST handlers prefixed with /api
	s := r.PathPrefix("/api").Subrouter()
	for _, route := range apiRoutes {
		s.Methods(route.Method).
			Path(route.Pattern).
			Name(route.Name).
			Handler(CheckSession(route.HandlerFunc))
	}

	// Serves the frontend application from the app directory
	// Uses basic file server to serve index.html and Javascript application
	// Routes match the ones defined in React application
	r.Path("/settings").
		Methods("GET").
		Name("Settings").
		Handler(CheckSession(http.StripPrefix("/settings", http.FileServer(http.Dir("./app/")))))
	r.Path("/mods").
		Methods("GET").
		Name("Mods").
		Handler(CheckSession(http.StripPrefix("/mods", http.FileServer(http.Dir("./app/")))))
	r.Path("/saves").
		Methods("GET").
		Name("Saves").
		Handler(CheckSession(http.StripPrefix("/saves", http.FileServer(http.Dir("./app/")))))
	r.Path("/logs").
		Methods("GET").
		Name("Logs").
		Handler(CheckSession(http.StripPrefix("/logs", http.FileServer(http.Dir("./app/")))))
	r.Path("/config").
		Methods("GET").
		Name("Config").
		Handler(CheckSession(http.StripPrefix("/config", http.FileServer(http.Dir("./app/")))))
	r.Path("/server").
		Methods("GET").
		Name("Server").
		Handler(CheckSession(http.StripPrefix("/server", http.FileServer(http.Dir("./app/")))))
	r.PathPrefix("/").
		Methods("GET").
		Name("Index").
		Handler(http.FileServer(http.Dir("./app/")))

	return r
}

// Middleware returns a http.HandlerFunc which authenticates the users request
// Redirects user to login page if no session is found
func CheckSession(h http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		if err := Auth.aaa.Authorize(w, r, true); err != nil {
			log.Printf("Unauthenticated request %s %s %s", r.Method, r.Host, r.RequestURI)
			http.Redirect(w, r, "/login", http.StatusSeeOther)
			return
		}
		h.ServeHTTP(w, r)
	})
}

// Defines all API REST endpoints
// All routes are prefixed with /api
var apiRoutes = Routes{
	Route{
		"ListInstalledMods",
		"GET",
		"/mods/list/installed",
		ListInstalledMods,
	}, {
		"ListMods",
		"GET",
		"/mods/list",
		ListMods,
	}, {
		"ToggleMod",
		"GET",
		"/mods/toggle/{mod}",
		ToggleMod,
	}, {
		"UploadMod",
		"POST",
		"/mods/upload",
		UploadMod,
	}, {
		"RemoveMod",
		"GET",
		"/mods/rm/{mod}",
		RemoveMod,
	}, {
		"DownloadMod",
		"GET",
		"/mods/dl/{mod}",
		DownloadMod,
	}, {
		"ListSaves",
		"GET",
		"/saves/list",
		ListSaves,
	}, {
		"DlSave",
		"GET",
		"/saves/dl/{save}",
		DLSave,
	}, {
		"UploadSave",
		"POST",
		"/saves/upload",
		UploadSave,
	}, {
		"RemoveSave",
		"GET",
		"/saves/rm/{save}",
		RemoveSave,
	}, {
		"CreateSave",
		"GET",
		"/saves/create/{save}",
		CreateSaveHandler,
	}, {
		"LogTail",
		"GET",
		"/log/tail",
		LogTail,
	}, {
		"LoadConfig",
		"GET",
		"/config",
		LoadConfig,
	}, {
		"StartServer",
		"GET",
		"/server/start",
		StartServer,
	}, {
		"StartServer",
		"POST",
		"/server/start",
		StartServer,
	}, {
		"StopServer",
		"GET",
		"/server/stop",
		StopServer,
	}, {
		"RunningServer",
		"GET",
		"/server/status",
		CheckServer,
	}, {
		"LogoutUser",
		"GET",
		"/logout",
		LogoutUser,
	}, {
		"StatusUser",
		"GET",
		"/user/status",
		GetCurrentLogin,
	}, {
		"ListUsers",
		"GET",
		"/user/list",
		ListUsers,
	}, {
		"AddUser",
		"POST",
		"/user/add",
		AddUser,
	}, {
		"RemoveUser",
		"POST",
		"/user/remove",
		RemoveUser,
	}, {
		"ListModPacks",
		"GET",
		"/mods/packs/list",
		ListModPacks,
	}, {
		"DownloadModPack",
		"GET",
		"/mods/packs/dl/{modpack}",
		DownloadModPack,
	}, {
		"DeleteModPack",
		"GET",
		"/mods/packs/rm/{modpack}",
		DeleteModPack,
	},
}
<commit_msg>added route for modpack creation<commit_after>package main

import (
	"log"
	"net/http"

	"github.com/gorilla/mux"
)

type Route struct {
	Name        string
	Method      string
	Pattern     string
	HandlerFunc http.HandlerFunc
}

type Routes []Route

func NewRouter() *mux.Router {
	r := mux.NewRouter().StrictSlash(true)

	r.Path("/login").
		Methods("GET").
		Name("Login").
		Handler(http.StripPrefix("/login", http.FileServer(http.Dir("./app/"))))
	r.Path("/login").
		Methods("POST").
		Name("LoginPOST").
		HandlerFunc(LoginUser)

	// API subrouter
	// Serves all JSON REST handlers prefixed with /api
	s := r.PathPrefix("/api").Subrouter()
	for _, route := range apiRoutes {
		s.Methods(route.Method).
			Path(route.Pattern).
			Name(route.Name).
			Handler(CheckSession(route.HandlerFunc))
	}

	// Serves the frontend application from the app directory
	// Uses basic file server to serve index.html and Javascript application
	// Routes match the ones defined in React application
	r.Path("/settings").
		Methods("GET").
		Name("Settings").
		Handler(CheckSession(http.StripPrefix("/settings", http.FileServer(http.Dir("./app/")))))
	r.Path("/mods").
		Methods("GET").
		Name("Mods").
		Handler(CheckSession(http.StripPrefix("/mods", http.FileServer(http.Dir("./app/")))))
	r.Path("/saves").
		Methods("GET").
		Name("Saves").
		Handler(CheckSession(http.StripPrefix("/saves", http.FileServer(http.Dir("./app/")))))
	r.Path("/logs").
		Methods("GET").
		Name("Logs").
		Handler(CheckSession(http.StripPrefix("/logs", http.FileServer(http.Dir("./app/")))))
	r.Path("/config").
		Methods("GET").
		Name("Config").
		Handler(CheckSession(http.StripPrefix("/config", http.FileServer(http.Dir("./app/")))))
	r.Path("/server").
		Methods("GET").
		Name("Server").
		Handler(CheckSession(http.StripPrefix("/server", http.FileServer(http.Dir("./app/")))))
	r.PathPrefix("/").
		Methods("GET").
		Name("Index").
		Handler(http.FileServer(http.Dir("./app/")))

	return r
}

// Middleware returns a http.HandlerFunc which authenticates the users request
// Redirects user to login page if no session is found
func CheckSession(h http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		if err := Auth.aaa.Authorize(w, r, true); err != nil {
			log.Printf("Unauthenticated request %s %s %s", r.Method, r.Host, r.RequestURI)
			http.Redirect(w, r, "/login", http.StatusSeeOther)
			return
		}
		h.ServeHTTP(w, r)
	})
}

// Defines all API REST endpoints
// All routes are prefixed with /api
var apiRoutes = Routes{
	Route{
		"ListInstalledMods",
		"GET",
		"/mods/list/installed",
		ListInstalledMods,
	}, {
		"ListMods",
		"GET",
		"/mods/list",
		ListMods,
	}, {
		"ToggleMod",
		"GET",
		"/mods/toggle/{mod}",
		ToggleMod,
	}, {
		"UploadMod",
		"POST",
		"/mods/upload",
		UploadMod,
	}, {
		"RemoveMod",
		"GET",
		"/mods/rm/{mod}",
		RemoveMod,
	}, {
		"DownloadMod",
		"GET",
		"/mods/dl/{mod}",
		DownloadMod,
	}, {
		"ListSaves",
		"GET",
		"/saves/list",
		ListSaves,
	}, {
		"DlSave",
		"GET",
		"/saves/dl/{save}",
		DLSave,
	}, {
		"UploadSave",
		"POST",
		"/saves/upload",
		UploadSave,
	}, {
		"RemoveSave",
		"GET",
		"/saves/rm/{save}",
		RemoveSave,
	}, {
		"CreateSave",
		"GET",
		"/saves/create/{save}",
		CreateSaveHandler,
	}, {
		"LogTail",
		"GET",
		"/log/tail",
		LogTail,
	}, {
		"LoadConfig",
		"GET",
		"/config",
		LoadConfig,
	}, {
		"StartServer",
		"GET",
		"/server/start",
		StartServer,
	}, {
		"StartServer",
		"POST",
		"/server/start",
		StartServer,
	}, {
		"StopServer",
		"GET",
		"/server/stop",
		StopServer,
	}, {
		"RunningServer",
		"GET",
		"/server/status",
		CheckServer,
	}, {
		"LogoutUser",
		"GET",
		"/logout",
		LogoutUser,
	}, {
		"StatusUser",
		"GET",
		"/user/status",
		GetCurrentLogin,
	}, {
		"ListUsers",
		"GET",
		"/user/list",
		ListUsers,
	}, {
		"AddUser",
		"POST",
		"/user/add",
		AddUser,
	}, {
		"RemoveUser",
		"POST",
		"/user/remove",
		RemoveUser,
	}, {
		"ListModPacks",
		"GET",
		"/mods/packs/list",
		ListModPacks,
	}, {
		"DownloadModPack",
		"GET",
		"/mods/packs/dl/{modpack}",
		DownloadModPack,
	}, {
		"DeleteModPack",
		"GET",
		"/mods/packs/rm/{modpack}",
		DeleteModPack,
	}, {
		"CreateModPack",
		"POST",
		"/mods/packs/add",
		CreateModPackHandler,
	},
}
<|endoftext|>


<commit_before><commit_msg>Renamed routes folder<commit_after><|endoftext|>


<commit_before>/*
Stochastic Gradient Descent (SGD)
=================================

Input
    theta_0 : initial array of parameters
    eta : initial step size
    loss_func : type of loss function to use "linear", "logistic", etc.

Output
    theta_hat : array of parameter estimates
    eta : current step size

Ref "Maching Learning from a Probabilistic Perspective" by Murphy pg. 264

Pseudo-code
-----------
Initialize theta, eta
repeat
    Randomly permute data
    for i = 1:N do
        g = grad(f(theta, (y_i, x_i)))
        theta_i+1 = theta_i - eta * g
        Update eta
until converged

SGD w/ Step Size
Complexity O(n)
Changes
    x  - Each theta update needs to be taken wrt all parameters
    x  - Need to figure out how to specify intercept for lin and log reg
            - Specify that data must be centered
    eta needs to be a list to handle per-parameter step sizes (e.g. adagrad)
    Step size needs to be a parameter in the function with a dict data structure

*/

package sgdlib

import (
	// "fmt"
    "math"
    "math/rand"
)

// TODO: Add map{} for step_size functions

// Learning Rate Schedule
//=======================

type eta_func func(k int) (eta float64)

var eta_map = map[string]eta_func {
    "inverse":eta_inverse,
}

func eta_inverse(k int) (eta float64) {
    eta = 1 / float64(k)
    return eta
}

// Channel Types
//======================
type model struct {
    Y []float64
    X []float64
    Theta0 []float64
    Loss_func string
    Eta int
}

type theta_hat []float64

// Loss Functions
//====================================

type loss_func func(y float64, x []float64, theta []float64) (grad []float64)

var loss_map = map[string]loss_func {
    "linear":grad_linear_loss,
    "logistic":grad_logistic_loss,
}

func grad_linear_loss(y float64, x []float64, theta []float64) (grad []float64) {
    // g = x_i * (y_est(theta, x_i) - y_i)
    var y_est float64
    grad = make([]float64, len(theta))

    // y_est = theta * x_i
    for i := 0; i < len(theta); i++ {
	   y_est = y_est + x[i] * theta[i]
    }

    // grad = (y - y_est) * x_i
    for i := 0; i < len(theta); i++ {
        grad[i] = (y - y_est) * x[i]
    }

	return grad
}

func grad_logistic_loss(y float64, x []float64, theta []float64) (grad []float64) {
    // grad = ( y - 1 / math.Exp(-(x * theta)) ) * x
    var y_est float64
    grad = make([]float64, len(theta))

    // y_est = theta * x_i
    for i := 0; i < len(theta); i++ {
        y_est = y_est + x[i] * theta[i]
    }

    // grad = (y - y_est) * x_i
    for i := 0; i < len(theta); i++ {
        grad[i] = (y - logit(y_est)) * x[i]
    }

    return grad
}

// Data Generators
//===============================
// TODO: Lin and Log reg could be same func by passing in a "linear" or "logit" func

// Lin reg RNG
func Lin_reg_gen(n int, betas []float64, beta0 float64) (x [][]float64, y []float64) {
    // TODO: The size of x is known beforehand, so allocate a fixed 2d array
    x = make([][]float64, n)
    y = make([]float64, n)

    for i := 0; i < n; i++ {
        y[i] = beta0
        x[i] = make([]float64, len(betas))
        for j := 0; j < len(betas); j++ {
            x[i][j] = rand.Float64()
            y[i] = y[i] + betas[j] * x[i][j] + rand.NormFloat64()
        }
    }
    return x, y
}

func logit(x float64) float64 {
    return 1 / (1 + math.Exp(-x))
}

// Log reg RNG
func Log_reg_gen(n int, betas []float64, beta0 float64) (x [][]float64, y []float64) {
    x = make([][]float64, n)
    y = make([]float64, n)

    for i := 0; i < n; i++ {
        y[i] = beta0
        x[i] = make([]float64, len(betas))
        for j := 0; j < len(betas); j++ {
            x[i][j] = rand.Float64()
            y[i] = y[i] + betas[j] * x[i][j] + rand.NormFloat64()
        }
        y[i] = logit(y[i])
    }

    return x, y
}

// SGD Kernel
//=============================

func Sgd(y float64, x []float64, theta0 []float64, loss_func string, eta int) (theta_hat []float64) {
    theta_hat = make([]float64, len(theta0))
    step_size := (1/(float64(eta) + 1))

    grad := loss_map[loss_func](y, x, theta0)

    for i := 0; i < len(theta0); i++ {
        theta_hat[i] = theta0[i] + step_size * grad[i]
    }

    return theta_hat
}

func Sgd2(input chan model, output chan theta_hat) {
    theta_hat = make([]float64, len(theta0))

    for {
        select {
        case model := <-input:
            step_size := (1/(float64(model.Eta) + 1))
            grad := loss_map[model.Loss_func](model.Y, model.X, model.Theta0)

            for i := 0; i < len(model.Theta0); i++ {
                theta_hat[i] = model.Theta0[i] + step_size * grad[i]
            }
            output <-theta_hat
        }
}

<commit_msg>Modifying SGD and RNG to work online<commit_after>/*
Stochastic Gradient Descent (SGD)
=================================

Input
    theta_0 : initial array of parameters
    eta : initial step size
    loss_func : type of loss function to use "linear", "logistic", etc.

Output
    theta_hat : array of parameter estimates
    eta : current step size

Ref "Maching Learning from a Probabilistic Perspective" by Murphy pg. 264

Pseudo-code
-----------
Initialize theta, eta
repeat
    Randomly permute data
    for i = 1:N do
        g = grad(f(theta, (y_i, x_i)))
        theta_i+1 = theta_i - eta * g
        Update eta
until converged

SGD w/ Step Size
Complexity O(n)
Changes
    x  - Each theta update needs to be taken wrt all parameters
    x  - Need to figure out how to specify intercept for lin and log reg
            - Specify that data must be centered
    eta needs to be a list to handle per-parameter step sizes (e.g. adagrad)
    Step size needs to be a parameter in the function with a dict data structure

*/

package sgdlib

import (
	// "fmt"
    "math"
    "math/rand"
    "time"
)

// TODO: Add map{} for step_size functions

// Learning Rate Schedule
//=======================

type eta_func func(k int) (eta float64)

var eta_map = map[string]eta_func {
    "inverse":eta_inverse,
}

func eta_inverse(k int) (eta float64) {
    eta = 1 / float64(k)
    return eta
}

// Channel Types
//======================
type model struct {
    Y float64
    X []float64
    Theta0 []float64
    Loss_func string
    Eta int
}

type theta_hat []float64

// Link Functions
//===================================
type link_func func(x float64) (y float64)

var link_map = map[string]link_func {
    "identity":identity,
    "logit":logit,
}

func identity(x float64) (y float64) {
    y = x
    return y
}

func logit(x float64) (y float64) {
    y = 1 / (1 + math.Exp(-x))
    return y
}

// Loss Functions
//====================================

type loss_func func(y float64, x []float64, theta []float64) (grad []float64)

var loss_map = map[string]loss_func {
    "linear":grad_linear_loss,
    "logistic":grad_logistic_loss,
}

func grad_linear_loss(y float64, x []float64, theta []float64) (grad []float64) {
    // g = x_i * (y_est(theta, x_i) - y_i)
    var y_est float64
    grad = make([]float64, len(theta))

    // y_est = theta * x_i
    for i := 0; i < len(theta); i++ {
	   y_est = y_est + x[i] * theta[i]
    }

    // grad = (y - y_est) * x_i
    for i := 0; i < len(theta); i++ {
        grad[i] = (y - y_est) * x[i]
    }

	return grad
}

func grad_logistic_loss(y float64, x []float64, theta []float64) (grad []float64) {
    // grad = ( y - 1 / math.Exp(-(x * theta)) ) * x
    var y_est float64
    grad = make([]float64, len(theta))

    // y_est = theta * x_i
    for i := 0; i < len(theta); i++ {
        y_est = y_est + x[i] * theta[i]
    }

    // grad = (y - y_est) * x_i
    for i := 0; i < len(theta); i++ {
        grad[i] = (y - logit(y_est)) * x[i]
    }

    return grad
}

// Data Generators
//===============================
// TODO: Lin and Log reg could be same func by passing in a "linear" or "logit" func

// Lin reg RNG
func Lin_reg_gen(n int, betas []float64, beta0 float64) (x [][]float64, y []float64) {
    // TODO: The size of x is known beforehand, so allocate a fixed 2d array
    x = make([][]float64, n)
    y = make([]float64, n)

    for i := 0; i < n; i++ {
        y[i] = beta0
        x[i] = make([]float64, len(betas))
        for j := 0; j < len(betas); j++ {
            x[i][j] = rand.Float64()
            y[i] = y[i] + betas[j] * x[i][j] + rand.NormFloat64()
        }
    }
    return x, y
}

// Log reg RNG
func Log_reg_gen(n int, betas []float64, beta0 float64) (x [][]float64, y []float64) {
    x = make([][]float64, n)
    y = make([]float64, n)

    for i := 0; i < n; i++ {
        y[i] = beta0
        x[i] = make([]float64, len(betas))
        for j := 0; j < len(betas); j++ {
            x[i][j] = rand.Float64()
            y[i] = y[i] + betas[j] * x[i][j] + rand.NormFloat64()
        }
        y[i] = logit(y[i])
    }

    return x, y
}

// TODO: Add mean and sd parameters

func Gen_lin_model_rng(betas []float64, beta0 float64, link_func string, out chan []float64) {
    time := time.NewTicker(time.Duration(1) * time.Second)
    for {
        select {
        case <- time.C:
            n := len(betas)
            x := make([]float64, n)
            model_rnd := make([]float64, n + 1)
            y := beta0
            for i := 0; i < n; i ++ {
                x[i] = rand.Float64()
                model_rnd[i + 1] = x[i]
                y = y + betas[i] * x[i]
            }
            y = link_map[link_func](y + rand.NormFloat64())
            model_rnd[0] = y
            out <- model_rnd
        }
    }
}

// SGD Kernel
//=============================

func Sgd(y float64, x []float64, theta0 []float64, loss_func string, eta int) (theta_hat []float64) {
    theta_hat = make([]float64, len(theta0))
    step_size := (1/(float64(eta) + 1))

    grad := loss_map[loss_func](y, x, theta0)

    for i := 0; i < len(theta0); i++ {
        theta_hat[i] = theta0[i] + step_size * grad[i]
    }

    return theta_hat
}

func Sgd_online(input chan model, output chan theta_hat) {
    for {
        select {
        case model := <-input:
            theta_est := make([]float64, len(model.Theta0))

            step_size := (1/(float64(model.Eta) + 1))
            grad := loss_map[model.Loss_func](model.Y, model.X, model.Theta0)

            for i := 0; i < len(model.Theta0); i++ {
                theta_est[i] = model.Theta0[i] + step_size * grad[i]
            }
            output <-theta_est
        }
    }
}

<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"fmt"
	"html"
	"io"
	"io/ioutil"
	"net/http"
	"os"
	"path"
	"strconv"
	"strings"
	"text/template"
	"time"
)

type FooterData struct {
	Version       string
	GeneratedTime float32
}

var funcMap = template.FuncMap{
	"add": func(a, b int) int {
		return a + b
	},
	"subtract": func(a, b int) int {
		return a - b
	},
	"len": func(arr []interface{}) int {
		return len(arr)
	},
	"getSlice": func(arr []interface{}, start, end int) []interface{} {
		slice := arr[start:end]
		defer func() {
			if r := recover(); r != nil {
				slice = make([]interface{}, 1)
			}
		}()
		return slice
	},
	"gt": func(a int, b int) bool {
		return a > b
	},
	"gte": func(a int, b int) bool {
		return a >= b
	},
	"lt": func(a int, b int) bool {
		return a < b
	},
	"lte": func(a int, b int) bool {
		return a <= b
	},
	"makeLoop": func(n int) []struct{} {
		return make([]struct{}, n)
	},
	"stringAppend": func(a, b string) string {
		return a + b
	},
	"stringEq": func(a, b string) bool {
		return a == b
	},
	"stringNeq": func(a, b string) bool {
		return a != b
	},
	"truncateMessage": func(msg string, limit int, max_lines int) string {
		var truncated bool
		split := strings.SplitN(msg, "
", -1)

		if len(split) > max_lines {
			split = split[:max_lines]
			msg = strings.Join(split, "
")
			truncated = true
		}

		if len(msg) < limit {
			if truncated {
				msg = msg + "..."
			}
			return msg
		} else {
			msg = msg[:limit]
			truncated = true
		}

		if truncated {
			msg = msg + "..."
		}
		return msg
	},
	"truncateString": func(msg string, limit int, ellipsis bool) string {
		if len(msg) > limit {
			if ellipsis {
				return msg[:limit] + "..."
			} else {
				return msg[:limit]
			}
		} else {
			return msg
		}
	},
	"unescapeString": func(a string) string {
		return html.UnescapeString(a)
	},
	"intEq": func(a, b int) bool {
		return a == b
	},
	"intToString": func(a int) string {
		return strconv.Itoa(a)
	},
	"isStyleDefault_img": func(style string) bool {
		return style == config.DefaultStyle_img
	},
	"isStyleNotDefault_img": func(style string) bool {
		return style != config.DefaultStyle_img
	},
	"getElement": func(in []interface{}, element int) interface{} {
		return in[element]
	},
	"getInterface": func(in []interface{}, index int) interface{} {
		var nope interface{}
		if len(in) == 0 {
			return nope
		} else if len(in) < index+1 {
			return nope
		}
		return in[index]
	},
	"formatTimestamp": func(timestamp time.Time) string {
		return humanReadableTime(timestamp)
	},
	"getThreadID": func(post_i interface{}) (thread int) {
		post := post_i.(PostTable)
		if post.ParentID == 0 {
			thread = post.ID
		} else {
			thread = post.ParentID
		}
		return
	},
	"getThumbnailFilename": func(name string) string {
		if name == "" || name == "deleted" {
			return ""
		}
		if name[len(name)-3:] == "gif" || name[len(name)-3:] == "gif" {
			name = name[:len(name)-3] + "jpg"
		}
		ext_begin := strings.LastIndex(name, ".")
		new_name := name[:ext_begin] + "t." + getFileExtension(name)
		return new_name
	},
	"formatFilesize": func(size_int int) string {
		size := float32(size_int)
		if size < 1000 {
			return fmt.Sprintf("%fB", size)
		} else if size <= 100000 {
			//size = size * 0.2
			return fmt.Sprintf("%0.1f KB", size/1024)
		} else if size <= 100000000 {
			//size = size * 0.2
			return fmt.Sprintf("%0.2f MB", size/1024/1024)
		}
		return fmt.Sprintf("%0.2f GB", size/1024/1024/1024)
	},
	"imageToThumbnailPath": func(img string) string {
		filetype := img[strings.LastIndex(img, ".")+1:]
		if filetype == "gif" || filetype == "GIF" {
			filetype = "jpg"
		}
		index := strings.LastIndex(img, ".")
		if index < 0 || index > len(img) {
			return ""
		}
		return img[0:index] + "t." + filetype
	},
}

var (
	footer_data = FooterData{version, float32(0)}

	banpage_tmpl_str string
	banpage_tmpl     *template.Template

	global_footer_tmpl_str string
	global_footer_tmpl     *template.Template

	global_header_tmpl_str string
	global_header_tmpl     *template.Template

	img_boardpage_tmpl_str string
	img_boardpage_tmpl     *template.Template

	img_threadpage_tmpl_str string
	img_threadpage_tmpl     *template.Template

	manage_header_tmpl_str string
	manage_header_tmpl     *template.Template

	front_page_tmpl_str string
	front_page_tmpl     *template.Template

	template_buffer bytes.Buffer
	starting_time   int
)

func initTemplates() {
	resetBoardSectionArrays()
	banpage_tmpl_bytes, tmpl_err := ioutil.ReadFile(config.TemplateDir + "/banpage.html")
	if tmpl_err != nil {
		fmt.Println("Failed loading template \"" + config.TemplateDir + "/banpage.html\": " + tmpl_err.Error())
		os.Exit(2)
	}
	banpage_tmpl_str = "{{$config := getInterface .Data 0}}" +
		"{{$ban := getInterface .Data 1}}" +
		string(banpage_tmpl_bytes)
	banpage_tmpl, tmpl_err = template.New("banpage_tmpl").Funcs(funcMap).Parse(string(banpage_tmpl_str))
	if tmpl_err != nil {
		fmt.Println("Failed loading template \"" + config.TemplateDir + "/banpage.html\": " + tmpl_err.Error())
		os.Exit(2)
	}

	global_footer_tmpl_bytes, tmpl_err := ioutil.ReadFile(config.TemplateDir + "/global_footer.html")
	if tmpl_err != nil {
		fmt.Println("Failed loading template \"" + config.TemplateDir + "/global_footer.html\": " + tmpl_err.Error())
		os.Exit(2)
	}
	global_footer_tmpl_str = string(global_footer_tmpl_bytes)
	global_footer_tmpl, tmpl_err = template.New("global_footer_tmpl").Funcs(funcMap).Parse(string(global_footer_tmpl_str))
	if tmpl_err != nil {
		fmt.Println("Failed loading template \"" + config.TemplateDir + "/global_footer.html\": " + tmpl_err.Error())
		os.Exit(2)
	}

	global_header_tmpl_bytes, tmpl_err := ioutil.ReadFile(config.TemplateDir + "/global_header.html")
	if tmpl_err != nil {
		fmt.Println("Failed loading template \"" + config.TemplateDir + "/global_header.html\": " + tmpl_err.Error())
		os.Exit(2)
	}
	global_header_tmpl_str = string(global_header_tmpl_bytes)
	global_header_tmpl, tmpl_err = template.New("global_header_tmpl").Funcs(funcMap).Parse(string(global_header_tmpl_str))
	if tmpl_err != nil {
		fmt.Println("Failed loading template \"" + config.TemplateDir + "/global_header.html\": " + tmpl_err.Error())
		os.Exit(2)
	}

	img_boardpage_tmpl_bytes, _ := ioutil.ReadFile(path.Join(config.TemplateDir, "img_boardpage.html"))
	if tmpl_err != nil {
		fmt.Println("Failed loading template \"" + config.TemplateDir + "/img_boardpage.html\": " + tmpl_err.Error())
		os.Exit(2)
	}
	img_boardpage_tmpl_str = "{{$config := getInterface .Data 0}}" +
		"{{$board_arr := (getInterface .Data 1).Data}}" +
		"{{$section_arr := (getInterface .Data 2).Data}}" +
		"{{$thread_arr := (getInterface .Data 3).Data}}" +
		"{{$board_info := (getInterface .Data 4).Data}}" +
		"{{$board := getInterface $board_info 0}}" +
		string(img_boardpage_tmpl_bytes)
	img_boardpage_tmpl, tmpl_err = template.New("img_boardpage_tmpl").Funcs(funcMap).Parse(img_boardpage_tmpl_str)
	if tmpl_err != nil {
		fmt.Println("Failed loading template \"" + config.TemplateDir + "/img_boardpage.html: \"" + tmpl_err.Error())
		os.Exit(2)
	}

	img_threadpage_tmpl_bytes, _ := ioutil.ReadFile(path.Join(config.TemplateDir, "img_threadpage.html"))
	if tmpl_err != nil {
		fmt.Println("Failed loading template \"" + config.TemplateDir + "/img_threadpage.html\": " + tmpl_err.Error())
		os.Exit(2)
	}
	img_threadpage_tmpl_str = "{{$config := getInterface .Data 0}}" +
		"{{$board_arr := (getInterface .Data 1).Data}}" +
		"{{$section_arr := (getInterface .Data 2).Data}}" +
		"{{$post_arr := (getInterface .Data 3).Data}}" +
		"{{$op := getElement $post_arr 0}}" +
		"{{$board := getElement $board_arr (subtract $op.BoardID 1)}}" +
		string(img_threadpage_tmpl_bytes)
	img_threadpage_tmpl, tmpl_err = template.New("img_threadpage_tmpl").Funcs(funcMap).Parse(img_threadpage_tmpl_str)
	if tmpl_err != nil {
		fmt.Println("Failed loading template \"" + config.TemplateDir + "/img_threadpage.html: \"" + tmpl_err.Error())
		os.Exit(2)
	}

	manage_header_tmpl_bytes, err := ioutil.ReadFile(config.TemplateDir + "/manage_header.html")
	if err != nil {
		fmt.Println(err.Error())
	}
	manage_header_tmpl_str = string(manage_header_tmpl_bytes)
	manage_header_tmpl, tmpl_err = template.New("manage_header_tmpl").Funcs(funcMap).Parse(manage_header_tmpl_str)
	if tmpl_err != nil {
		fmt.Println("Failed loading template \"" + config.TemplateDir + "/manage_header.html\": " + tmpl_err.Error())
		os.Exit(2)
	}

	front_page_tmpl_bytes, err := ioutil.ReadFile(config.TemplateDir + "/front.html")
	if err != nil {
		fmt.Println(err.Error())
		os.Exit(2)
	}
	front_page_tmpl_str = "{{$config := getInterface .Data 0}}\n" +
		"{{$page_arr := getInterface .Data 1}}\n" +
		"{{$board_arr := getInterface .Data 2}}\n" +
		"{{$section_arr := getInterface .Data 3}}\n" +
		"{{$recent_posts_arr := getInterface .Data 4}}\n" +
		string(front_page_tmpl_bytes)
	front_page_tmpl, tmpl_err = template.New("front_page_tmpl").Funcs(funcMap).Parse(front_page_tmpl_str)
	if tmpl_err != nil {
		fmt.Println("Failed loading template \"" + config.TemplateDir + "/front.html\": " + tmpl_err.Error())
		os.Exit(2)
	}
}

func getTemplateAsString(templ template.Template) (string, error) {
	var buf bytes.Buffer
	err := templ.Execute(&buf, config)
	if err == nil {
		return buf.String(), nil
	}
	return "", err
}

func getStyleLinks(w http.ResponseWriter, stylesheet string) {
	styles_map := make(map[int]string)
	for i := 0; i < len(config.Styles_img); i++ {
		styles_map[i] = config.Styles_img[i]
	}

	err := manage_header_tmpl.Execute(w, config)
	if err != nil {
		fmt.Println(err.Error())
		os.Exit(2)
	}
}

func renderTemplate(tmpl *template.Template, name string, output io.Writer, wrappers ...*Wrapper) error {
	var interfaces []interface{}
	interfaces = append(interfaces, config)

	for _, wrapper := range wrappers {
		interfaces = append(interfaces, wrapper)
	}
	wrapped := &Wrapper{IName: name, Data: interfaces}
	return img_boardpage_tmpl.Execute(output, wrapped)
}
<commit_msg>fix leftover template execution code (causing panics and/or template execution failure when not building board page)<commit_after>package main

import (
	"bytes"
	"fmt"
	"html"
	"html/template"
	"io"
	"io/ioutil"
	"net/http"
	"os"
	"path"
	"strconv"
	"strings"
	"time"
)

type FooterData struct {
	Version       string
	GeneratedTime float32
}

var funcMap = template.FuncMap{
	"add": func(a, b int) int {
		return a + b
	},
	"subtract": func(a, b int) int {
		return a - b
	},
	"len": func(arr []interface{}) int {
		return len(arr)
	},
	"getSlice": func(arr []interface{}, start, end int) []interface{} {
		slice := arr[start:end]
		defer func() {
			if r := recover(); r != nil {
				slice = make([]interface{}, 1)
			}
		}()
		return slice
	},
	"gt": func(a int, b int) bool {
		return a > b
	},
	"gte": func(a int, b int) bool {
		return a >= b
	},
	"lt": func(a int, b int) bool {
		return a < b
	},
	"lte": func(a int, b int) bool {
		return a <= b
	},
	"makeLoop": func(n int) []struct{} {
		return make([]struct{}, n)
	},
	"stringAppend": func(a, b string) string {
		return a + b
	},
	"stringEq": func(a, b string) bool {
		return a == b
	},
	"stringNeq": func(a, b string) bool {
		return a != b
	},
	"truncateMessage": func(msg string, limit int, max_lines int) string {
		var truncated bool
		split := strings.SplitN(msg, "
", -1)

		if len(split) > max_lines {
			split = split[:max_lines]
			msg = strings.Join(split, "
")
			truncated = true
		}

		if len(msg) < limit {
			if truncated {
				msg = msg + "..."
			}
			return msg
		} else {
			msg = msg[:limit]
			truncated = true
		}

		if truncated {
			msg = msg + "..."
		}
		return msg
	},
	"truncateString": func(msg string, limit int, ellipsis bool) string {
		if len(msg) > limit {
			if ellipsis {
				return msg[:limit] + "..."
			} else {
				return msg[:limit]
			}
		} else {
			return msg
		}
	},
	"unescapeString": func(a string) string {
		return html.UnescapeString(a)
	},
	"intEq": func(a, b int) bool {
		return a == b
	},
	"intToString": func(a int) string {
		return strconv.Itoa(a)
	},
	"isStyleDefault_img": func(style string) bool {
		return style == config.DefaultStyle_img
	},
	"isStyleNotDefault_img": func(style string) bool {
		return style != config.DefaultStyle_img
	},
	"getElement": func(in []interface{}, element int) interface{} {
		return in[element]
	},
	"getInterface": func(in []interface{}, index int) interface{} {
		var nope interface{}
		if len(in) == 0 {
			return nope
		} else if len(in) < index+1 {
			return nope
		}
		return in[index]
	},
	"formatTimestamp": func(timestamp time.Time) string {
		return humanReadableTime(timestamp)
	},
	"getThreadID": func(post_i interface{}) (thread int) {
		post := post_i.(PostTable)
		if post.ParentID == 0 {
			thread = post.ID
		} else {
			thread = post.ParentID
		}
		return
	},
	"getThumbnailFilename": func(name string) string {
		if name == "" || name == "deleted" {
			return ""
		}
		if name[len(name)-3:] == "gif" || name[len(name)-3:] == "gif" {
			name = name[:len(name)-3] + "jpg"
		}
		ext_begin := strings.LastIndex(name, ".")
		new_name := name[:ext_begin] + "t." + getFileExtension(name)
		return new_name
	},
	"formatFilesize": func(size_int int) string {
		size := float32(size_int)
		if size < 1000 {
			return fmt.Sprintf("%fB", size)
		} else if size <= 100000 {
			//size = size * 0.2
			return fmt.Sprintf("%0.1f KB", size/1024)
		} else if size <= 100000000 {
			//size = size * 0.2
			return fmt.Sprintf("%0.2f MB", size/1024/1024)
		}
		return fmt.Sprintf("%0.2f GB", size/1024/1024/1024)
	},
	"imageToThumbnailPath": func(img string) string {
		filetype := img[strings.LastIndex(img, ".")+1:]
		if filetype == "gif" || filetype == "GIF" {
			filetype = "jpg"
		}
		index := strings.LastIndex(img, ".")
		if index < 0 || index > len(img) {
			return ""
		}
		return img[0:index] + "t." + filetype
	},
}

var (
	footer_data = FooterData{version, float32(0)}

	banpage_tmpl_str string
	banpage_tmpl     *template.Template

	global_footer_tmpl_str string
	global_footer_tmpl     *template.Template

	global_header_tmpl_str string
	global_header_tmpl     *template.Template

	img_boardpage_tmpl_str string
	img_boardpage_tmpl     *template.Template

	img_threadpage_tmpl_str string
	img_threadpage_tmpl     *template.Template

	manage_header_tmpl_str string
	manage_header_tmpl     *template.Template

	front_page_tmpl_str string
	front_page_tmpl     *template.Template

	template_buffer bytes.Buffer
	starting_time   int
)

func initTemplates() {
	resetBoardSectionArrays()
	banpage_tmpl_bytes, tmpl_err := ioutil.ReadFile(config.TemplateDir + "/banpage.html")
	if tmpl_err != nil {
		fmt.Println("Failed loading template \"" + config.TemplateDir + "/banpage.html\": " + tmpl_err.Error())
		os.Exit(2)
	}
	banpage_tmpl_str = "{{$config := getInterface .Data 0}}" +
		"{{$ban := getInterface .Data 1}}" +
		string(banpage_tmpl_bytes)
	banpage_tmpl, tmpl_err = template.New("banpage_tmpl").Funcs(funcMap).Parse(string(banpage_tmpl_str))
	if tmpl_err != nil {
		fmt.Println("Failed loading template \"" + config.TemplateDir + "/banpage.html\": " + tmpl_err.Error())
		os.Exit(2)
	}

	global_footer_tmpl_bytes, tmpl_err := ioutil.ReadFile(config.TemplateDir + "/global_footer.html")
	if tmpl_err != nil {
		fmt.Println("Failed loading template \"" + config.TemplateDir + "/global_footer.html\": " + tmpl_err.Error())
		os.Exit(2)
	}
	global_footer_tmpl_str = string(global_footer_tmpl_bytes)
	global_footer_tmpl, tmpl_err = template.New("global_footer_tmpl").Funcs(funcMap).Parse(string(global_footer_tmpl_str))
	if tmpl_err != nil {
		fmt.Println("Failed loading template \"" + config.TemplateDir + "/global_footer.html\": " + tmpl_err.Error())
		os.Exit(2)
	}

	global_header_tmpl_bytes, tmpl_err := ioutil.ReadFile(config.TemplateDir + "/global_header.html")
	if tmpl_err != nil {
		fmt.Println("Failed loading template \"" + config.TemplateDir + "/global_header.html\": " + tmpl_err.Error())
		os.Exit(2)
	}
	global_header_tmpl_str = string(global_header_tmpl_bytes)
	global_header_tmpl, tmpl_err = template.New("global_header_tmpl").Funcs(funcMap).Parse(string(global_header_tmpl_str))
	if tmpl_err != nil {
		fmt.Println("Failed loading template \"" + config.TemplateDir + "/global_header.html\": " + tmpl_err.Error())
		os.Exit(2)
	}

	img_boardpage_tmpl_bytes, _ := ioutil.ReadFile(path.Join(config.TemplateDir, "img_boardpage.html"))
	if tmpl_err != nil {
		fmt.Println("Failed loading template \"" + config.TemplateDir + "/img_boardpage.html\": " + tmpl_err.Error())
		os.Exit(2)
	}
	img_boardpage_tmpl_str = "{{$config := getInterface .Data 0}}" +
		"{{$board_arr := (getInterface .Data 1).Data}}" +
		"{{$section_arr := (getInterface .Data 2).Data}}" +
		"{{$thread_arr := (getInterface .Data 3).Data}}" +
		"{{$board_info := (getInterface .Data 4).Data}}" +
		"{{$board := getInterface $board_info 0}}" +
		string(img_boardpage_tmpl_bytes)
	img_boardpage_tmpl, tmpl_err = template.New("img_boardpage_tmpl").Funcs(funcMap).Parse(img_boardpage_tmpl_str)
	if tmpl_err != nil {
		fmt.Println("Failed loading template \"" + config.TemplateDir + "/img_boardpage.html: \"" + tmpl_err.Error())
		os.Exit(2)
	}

	img_threadpage_tmpl_bytes, _ := ioutil.ReadFile(path.Join(config.TemplateDir, "img_threadpage.html"))
	if tmpl_err != nil {
		fmt.Println("Failed loading template \"" + config.TemplateDir + "/img_threadpage.html\": " + tmpl_err.Error())
		os.Exit(2)
	}
	img_threadpage_tmpl_str = "{{$config := getInterface .Data 0}}" +
		"{{$board_arr := (getInterface .Data 1).Data}}" +
		"{{$section_arr := (getInterface .Data 2).Data}}" +
		"{{$post_arr := (getInterface .Data 3).Data}}" +
		"{{$op := getElement $post_arr 0}}" +
		"{{$board := getElement $board_arr (subtract $op.BoardID 1)}}" +
		string(img_threadpage_tmpl_bytes)
	img_threadpage_tmpl, tmpl_err = template.New("img_threadpage_tmpl").Funcs(funcMap).Parse(img_threadpage_tmpl_str)
	if tmpl_err != nil {
		fmt.Println("Failed loading template \"" + config.TemplateDir + "/img_threadpage.html: \"" + tmpl_err.Error())
		os.Exit(2)
	}

	manage_header_tmpl_bytes, err := ioutil.ReadFile(config.TemplateDir + "/manage_header.html")
	if err != nil {
		fmt.Println(err.Error())
	}
	manage_header_tmpl_str = string(manage_header_tmpl_bytes)
	manage_header_tmpl, tmpl_err = template.New("manage_header_tmpl").Funcs(funcMap).Parse(manage_header_tmpl_str)
	if tmpl_err != nil {
		fmt.Println("Failed loading template \"" + config.TemplateDir + "/manage_header.html\": " + tmpl_err.Error())
		os.Exit(2)
	}

	front_page_tmpl_bytes, err := ioutil.ReadFile(config.TemplateDir + "/front.html")
	if err != nil {
		fmt.Println(err.Error())
		os.Exit(2)
	}
	front_page_tmpl_str = "{{$config := getInterface .Data 0}}\n" +
		"{{$page_arr := getInterface .Data 1}}\n" +
		"{{$board_arr := getInterface .Data 2}}\n" +
		"{{$section_arr := getInterface .Data 3}}\n" +
		"{{$recent_posts_arr := getInterface .Data 4}}\n" +
		string(front_page_tmpl_bytes)
	front_page_tmpl, tmpl_err = template.New("front_page_tmpl").Funcs(funcMap).Parse(front_page_tmpl_str)
	if tmpl_err != nil {
		fmt.Println("Failed loading template \"" + config.TemplateDir + "/front.html\": " + tmpl_err.Error())
		os.Exit(2)
	}
}

func getTemplateAsString(templ template.Template) (string, error) {
	var buf bytes.Buffer
	err := templ.Execute(&buf, config)
	if err == nil {
		return buf.String(), nil
	}
	return "", err
}

func getStyleLinks(w http.ResponseWriter, stylesheet string) {
	styles_map := make(map[int]string)
	for i := 0; i < len(config.Styles_img); i++ {
		styles_map[i] = config.Styles_img[i]
	}

	err := manage_header_tmpl.Execute(w, config)
	if err != nil {
		fmt.Println(err.Error())
		os.Exit(2)
	}
}

func renderTemplate(tmpl *template.Template, name string, output io.Writer, wrappers ...*Wrapper) error {
	var interfaces []interface{}
	interfaces = append(interfaces, config)

	for _, wrapper := range wrappers {
		interfaces = append(interfaces, wrapper)
	}
	wrapped := &Wrapper{IName: name, Data: interfaces}
	return tmpl.Execute(output, wrapped)
}
<|endoftext|>


<commit_before><commit_msg>Use geography in tests.<commit_after><|endoftext|>


<commit_before>package manager

import (
	"testing"
	"time"

	"github.com/micro/go-micro/v2/runtime"
	"github.com/micro/go-micro/v2/store/memory"
	"github.com/micro/micro/v2/internal/namespace"
)

func TestEvents(t *testing.T) {
	// an event is passed through this channel from the test runtime everytime a method is called,
	// this is done since events ae processed async
	eventChan := make(chan *runtime.Service)

	rt := &testRuntime{events: eventChan}
	m := New(rt, Store(memory.NewStore())).(*manager)

	// set the eventPollFrequency to 10ms so events are processed immediately
	eventPollFrequency = time.Millisecond * 10
	go m.watchEvents()

	// timeout async tests after 50ms
	timeout := time.NewTimer(time.Millisecond * 50)

	// the service that should be passed to the runtime
	testSrv := &runtime.Service{Name: "go.micro.service.foo", Version: "latest"}
	opts := &runtime.CreateOptions{Namespace: namespace.DefaultNamespace}

	t.Run("Create", func(t *testing.T) {
		defer rt.Reset()

		if err := m.publishEvent(runtime.Create, testSrv, opts); err != nil {
			t.Errorf("Unexpected error when publishing events: %v", err)
		}

		timeout.Reset(time.Millisecond * 50)

		select {
		case srv := <-eventChan:
			if srv.Name != testSrv.Name || srv.Version != testSrv.Version {
				t.Errorf("Incorrect service passed to the runtime")
			}
		case <-timeout.C:
			t.Fatalf("The runtime wasn't called")
		}

		if rt.createCount != 1 {
			t.Errorf("Expected runtime create to be called 1 time but was actually called %v times", rt.createCount)
		}
	})

	t.Run("Update", func(t *testing.T) {
		defer rt.Reset()

		if err := m.publishEvent(runtime.Update, testSrv, opts); err != nil {
			t.Errorf("Unexpected error when publishing events: %v", err)
		}

		timeout.Reset(time.Millisecond * 50)

		select {
		case srv := <-eventChan:
			if srv.Name != testSrv.Name || srv.Version != testSrv.Version {
				t.Errorf("Incorrect service passed to the runtime")
			}
		case <-timeout.C:
			t.Fatalf("The runtime wasn't called")
		}

		if rt.updateCount != 1 {
			t.Errorf("Expected runtime update to be called 1 time but was actually called %v times", rt.createCount)
		}
	})

	t.Run("Delete", func(t *testing.T) {
		defer rt.Reset()

		if err := m.publishEvent(runtime.Delete, testSrv, opts); err != nil {
			t.Errorf("Unexpected error when publishing events: %v", err)
		}

		timeout.Reset(time.Millisecond * 50)

		select {
		case srv := <-eventChan:
			if srv.Name != testSrv.Name || srv.Version != testSrv.Version {
				t.Errorf("Incorrect service passed to the runtime")
			}
		case <-timeout.C:
			t.Fatalf("The runtime wasn't called")
		}

		if rt.deleteCount != 1 {
			t.Errorf("Expected runtime delete to be called 1 time but was actually called %v times", rt.createCount)
		}
	})
}
<commit_msg>loosen up the test timeout<commit_after>package manager

import (
	"testing"
	"time"

	"github.com/micro/go-micro/v2/runtime"
	"github.com/micro/go-micro/v2/store/memory"
	"github.com/micro/micro/v2/internal/namespace"
)

func TestEvents(t *testing.T) {
	// an event is passed through this channel from the test runtime everytime a method is called,
	// this is done since events ae processed async
	eventChan := make(chan *runtime.Service)

	rt := &testRuntime{events: eventChan}
	m := New(rt, Store(memory.NewStore())).(*manager)

	// set the eventPollFrequency to 10ms so events are processed immediately
	eventPollFrequency = time.Millisecond * 10
	go m.watchEvents()

	// timeout async tests after 500ms
	timeout := time.NewTimer(time.Millisecond * 500)

	// the service that should be passed to the runtime
	testSrv := &runtime.Service{Name: "go.micro.service.foo", Version: "latest"}
	opts := &runtime.CreateOptions{Namespace: namespace.DefaultNamespace}

	t.Run("Create", func(t *testing.T) {
		defer rt.Reset()

		if err := m.publishEvent(runtime.Create, testSrv, opts); err != nil {
			t.Errorf("Unexpected error when publishing events: %v", err)
		}

		timeout.Reset(time.Millisecond * 500)

		select {
		case srv := <-eventChan:
			if srv.Name != testSrv.Name || srv.Version != testSrv.Version {
				t.Errorf("Incorrect service passed to the runtime")
			}
		case <-timeout.C:
			t.Fatalf("The runtime wasn't called")
		}

		if rt.createCount != 1 {
			t.Errorf("Expected runtime create to be called 1 time but was actually called %v times", rt.createCount)
		}
	})

	t.Run("Update", func(t *testing.T) {
		defer rt.Reset()

		if err := m.publishEvent(runtime.Update, testSrv, opts); err != nil {
			t.Errorf("Unexpected error when publishing events: %v", err)
		}

		timeout.Reset(time.Millisecond * 500)

		select {
		case srv := <-eventChan:
			if srv.Name != testSrv.Name || srv.Version != testSrv.Version {
				t.Errorf("Incorrect service passed to the runtime")
			}
		case <-timeout.C:
			t.Fatalf("The runtime wasn't called")
		}

		if rt.updateCount != 1 {
			t.Errorf("Expected runtime update to be called 1 time but was actually called %v times", rt.updateCount)
		}
	})

	t.Run("Delete", func(t *testing.T) {
		defer rt.Reset()

		if err := m.publishEvent(runtime.Delete, testSrv, opts); err != nil {
			t.Errorf("Unexpected error when publishing events: %v", err)
		}

		timeout.Reset(time.Millisecond * 500)

		select {
		case srv := <-eventChan:
			if srv.Name != testSrv.Name || srv.Version != testSrv.Version {
				t.Errorf("Incorrect service passed to the runtime")
			}
		case <-timeout.C:
			t.Fatalf("The runtime wasn't called")
		}

		if rt.deleteCount != 1 {
			t.Errorf("Expected runtime delete to be called 1 time but was actually called %v times", rt.deleteCount)
		}
	})
}
<|endoftext|>


<commit_before>/*
Copyright 2014 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package cmd

import (
	"fmt"
	"io"

	"github.com/renstrom/dedent"
	"github.com/spf13/cobra"

	"k8s.io/kubernetes/pkg/api/unversioned"
	"k8s.io/kubernetes/pkg/kubectl"
	cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
	"k8s.io/kubernetes/pkg/kubectl/resource"
	"k8s.io/kubernetes/pkg/runtime"
)

// CreateOptions is the start of the data required to perform the operation.  As new fields are added, add them here instead of
// referencing the cmd.Flags()
type CreateOptions struct {
	Filenames []string
	Recursive bool
}

var (
	create_long = dedent.Dedent(`
		Create a resource by filename or stdin.

		JSON and YAML formats are accepted.`)
	create_example = dedent.Dedent(`
		# Create a pod using the data in pod.json.
		kubectl create -f ./pod.json

		# Create a pod based on the JSON passed into stdin.
		cat pod.json | kubectl create -f -`)
)

func NewCmdCreate(f *cmdutil.Factory, out io.Writer) *cobra.Command {
	options := &CreateOptions{}

	cmd := &cobra.Command{
		Use:     "create -f FILENAME",
		Short:   "Create a resource by filename or stdin",
		Long:    create_long,
		Example: create_example,
		Run: func(cmd *cobra.Command, args []string) {
			if len(options.Filenames) == 0 {
				cmd.Help()
				return
			}
			cmdutil.CheckErr(ValidateArgs(cmd, args))
			cmdutil.CheckErr(cmdutil.ValidateOutputArgs(cmd))
			cmdutil.CheckErr(RunCreate(f, cmd, out, options))
		},
	}

	usage := "Filename, directory, or URL to file to use to create the resource"
	kubectl.AddJsonFilenameFlag(cmd, &options.Filenames, usage)
	cmd.MarkFlagRequired("filename")
	cmdutil.AddValidateFlags(cmd)
	cmdutil.AddRecursiveFlag(cmd, &options.Recursive)
	cmdutil.AddOutputFlagsForMutation(cmd)
	cmdutil.AddApplyAnnotationFlags(cmd)
	cmdutil.AddRecordFlag(cmd)
	cmdutil.AddInclude3rdPartyFlags(cmd)

	// create subcommands
	cmd.AddCommand(NewCmdCreateNamespace(f, out))
	cmd.AddCommand(NewCmdCreateQuota(f, out))
	cmd.AddCommand(NewCmdCreateSecret(f, out))
	cmd.AddCommand(NewCmdCreateConfigMap(f, out))
	cmd.AddCommand(NewCmdCreateServiceAccount(f, out))
	cmd.AddCommand(NewCmdCreateService(f, out))
	cmd.AddCommand(NewCmdCreateDeployment(f, out))
	return cmd
}

func ValidateArgs(cmd *cobra.Command, args []string) error {
	if len(args) != 0 {
		return cmdutil.UsageError(cmd, "Unexpected args: %v", args)
	}
	return nil
}

func RunCreate(f *cmdutil.Factory, cmd *cobra.Command, out io.Writer, options *CreateOptions) error {
	schema, err := f.Validator(cmdutil.GetFlagBool(cmd, "validate"), cmdutil.GetFlagString(cmd, "schema-cache-dir"))
	if err != nil {
		return err
	}

	cmdNamespace, enforceNamespace, err := f.DefaultNamespace()
	if err != nil {
		return err
	}

	mapper, typer, err := f.UnstructuredObject()
	if err != nil {
		return err
	}
	r := resource.NewBuilder(mapper, typer, resource.ClientMapperFunc(f.UnstructuredClientForMapping), runtime.UnstructuredJSONScheme).
		Schema(schema).
		ContinueOnError().
		NamespaceParam(cmdNamespace).DefaultNamespace().
		FilenameParam(enforceNamespace, options.Recursive, options.Filenames...).
		Flatten().
		Do()
	err = r.Err()
	if err != nil {
		return err
	}

	count := 0
	err = r.Visit(func(info *resource.Info, err error) error {
		if err != nil {
			return err
		}
		if err := kubectl.CreateOrUpdateAnnotation(cmdutil.GetFlagBool(cmd, cmdutil.ApplyAnnotationsFlag), info, f.JSONEncoder()); err != nil {
			return cmdutil.AddSourceToErr("creating", info.Source, err)
		}

		if cmdutil.ShouldRecord(cmd, info) {
			if err := cmdutil.RecordChangeCause(info.Object, f.Command()); err != nil {
				return cmdutil.AddSourceToErr("creating", info.Source, err)
			}
		}

		if err := createAndRefresh(info); err != nil {
			return cmdutil.AddSourceToErr("creating", info.Source, err)
		}

		count++
		shortOutput := cmdutil.GetFlagString(cmd, "output") == "name"
		if !shortOutput {
			f.PrintObjectSpecificMessage(info.Object, out)
		}
		cmdutil.PrintSuccess(mapper, shortOutput, out, info.Mapping.Resource, info.Name, "created")
		return nil
	})
	if err != nil {
		return err
	}
	if count == 0 {
		return fmt.Errorf("no objects passed to create")
	}
	return nil
}

// createAndRefresh creates an object from input info and refreshes info with that object
func createAndRefresh(info *resource.Info) error {
	obj, err := resource.NewHelper(info.Client, info.Mapping).Create(info.Namespace, true, info.Object)
	if err != nil {
		return err
	}
	info.Refresh(obj, true)
	return nil
}

// NameFromCommandArgs is a utility function for commands that assume the first argument is a resource name
func NameFromCommandArgs(cmd *cobra.Command, args []string) (string, error) {
	if len(args) == 0 {
		return "", cmdutil.UsageError(cmd, "NAME is required")
	}
	return args[0], nil
}

// CreateSubcommandOptions is an options struct to support create subcommands
type CreateSubcommandOptions struct {
	// Name of resource being created
	Name string
	// StructuredGenerator is the resource generator for the object being created
	StructuredGenerator kubectl.StructuredGenerator
	// DryRun is true if the command should be simulated but not run against the server
	DryRun bool
	// OutputFormat
	OutputFormat string
}

// RunCreateSubcommand executes a create subcommand using the specified options
func RunCreateSubcommand(f *cmdutil.Factory, cmd *cobra.Command, out io.Writer, options *CreateSubcommandOptions) error {
	namespace, _, err := f.DefaultNamespace()
	if err != nil {
		return err
	}
	obj, err := options.StructuredGenerator.StructuredGenerate()
	if err != nil {
		return err
	}
	mapper, typer := f.Object(cmdutil.GetIncludeThirdPartyAPIs(cmd))
	gvks, _, err := typer.ObjectKinds(obj)
	if err != nil {
		return err
	}
	gvk := gvks[0]
	mapping, err := mapper.RESTMapping(unversioned.GroupKind{Group: gvk.Group, Kind: gvk.Kind}, gvk.Version)
	if err != nil {
		return err
	}
	client, err := f.ClientForMapping(mapping)
	if err != nil {
		return err
	}
	resourceMapper := &resource.Mapper{
		ObjectTyper:  typer,
		RESTMapper:   mapper,
		ClientMapper: resource.ClientMapperFunc(f.ClientForMapping),
	}
	info, err := resourceMapper.InfoForObject(obj, nil)
	if err != nil {
		return err
	}
	if err := kubectl.UpdateApplyAnnotation(info, f.JSONEncoder()); err != nil {
		return err
	}
	if !options.DryRun {
		obj, err = resource.NewHelper(client, mapping).Create(namespace, false, info.Object)
		if err != nil {
			return err
		}
	}

	if useShortOutput := options.OutputFormat == "name"; useShortOutput || len(options.OutputFormat) == 0 {
		cmdutil.PrintSuccess(mapper, useShortOutput, out, mapping.Resource, options.Name, "created")
		return nil
	}

	return f.PrintObject(cmd, mapper, obj, out)
}
<commit_msg>UPSTREAM: 34028: add --dry-run option to create root cmd<commit_after>/*
Copyright 2014 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package cmd

import (
	"fmt"
	"io"

	"github.com/renstrom/dedent"
	"github.com/spf13/cobra"

	"k8s.io/kubernetes/pkg/api/unversioned"
	"k8s.io/kubernetes/pkg/kubectl"
	cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
	"k8s.io/kubernetes/pkg/kubectl/resource"
	"k8s.io/kubernetes/pkg/runtime"
)

// CreateOptions is the start of the data required to perform the operation.  As new fields are added, add them here instead of
// referencing the cmd.Flags()
type CreateOptions struct {
	Filenames []string
	Recursive bool
}

var (
	create_long = dedent.Dedent(`
		Create a resource by filename or stdin.

		JSON and YAML formats are accepted.`)
	create_example = dedent.Dedent(`
		# Create a pod using the data in pod.json.
		kubectl create -f ./pod.json

		# Create a pod based on the JSON passed into stdin.
		cat pod.json | kubectl create -f -`)
)

func NewCmdCreate(f *cmdutil.Factory, out io.Writer) *cobra.Command {
	options := &CreateOptions{}

	cmd := &cobra.Command{
		Use:     "create -f FILENAME",
		Short:   "Create a resource by filename or stdin",
		Long:    create_long,
		Example: create_example,
		Run: func(cmd *cobra.Command, args []string) {
			if len(options.Filenames) == 0 {
				cmd.Help()
				return
			}
			cmdutil.CheckErr(ValidateArgs(cmd, args))
			cmdutil.CheckErr(cmdutil.ValidateOutputArgs(cmd))
			cmdutil.CheckErr(RunCreate(f, cmd, out, options))
		},
	}

	usage := "Filename, directory, or URL to file to use to create the resource"
	kubectl.AddJsonFilenameFlag(cmd, &options.Filenames, usage)
	cmd.MarkFlagRequired("filename")
	cmdutil.AddPrinterFlags(cmd)
	cmdutil.AddValidateFlags(cmd)
	cmdutil.AddRecursiveFlag(cmd, &options.Recursive)
	cmdutil.AddApplyAnnotationFlags(cmd)
	cmdutil.AddRecordFlag(cmd)
	cmdutil.AddDryRunFlag(cmd)
	cmdutil.AddInclude3rdPartyFlags(cmd)

	// create subcommands
	cmd.AddCommand(NewCmdCreateNamespace(f, out))
	cmd.AddCommand(NewCmdCreateQuota(f, out))
	cmd.AddCommand(NewCmdCreateSecret(f, out))
	cmd.AddCommand(NewCmdCreateConfigMap(f, out))
	cmd.AddCommand(NewCmdCreateServiceAccount(f, out))
	cmd.AddCommand(NewCmdCreateService(f, out))
	cmd.AddCommand(NewCmdCreateDeployment(f, out))
	return cmd
}

func ValidateArgs(cmd *cobra.Command, args []string) error {
	if len(args) != 0 {
		return cmdutil.UsageError(cmd, "Unexpected args: %v", args)
	}
	return nil
}

func RunCreate(f *cmdutil.Factory, cmd *cobra.Command, out io.Writer, options *CreateOptions) error {
	schema, err := f.Validator(cmdutil.GetFlagBool(cmd, "validate"), cmdutil.GetFlagString(cmd, "schema-cache-dir"))
	if err != nil {
		return err
	}

	cmdNamespace, enforceNamespace, err := f.DefaultNamespace()
	if err != nil {
		return err
	}

	mapper, typer, err := f.UnstructuredObject()
	if err != nil {
		return err
	}
	r := resource.NewBuilder(mapper, typer, resource.ClientMapperFunc(f.UnstructuredClientForMapping), runtime.UnstructuredJSONScheme).
		Schema(schema).
		ContinueOnError().
		NamespaceParam(cmdNamespace).DefaultNamespace().
		FilenameParam(enforceNamespace, options.Recursive, options.Filenames...).
		Flatten().
		Do()
	err = r.Err()
	if err != nil {
		return err
	}

	dryRun := cmdutil.GetFlagBool(cmd, "dry-run")

	count := 0
	err = r.Visit(func(info *resource.Info, err error) error {
		if err != nil {
			return err
		}
		if err := kubectl.CreateOrUpdateAnnotation(cmdutil.GetFlagBool(cmd, cmdutil.ApplyAnnotationsFlag), info, f.JSONEncoder()); err != nil {
			return cmdutil.AddSourceToErr("creating", info.Source, err)
		}

		if cmdutil.ShouldRecord(cmd, info) {
			if err := cmdutil.RecordChangeCause(info.Object, f.Command()); err != nil {
				return cmdutil.AddSourceToErr("creating", info.Source, err)
			}
		}

		if !dryRun {
			if err := createAndRefresh(info); err != nil {
				return cmdutil.AddSourceToErr("creating", info.Source, err)
			}
		}

		count++
		shortOutput := cmdutil.GetFlagString(cmd, "output") == "name"
		if !shortOutput {
			f.PrintObjectSpecificMessage(info.Object, out)
		}

		created := "created"
		if dryRun {
			created = "created (DRY RUN)"
		}

		cmdutil.PrintSuccess(mapper, shortOutput, out, info.Mapping.Resource, info.Name, created)
		return nil
	})
	if err != nil {
		return err
	}
	if count == 0 {
		return fmt.Errorf("no objects passed to create")
	}
	return nil
}

// createAndRefresh creates an object from input info and refreshes info with that object
func createAndRefresh(info *resource.Info) error {
	obj, err := resource.NewHelper(info.Client, info.Mapping).Create(info.Namespace, true, info.Object)
	if err != nil {
		return err
	}
	info.Refresh(obj, true)
	return nil
}

// NameFromCommandArgs is a utility function for commands that assume the first argument is a resource name
func NameFromCommandArgs(cmd *cobra.Command, args []string) (string, error) {
	if len(args) == 0 {
		return "", cmdutil.UsageError(cmd, "NAME is required")
	}
	return args[0], nil
}

// CreateSubcommandOptions is an options struct to support create subcommands
type CreateSubcommandOptions struct {
	// Name of resource being created
	Name string
	// StructuredGenerator is the resource generator for the object being created
	StructuredGenerator kubectl.StructuredGenerator
	// DryRun is true if the command should be simulated but not run against the server
	DryRun bool
	// OutputFormat
	OutputFormat string
}

// RunCreateSubcommand executes a create subcommand using the specified options
func RunCreateSubcommand(f *cmdutil.Factory, cmd *cobra.Command, out io.Writer, options *CreateSubcommandOptions) error {
	namespace, _, err := f.DefaultNamespace()
	if err != nil {
		return err
	}
	obj, err := options.StructuredGenerator.StructuredGenerate()
	if err != nil {
		return err
	}
	mapper, typer := f.Object(cmdutil.GetIncludeThirdPartyAPIs(cmd))
	gvks, _, err := typer.ObjectKinds(obj)
	if err != nil {
		return err
	}
	gvk := gvks[0]
	mapping, err := mapper.RESTMapping(unversioned.GroupKind{Group: gvk.Group, Kind: gvk.Kind}, gvk.Version)
	if err != nil {
		return err
	}
	client, err := f.ClientForMapping(mapping)
	if err != nil {
		return err
	}
	resourceMapper := &resource.Mapper{
		ObjectTyper:  typer,
		RESTMapper:   mapper,
		ClientMapper: resource.ClientMapperFunc(f.ClientForMapping),
	}
	info, err := resourceMapper.InfoForObject(obj, nil)
	if err != nil {
		return err
	}
	if err := kubectl.UpdateApplyAnnotation(info, f.JSONEncoder()); err != nil {
		return err
	}
	if !options.DryRun {
		obj, err = resource.NewHelper(client, mapping).Create(namespace, false, info.Object)
		if err != nil {
			return err
		}
	}

	if useShortOutput := options.OutputFormat == "name"; useShortOutput || len(options.OutputFormat) == 0 {
		cmdutil.PrintSuccess(mapper, useShortOutput, out, mapping.Resource, options.Name, "created")
		return nil
	}

	return f.PrintObject(cmd, mapper, obj, out)
}
<|endoftext|>


<commit_before>package goose

import (
	"github.com/PuerkitoBio/goquery"
	"net/url"
	"regexp"
	"strconv"
	"strings"
)

type candidate struct {
	url     string
	surface int
	score   int
}

func (c *candidate) GetUrl() string {
	return c.url
}

var largebig = regexp.MustCompile("(large|big)")

var rules = map[*regexp.Regexp]int{
	regexp.MustCompile("(large|big)"):          1,
	regexp.MustCompile("upload"):               1,
	regexp.MustCompile("media"):                1,
	regexp.MustCompile("gravatar.com"):         -1,
	regexp.MustCompile("feeds.feedburner.com"): -1,
	regexp.MustCompile("(?i)icon"):             -1,
	regexp.MustCompile("(?i)logo"):             -1,
	regexp.MustCompile("(?i)spinner"):          -1,
	regexp.MustCompile("(?i)loading"):          -1,
	regexp.MustCompile("(?i)ads"):              -1,
	regexp.MustCompile("badge"):                -1,
	regexp.MustCompile("1x1"):                  -1,
	regexp.MustCompile("pixel"):                -1,
	regexp.MustCompile("thumbnail[s]*"):        -1,
	regexp.MustCompile(".html|" +
		".gif|" +
		".ico|" +
		"button|" +
		"twitter.jpg|" +
		"facebook.jpg|" +
		"ap_buy_photo|" +
		"digg.jpg|" +
		"digg.png|" +
		"delicious.png|" +
		"facebook.png|" +
		"reddit.jpg|" +
		"doubleclick|" +
		"diggthis|" +
		"diggThis|" +
		"adserver|" +
		"/ads/|" +
		"ec.atdmt.com|" +
		"mediaplex.com|" +
		"adsatt|" +
		"view.atdmt"): -1}

func score(tag *goquery.Selection) int {
	src, _ := tag.Attr("src")
	if src == "" {
		src, _ = tag.Attr("data-src")
	}
	if src == "" {
		src, _ = tag.Attr("data-lazy-src")
	}
	if src == "" {
		return -1
	}
	tagScore := 0
	for rule, score := range rules {
		if rule.MatchString(src) {
			tagScore += score
		}
	}

	alt, exists := tag.Attr("alt")
	if exists {
		if strings.Contains(alt, "thumbnail") {
			tagScore--
		}
	}

	id, exists := tag.Attr("id")
	if exists {
		if id == "fbPhotoImage" {
			tagScore++
		}
	}
	return tagScore
}

// WebPageResolver fetches all candidate images from the HTML page
func WebPageImageResolver(doc *goquery.Document) ([]candidate, int) {
	imgs := doc.Find("img")

	var candidates []candidate
	significantSurface := 320 * 200
	significantSurfaceCount := 0
	src := ""
	imgs.Each(func(i int, tag *goquery.Selection) {
		var surface int
		src, _ = tag.Attr("src")
		if src == "" {
			src, _ = tag.Attr("data-src")
		}
		if src == "" {
			src, _ = tag.Attr("data-lazy-src")
		}
		if src == "" {
			return
		}

		width, _ := tag.Attr("width")
		height, _ := tag.Attr("height")
		if width != "" {
			w, _ := strconv.Atoi(width)
			if height != "" {
				h, _ := strconv.Atoi(height)
				surface = w * h
			} else {
				surface = w
			}
		} else {
			if height != "" {
				surface, _ = strconv.Atoi(height)
			} else {
				surface = 0
			}
		}

		if surface > significantSurface {
			significantSurfaceCount++
		}

		tagscore := score(tag)
		if tagscore >= 0 {
			c := candidate{
				url:     src,
				surface: surface,
				score:   score(tag),
			}
			candidates = append(candidates, c)
		}
	})

	if len(candidates) == 0 {
		return nil, 0
	}

	return candidates, significantSurfaceCount

}

// WebPageResolver fetches the main image from the HTML page
func WebPageResolver(article *Article) string {
	candidates, significantSurfaceCount := WebPageImageResolver(article.Doc)
	if candidates == nil {
		return ""
	}
	var bestCandidate candidate
	var topImage string
	if significantSurfaceCount > 0 {
		bestCandidate = findBestCandidateFromSurface(candidates)
	} else {
		bestCandidate = findBestCandidateFromScore(candidates)
	}

	topImage = bestCandidate.url
	a, err := url.Parse(topImage)
	if err != nil {
		return topImage
	}
	finalURL, err := url.Parse(article.FinalURL)
	if err != nil {
		return topImage
	}
	b := finalURL.ResolveReference(a)
	topImage = b.String()

	return topImage
}

func findBestCandidateFromSurface(candidates []candidate) candidate {
	max := 0
	var bestCandidate candidate
	for _, candidate := range candidates {
		surface := candidate.surface
		if surface >= max {
			max = surface
			bestCandidate = candidate
		}
	}

	return bestCandidate
}

func findBestCandidateFromScore(candidates []candidate) candidate {
	max := 0
	var bestCandidate candidate
	for _, candidate := range candidates {
		score := candidate.score
		if score >= max {
			max = score
			bestCandidate = candidate
		}
	}

	return bestCandidate
}

type ogTag struct {
	tpe       string
	attribute string
	name      string
	value     string
}

var ogTags = [4]ogTag{
	{
		tpe:       "facebook",
		attribute: "property",
		name:      "og:image",
		value:     "content",
	},
	{
		tpe:       "facebook",
		attribute: "rel",
		name:      "image_src",
		value:     "href",
	},
	{
		tpe:       "twitter",
		attribute: "name",
		name:      "twitter:image",
		value:     "value",
	},
	{
		tpe:       "twitter",
		attribute: "name",
		name:      "twitter:image",
		value:     "content",
	},
}

type ogImage struct {
	url   string
	tpe   string
	score int
}

// OpenGraphResolver return OpenGraph properties
func OpenGraphResolver(doc *goquery.Document) string {
	meta := doc.Find("meta")
	links := doc.Find("link")
	var topImage string
	meta = meta.Union(links)
	var ogImages []ogImage
	meta.Each(func(i int, tag *goquery.Selection) {
		for _, ogTag := range ogTags {
			attr, exist := tag.Attr(ogTag.attribute)
			value, vexist := tag.Attr(ogTag.value)
			if exist && attr == ogTag.name && vexist {
				ogImage := ogImage{
					url:   value,
					tpe:   ogTag.tpe,
					score: 0,
				}

				ogImages = append(ogImages, ogImage)
			}
		}
	})
	if len(ogImages) == 0 {
		return ""
	}
	if len(ogImages) == 1 {
		topImage = ogImages[0].url
		goto IMAGE_FINALIZE
	}
	for _, ogImage := range ogImages {
		if largebig.MatchString(ogImage.url) {
			ogImage.score++
		}
		if ogImage.tpe == "twitter" {
			ogImage.score++
		}
	}
	topImage = findBestImageFromScore(ogImages).url
IMAGE_FINALIZE:
	if !strings.HasPrefix(topImage, "http") {
		topImage = "http://" + topImage
	}

	return topImage
}

// assume that len(ogImages)>=2
func findBestImageFromScore(ogImages []ogImage) ogImage {
	max := 0
	bestOGImage := ogImages[0]
	for _, ogImage := range ogImages[1:] {
		score := ogImage.score
		if score > max {
			max = score
			bestOGImage = ogImage
		}
	}

	return bestOGImage
}
<commit_msg>Refactor Extract getImageSrc, and skip inline images<commit_after>package goose

import (
	"github.com/PuerkitoBio/goquery"
	"net/url"
	"regexp"
	"strconv"
	"strings"
)

type candidate struct {
	url     string
	surface int
	score   int
}

func (c *candidate) GetUrl() string {
	return c.url
}

var largebig = regexp.MustCompile("(large|big)")

var rules = map[*regexp.Regexp]int{
	regexp.MustCompile("(large|big)"):          1,
	regexp.MustCompile("upload"):               1,
	regexp.MustCompile("media"):                1,
	regexp.MustCompile("gravatar.com"):         -1,
	regexp.MustCompile("feeds.feedburner.com"): -1,
	regexp.MustCompile("(?i)icon"):             -1,
	regexp.MustCompile("(?i)logo"):             -1,
	regexp.MustCompile("(?i)spinner"):          -1,
	regexp.MustCompile("(?i)loading"):          -1,
	regexp.MustCompile("(?i)ads"):              -1,
	regexp.MustCompile("badge"):                -1,
	regexp.MustCompile("1x1"):                  -1,
	regexp.MustCompile("pixel"):                -1,
	regexp.MustCompile("thumbnail[s]*"):        -1,
	regexp.MustCompile(".html|" +
		".gif|" +
		".ico|" +
		"button|" +
		"twitter.jpg|" +
		"facebook.jpg|" +
		"ap_buy_photo|" +
		"digg.jpg|" +
		"digg.png|" +
		"delicious.png|" +
		"facebook.png|" +
		"reddit.jpg|" +
		"doubleclick|" +
		"diggthis|" +
		"diggThis|" +
		"adserver|" +
		"/ads/|" +
		"ec.atdmt.com|" +
		"mediaplex.com|" +
		"adsatt|" +
		"view.atdmt"): -1}

func getImageSrc(tag *goquery.Selection) string {
	src, _ := tag.Attr("src")
	// skip inline images
	if strings.Contains(src, "data:image/") {
		src = ""
	}
	if src == "" {
		src, _ = tag.Attr("data-src")
	}
	if src == "" {
		src, _ = tag.Attr("data-lazy-src")
	}
	return src
}

func score(tag *goquery.Selection) int {
	src := getImageSrc(tag)
	if src == "" {
		return -1
	}
	tagScore := 0
	for rule, score := range rules {
		if rule.MatchString(src) {
			tagScore += score
		}
	}

	alt, exists := tag.Attr("alt")
	if exists {
		if strings.Contains(alt, "thumbnail") {
			tagScore--
		}
	}

	id, exists := tag.Attr("id")
	if exists {
		if id == "fbPhotoImage" {
			tagScore++
		}
	}
	return tagScore
}

// WebPageResolver fetches all candidate images from the HTML page
func WebPageImageResolver(doc *goquery.Document) ([]candidate, int) {
	imgs := doc.Find("img")

	var candidates []candidate
	significantSurface := 320 * 200
	significantSurfaceCount := 0
	src := ""
	imgs.Each(func(i int, tag *goquery.Selection) {
		var surface int
		src = getImageSrc(tag)
		if src == "" {
			return
		}

		width, _ := tag.Attr("width")
		height, _ := tag.Attr("height")
		if width != "" {
			w, _ := strconv.Atoi(width)
			if height != "" {
				h, _ := strconv.Atoi(height)
				surface = w * h
			} else {
				surface = w
			}
		} else {
			if height != "" {
				surface, _ = strconv.Atoi(height)
			} else {
				surface = 0
			}
		}

		if surface > significantSurface {
			significantSurfaceCount++
		}

		tagscore := score(tag)
		if tagscore >= 0 {
			c := candidate{
				url:     src,
				surface: surface,
				score:   score(tag),
			}
			candidates = append(candidates, c)
		}
	})

	if len(candidates) == 0 {
		return nil, 0
	}

	return candidates, significantSurfaceCount

}

// WebPageResolver fetches the main image from the HTML page
func WebPageResolver(article *Article) string {
	candidates, significantSurfaceCount := WebPageImageResolver(article.Doc)
	if candidates == nil {
		return ""
	}
	var bestCandidate candidate
	var topImage string
	if significantSurfaceCount > 0 {
		bestCandidate = findBestCandidateFromSurface(candidates)
	} else {
		bestCandidate = findBestCandidateFromScore(candidates)
	}

	topImage = bestCandidate.url
	a, err := url.Parse(topImage)
	if err != nil {
		return topImage
	}
	finalURL, err := url.Parse(article.FinalURL)
	if err != nil {
		return topImage
	}
	b := finalURL.ResolveReference(a)
	topImage = b.String()

	return topImage
}

func findBestCandidateFromSurface(candidates []candidate) candidate {
	max := 0
	var bestCandidate candidate
	for _, candidate := range candidates {
		surface := candidate.surface
		if surface >= max {
			max = surface
			bestCandidate = candidate
		}
	}

	return bestCandidate
}

func findBestCandidateFromScore(candidates []candidate) candidate {
	max := 0
	var bestCandidate candidate
	for _, candidate := range candidates {
		score := candidate.score
		if score >= max {
			max = score
			bestCandidate = candidate
		}
	}

	return bestCandidate
}

type ogTag struct {
	tpe       string
	attribute string
	name      string
	value     string
}

var ogTags = [4]ogTag{
	{
		tpe:       "facebook",
		attribute: "property",
		name:      "og:image",
		value:     "content",
	},
	{
		tpe:       "facebook",
		attribute: "rel",
		name:      "image_src",
		value:     "href",
	},
	{
		tpe:       "twitter",
		attribute: "name",
		name:      "twitter:image",
		value:     "value",
	},
	{
		tpe:       "twitter",
		attribute: "name",
		name:      "twitter:image",
		value:     "content",
	},
}

type ogImage struct {
	url   string
	tpe   string
	score int
}

// OpenGraphResolver return OpenGraph properties
func OpenGraphResolver(doc *goquery.Document) string {
	meta := doc.Find("meta")
	links := doc.Find("link")
	var topImage string
	meta = meta.Union(links)
	var ogImages []ogImage
	meta.Each(func(i int, tag *goquery.Selection) {
		for _, ogTag := range ogTags {
			attr, exist := tag.Attr(ogTag.attribute)
			value, vexist := tag.Attr(ogTag.value)
			if exist && attr == ogTag.name && vexist {
				ogImage := ogImage{
					url:   value,
					tpe:   ogTag.tpe,
					score: 0,
				}

				ogImages = append(ogImages, ogImage)
			}
		}
	})
	if len(ogImages) == 0 {
		return ""
	}
	if len(ogImages) == 1 {
		topImage = ogImages[0].url
		goto IMAGE_FINALIZE
	}
	for _, ogImage := range ogImages {
		if largebig.MatchString(ogImage.url) {
			ogImage.score++
		}
		if ogImage.tpe == "twitter" {
			ogImage.score++
		}
	}
	topImage = findBestImageFromScore(ogImages).url
IMAGE_FINALIZE:
	if !strings.HasPrefix(topImage, "http") {
		topImage = "http://" + topImage
	}

	return topImage
}

// assume that len(ogImages)>=2
func findBestImageFromScore(ogImages []ogImage) ogImage {
	max := 0
	bestOGImage := ogImages[0]
	for _, ogImage := range ogImages[1:] {
		score := ogImage.score
		if score > max {
			max = score
			bestOGImage = ogImage
		}
	}

	return bestOGImage
}
<|endoftext|>


<commit_before>package main

import (
	"github.com/dominikh/conntrack"
	"github.com/dominikh/netdb"

	flag "github.com/ogier/pflag"

	"fmt"
	"net"
	"os"
	"sort"
	"strconv"
	"text/tabwriter"
)

// TODO implement the following flags
//       -N: display NAT box connection information (only valid with SNAT & DNAT)

type FlowSlice conntrack.FlowSlice

type SortBySource struct{ FlowSlice }
type SortByDestination struct{ FlowSlice }
type SortBySPort struct{ FlowSlice }
type SortByDPort struct{ FlowSlice }
type SortByState struct{ FlowSlice }

func (flows FlowSlice) Swap(i, j int) {
	flows[i], flows[j] = flows[j], flows[i]
}

func (flows FlowSlice) Len() int {
	return len(flows)
}

func (flows SortBySource) Less(i, j int) bool {
	return flows.FlowSlice[i].Original.Source.String() < flows.FlowSlice[j].Original.Source.String()
}

func (flows SortByDestination) Less(i, j int) bool {
	return flows.FlowSlice[i].Original.Destination.String() < flows.FlowSlice[j].Original.Destination.String()
}

func (flows SortBySPort) Less(i, j int) bool {
	return flows.FlowSlice[i].Original.SPort < flows.FlowSlice[j].Original.SPort
}

func (flows SortByDPort) Less(i, j int) bool {
	return flows.FlowSlice[i].Original.DPort < flows.FlowSlice[j].Original.DPort
}

func (flows SortByState) Less(i, j int) bool {
	return flows.FlowSlice[i].State < flows.FlowSlice[j].State
}

var Version = "0.1.0"

var onlySNAT = flag.BoolP("snat", "S", false, "Display only SNAT connections")
var onlyDNAT = flag.BoolP("dnat", "D", false, "Display only DNAT connections")
var onlyLocal = flag.BoolP("local", "L", false, "Display only local connections (originating from or going to the router)")
var onlyRouted = flag.BoolP("routed", "R", false, "Display only connections routed through the router")
var noResolve = flag.BoolP("no-resolve", "n", false, "Do not resolve hostnames")
var noHeader = flag.BoolP("no-header", "o", false, "Strip output header")
var protocol = flag.StringP("protocol", "p", "", "Filter connections by protocol")
var sourceHost = flag.StringP("source", "s", "", "Filter by source IP")
var destinationHost = flag.StringP("destination", "d", "", "Filter by destination IP")
var displayVersion = flag.BoolP("version", "v", false, "Print version")
var sortBy = flag.StringP("sort", "r", "src", "Sort connections (src | dst | src-port | dst-port | state)")

func main() {
	flag.Parse()

	if *displayVersion {
		fmt.Println("Version " + Version)
		os.Exit(0)
	}

	which := conntrack.SNATFilter | conntrack.DNATFilter

	if *onlySNAT {
		which = conntrack.SNATFilter
	}

	if *onlyDNAT {
		which = conntrack.DNATFilter
	}

	if *onlyLocal {
		which = conntrack.LocalFilter
	}

	if *onlyRouted {
		which = conntrack.RoutedFilter
	}

	flows, err := conntrack.Flows()
	if err != nil {
		fmt.Fprintf(os.Stderr, "Could not read conntrack information: %s\n", err.Error())
		os.Exit(1)
	}

	filteredFlows := flows.FilterByType(which)
	if *protocol != "" {
		protoent, ok := netdb.GetProtoByName(*protocol)
		if !ok {
			fmt.Fprintf(os.Stderr, "'%s' is not a known protocol.\n", *protocol)
			os.Exit(1)
		}
		filteredFlows = filteredFlows.FilterByProtocol(protoent)
	}

	if *sourceHost != "" {
		sourceIP := net.ParseIP(*sourceHost) // TODO support hostnames
		filteredFlows = filteredFlows.Filter(func(flow conntrack.Flow) bool {
			return flow.Original.Source.Equal(sourceIP)
		})
	}

	if *destinationHost != "" {
		destinationIP := net.ParseIP(*destinationHost) // TODO support hostnames
		filteredFlows = filteredFlows.Filter(func(flow conntrack.Flow) bool {
			return flow.Original.Destination.Equal(destinationIP)
		})
	}

	switch *sortBy {
	case "src":
		sort.Sort(SortBySource{FlowSlice(filteredFlows)})
	case "dst":
		sort.Sort(SortByDestination{FlowSlice(filteredFlows)})
	case "src-port":
		sort.Sort(SortBySPort{FlowSlice(filteredFlows)})
	case "dst-port":
		sort.Sort(SortByDPort{FlowSlice(filteredFlows)})
	case "state":
		sort.Sort(SortByState{FlowSlice(filteredFlows)})
	}

	tabWriter := &tabwriter.Writer{}
	tabWriter.Init(os.Stdout, 0, 0, 4, ' ', 0)

	if !*noHeader {
		fmt.Fprintln(tabWriter, "Proto\tSource Address\tDestination Address\tState")
	}

	for _, flow := range filteredFlows {
		sHostname := resolve(flow.Original.Source, *noResolve)
		dHostname := resolve(flow.Original.Destination, *noResolve)
		sPortName := portToName(int(flow.Original.SPort), flow.Protocol.Name)
		dPortName := portToName(int(flow.Original.DPort), flow.Protocol.Name)
		fmt.Fprintf(tabWriter, "%s\t%s:%s\t%s:%s\t%s\n",
			flow.Protocol.Name,
			sHostname,
			sPortName,
			dHostname,
			dPortName,
			flow.State,
		)
	}
	tabWriter.Flush()
}

func portToName(port int, protocol string) string {
	servent, ok := netdb.GetServByPort(port, protocol)
	if !ok {
		return strconv.FormatInt(int64(port), 10)
	}

	return servent.Name
}

func resolve(ip net.IP, noop bool) string {
	if noop {
		return ip.String()
	}

	lookup, err := net.LookupAddr(ip.String())
	if err == nil && len(lookup) > 0 {
		return lookup[0]
	}

	return ip.String()
}
<commit_msg>add -x as noop flag<commit_after>package main

import (
	"github.com/dominikh/conntrack"
	"github.com/dominikh/netdb"

	flag "github.com/ogier/pflag"

	"fmt"
	"net"
	"os"
	"sort"
	"strconv"
	"text/tabwriter"
)

// TODO implement the following flags
//       -N: display NAT box connection information (only valid with SNAT & DNAT)

type FlowSlice conntrack.FlowSlice

type SortBySource struct{ FlowSlice }
type SortByDestination struct{ FlowSlice }
type SortBySPort struct{ FlowSlice }
type SortByDPort struct{ FlowSlice }
type SortByState struct{ FlowSlice }

func (flows FlowSlice) Swap(i, j int) {
	flows[i], flows[j] = flows[j], flows[i]
}

func (flows FlowSlice) Len() int {
	return len(flows)
}

func (flows SortBySource) Less(i, j int) bool {
	return flows.FlowSlice[i].Original.Source.String() < flows.FlowSlice[j].Original.Source.String()
}

func (flows SortByDestination) Less(i, j int) bool {
	return flows.FlowSlice[i].Original.Destination.String() < flows.FlowSlice[j].Original.Destination.String()
}

func (flows SortBySPort) Less(i, j int) bool {
	return flows.FlowSlice[i].Original.SPort < flows.FlowSlice[j].Original.SPort
}

func (flows SortByDPort) Less(i, j int) bool {
	return flows.FlowSlice[i].Original.DPort < flows.FlowSlice[j].Original.DPort
}

func (flows SortByState) Less(i, j int) bool {
	return flows.FlowSlice[i].State < flows.FlowSlice[j].State
}

var Version = "0.1.0"

var onlySNAT = flag.BoolP("snat", "S", false, "Display only SNAT connections")
var onlyDNAT = flag.BoolP("dnat", "D", false, "Display only DNAT connections")
var onlyLocal = flag.BoolP("local", "L", false, "Display only local connections (originating from or going to the router)")
var onlyRouted = flag.BoolP("routed", "R", false, "Display only connections routed through the router")
var noResolve = flag.BoolP("no-resolve", "n", false, "Do not resolve hostnames")
var noHeader = flag.BoolP("no-header", "o", false, "Strip output header")
var protocol = flag.StringP("protocol", "p", "", "Filter connections by protocol")
var sourceHost = flag.StringP("source", "s", "", "Filter by source IP")
var destinationHost = flag.StringP("destination", "d", "", "Filter by destination IP")
var displayVersion = flag.BoolP("version", "v", false, "Print version")
var sortBy = flag.StringP("sort", "r", "src", "Sort connections (src | dst | src-port | dst-port | state)")
var _ = flag.BoolP("extended-hostnames", "x", false, "This flag serves no purpose other than compatibility")

func main() {
	flag.Parse()

	if *displayVersion {
		fmt.Println("Version " + Version)
		os.Exit(0)
	}

	which := conntrack.SNATFilter | conntrack.DNATFilter

	if *onlySNAT {
		which = conntrack.SNATFilter
	}

	if *onlyDNAT {
		which = conntrack.DNATFilter
	}

	if *onlyLocal {
		which = conntrack.LocalFilter
	}

	if *onlyRouted {
		which = conntrack.RoutedFilter
	}

	flows, err := conntrack.Flows()
	if err != nil {
		fmt.Fprintf(os.Stderr, "Could not read conntrack information: %s\n", err.Error())
		os.Exit(1)
	}

	filteredFlows := flows.FilterByType(which)
	if *protocol != "" {
		protoent, ok := netdb.GetProtoByName(*protocol)
		if !ok {
			fmt.Fprintf(os.Stderr, "'%s' is not a known protocol.\n", *protocol)
			os.Exit(1)
		}
		filteredFlows = filteredFlows.FilterByProtocol(protoent)
	}

	if *sourceHost != "" {
		sourceIP := net.ParseIP(*sourceHost) // TODO support hostnames
		filteredFlows = filteredFlows.Filter(func(flow conntrack.Flow) bool {
			return flow.Original.Source.Equal(sourceIP)
		})
	}

	if *destinationHost != "" {
		destinationIP := net.ParseIP(*destinationHost) // TODO support hostnames
		filteredFlows = filteredFlows.Filter(func(flow conntrack.Flow) bool {
			return flow.Original.Destination.Equal(destinationIP)
		})
	}

	switch *sortBy {
	case "src":
		sort.Sort(SortBySource{FlowSlice(filteredFlows)})
	case "dst":
		sort.Sort(SortByDestination{FlowSlice(filteredFlows)})
	case "src-port":
		sort.Sort(SortBySPort{FlowSlice(filteredFlows)})
	case "dst-port":
		sort.Sort(SortByDPort{FlowSlice(filteredFlows)})
	case "state":
		sort.Sort(SortByState{FlowSlice(filteredFlows)})
	}

	tabWriter := &tabwriter.Writer{}
	tabWriter.Init(os.Stdout, 0, 0, 4, ' ', 0)

	if !*noHeader {
		fmt.Fprintln(tabWriter, "Proto\tSource Address\tDestination Address\tState")
	}

	for _, flow := range filteredFlows {
		sHostname := resolve(flow.Original.Source, *noResolve)
		dHostname := resolve(flow.Original.Destination, *noResolve)
		sPortName := portToName(int(flow.Original.SPort), flow.Protocol.Name)
		dPortName := portToName(int(flow.Original.DPort), flow.Protocol.Name)
		fmt.Fprintf(tabWriter, "%s\t%s:%s\t%s:%s\t%s\n",
			flow.Protocol.Name,
			sHostname,
			sPortName,
			dHostname,
			dPortName,
			flow.State,
		)
	}
	tabWriter.Flush()
}

func portToName(port int, protocol string) string {
	servent, ok := netdb.GetServByPort(port, protocol)
	if !ok {
		return strconv.FormatInt(int64(port), 10)
	}

	return servent.Name
}

func resolve(ip net.IP, noop bool) string {
	if noop {
		return ip.String()
	}

	lookup, err := net.LookupAddr(ip.String())
	if err == nil && len(lookup) > 0 {
		return lookup[0]
	}

	return ip.String()
}
<|endoftext|>