<commit_before>package app

import (
	"fmt"

	"github.com/moncho/dry/version"
)

//ShortHelp is a short description of dry
const ShortHelp = `
dry

A tool to interact with a Docker Daemon from the terminal.
`

var help = `
<white>dry ` + fmt.Sprintf("version %s, build %s", version.VERSION, version.GITCOMMIT) + `</>` +
	`
A tool to interact with a Docker Daemon from the terminal.

Visit <blue>http://moncho.github.io/dry/</> for more information.

<yellow>Global keybinds</>
	<white>F8</>        Shows Docker disk usage
	<white>F9</>        Shows the last 10 events reported by Docker
	<white>F10</>       Inspects Docker
	<white>1</>         To container list
	<white>2</>         To image list
	<white>3</>         To network list
	<white>4</>         To node list (in Swarm mode)
	<white>5</>         To service list (in Swarm mode)
	<white>m</>         Show container monitor mode
	<white>h</>         Shows this help screen
	<white>Ctrl+c</>    Quits <white>dry</> inmediately
	<white>q</>         Quits <white>dry</>
	<white>esc</>       Goes back to the main screen

<yellow>Container list keybinds</>
	<white>F1</>        Cycles through containers sort modes (by Id | by Image | by Status | by Name)
	<white>F2</>        Toggles showing all containers (default shows just running)
	<white>F3</>        Filters containers by its name
	<white>F5</>        Refreshes container list
	<white>e</>         Removes the selected container
	<white>Ctrl+e</>    Removes all stopped containers
	<white>Ctrl+k</>    Kills the selected container
	<white>l</>         Displays the logs of the selected container
	<white>Ctrl+r</>    Restarts selected container
	<white>s</>         Displays a live stream of the selected container resource usage statistics
	<white>Ctrl+t</>    Stops selected container (noop if it is not running)
	<white>Enter</>     Returns low-level information of the selected container

<yellow>Image list keybinds</>
	<white>F1</>        Cycles through images sort modes (by Repo | by Id | by Creation date | by Size)
	<white>F5</>        Refresh the image list
	<white>Ctrl+e</>    Removes the selected image
	<white>Ctrl+f</>    Forces removal of the selected image
	<white>i</>         Shows image history
	<white>Enter</>     Returns low-level information of the selected image

<yellow>Network list keybinds</>
	<white>Enter</>     Returns low-level information of the selected network

<yellow>Node list keybinds</>
	<white>Enter</>     Shows the list of taks running on the selected node

<yellow>Service list keybinds</>
	<white>Enter</>     Shows the list of taks that are part of the selected service
	<white>l</>         Displays the logs of the selected service
	<white>Ctrl+R</>    Removes the selected service

<yellow>Move around in lists</>
	<white>ArrowUp</>   Moves the cursor one line up
	<white>ArrowDown</> Moves the cursor one line down
	<white>g</>         Moves the cursor to the beginning of the list
	<white>G</>         Moves the cursor to the end of the list

<yellow>Move around in logs/inspect buffers</>
	<white>/</>         Searches for a pattern
	<white>F</>         Only show lines that matches a pattern
	<white>g</>         Moves the cursor to the beginning
	<white>G</>         Moves the cursor until the end
	<white>n</>         After a search, it moves forwards to the next search hit
	<white>N</>         After a search, it moves backwards to the previous search hit
	<white>pg up</>     Moves the cursor "screen size" lines up
	<white>pg down</>   Moves the cursor "screen size" lines down

<r> Press ESC to exit help. </r>
`

const (
	commonMappings = "<b>[H]:<darkgrey>Help</> <b>[Q]:<darkgrey>Quit</> <blue>|</> "
	keyMappings    = commonMappings +
		"<b>[F1]:<darkgrey>Sort</> <b>[F2]:<darkgrey>Toggle Show Containers</> <b>[F3]:<darkgrey>Filter(By Name)</> <b>[F5]:<darkgrey>Refresh</> <blue>|</> " +
		"<b>[m]:<darkgrey>Monitor mode</> <b>[2]:<darkgrey>Images</> <b>[3]:<darkgrey>Networks</> <b>[4]:<darkgrey>Nodes</> <b>[5]:<darkgrey>Services</> <blue>|</> <b>[Enter]:<darkgrey>Commands</></>"

	monitorMapping = commonMappings +
		"<b>[m]:<darkgrey>Monitor mode</> <b>[1]:<darkgrey>Containers</> <b>[2]:<darkgrey>Images</> <b>[3]:<darkgrey>Networks</> <b>[4]:<darkgrey>Nodes</> <b>[5]:<darkgrey>Services</>"

	swarmMapping = commonMappings +
		"<b>[m]:<darkgrey>Monitor mode</> <b>[1]:<darkgrey>Containers</> <b>[2]:<darkgrey>Images</> <b>[3]:<darkgrey>Networks</> <b>[4]:<darkgrey>Nodes</> <b>[5]:<darkgrey>Services</>"

	imagesKeyMappings = commonMappings +
		"<b>[F1]:<darkgrey>Sort</> <b>[F5]:<darkgrey>Refresh</> <blue>|</> " +
		"<b>[1]:<darkgrey>Containers</> <b>[3]:<darkgrey>Networks</> <b>[4]:<darkgrey>Nodes</> <b>[5]:<darkgrey>Services</> <blue>|</>" +
		"<b>[Ctrl+D]:<darkgrey>Remove Dangling</> <b>[Ctrl+E]:<darkgrey>Remove</> <b>[Ctrl+F]:<darkgrey>Force Remove</> <b>[I]:<darkgrey>History</>"

	networkKeyMappings = commonMappings +
		"<b>[F1]:<darkgrey>Sort</> <b>[F5]:<darkgrey>Refresh</> <blue>|</> " +
		"<b>[1]:<darkgrey>Containers</> <b>[2]:<darkgrey>Images</> <b>[4]:<darkgrey>Nodes</> <b>[5]:<darkgrey>Services</> <blue>|</>" +
		"<b>[Ctrl+E]:<darkgrey>Remove</> <b>[Enter]:<darkgrey>Inspect</>"

	diskUsageKeyMappings = commonMappings +
		"<b>[1]:<darkgrey>Containers</> <b>[2]:<darkgrey>Images</><blue>|</> <b>[3]:<darkgrey>Networks</> <b>[4]:<darkgrey>Nodes</> <b>[5]:<darkgrey>Services</> <blue>|</>" +
		"<b>[p]:<darkgrey>Prune</>"

	serviceKeyMappings = swarmMapping + " <blue>|</> <b>[F1]:<darkgrey>Sort</> <b>[F5]:<darkgrey>Refresh</> <blue>|</> <b>[l]:<darkgrey>Service logs</> <b>[Ctrl+R]:<darkgrey>Remove Service</> <b>[Ctrl+S]:<darkgrey>Scale service</>"

	nodeKeyMappings = swarmMapping + " <blue>|</> <b>[F1]:<darkgrey>Sort</> <b>[F5]:<darkgrey>Refresh</> <blue>|</>  <b>[Enter]:<darkgrey>Show Node Tasks</> <b>[Ctrl+A]:<darkgrey>Set Availability</>"

	commandsMenuBar = "<b>[Esc]:<darkgrey>Back</> <b>[Up]:<darkgrey>Cursor Up</> <b>[Down]:<darkgrey>Cursor Down</> <b>[Enter]:<darkgrey>Execute Command</>"
)
<commit_msg>Typo, fixes #55<commit_after>package app

import (
	"fmt"

	"github.com/moncho/dry/version"
)

//ShortHelp is a short description of dry
const ShortHelp = `
dry

A tool to interact with a Docker Daemon from the terminal.
`

var help = `
<white>dry ` + fmt.Sprintf("version %s, build %s", version.VERSION, version.GITCOMMIT) + `</>` +
	`
A tool to interact with a Docker Daemon from the terminal.

Visit <blue>http://moncho.github.io/dry/</> for more information.

<yellow>Global keybinds</>
	<white>F8</>        Shows Docker disk usage
	<white>F9</>        Shows the last 10 events reported by Docker
	<white>F10</>       Inspects Docker
	<white>1</>         To container list
	<white>2</>         To image list
	<white>3</>         To network list
	<white>4</>         To node list (in Swarm mode)
	<white>5</>         To service list (in Swarm mode)
	<white>m</>         Show container monitor mode
	<white>h</>         Shows this help screen
	<white>Ctrl+c</>    Quits <white>dry</> immediately
	<white>q</>         Quits <white>dry</>
	<white>esc</>       Goes back to the main screen

<yellow>Container list keybinds</>
	<white>F1</>        Cycles through containers sort modes (by Id | by Image | by Status | by Name)
	<white>F2</>        Toggles showing all containers (default shows just running)
	<white>F3</>        Filters containers by its name
	<white>F5</>        Refreshes container list
	<white>e</>         Removes the selected container
	<white>Ctrl+e</>    Removes all stopped containers
	<white>Ctrl+k</>    Kills the selected container
	<white>l</>         Displays the logs of the selected container
	<white>Ctrl+r</>    Restarts selected container
	<white>s</>         Displays a live stream of the selected container resource usage statistics
	<white>Ctrl+t</>    Stops selected container (noop if it is not running)
	<white>Enter</>     Returns low-level information of the selected container

<yellow>Image list keybinds</>
	<white>F1</>        Cycles through images sort modes (by Repo | by Id | by Creation date | by Size)
	<white>F5</>        Refresh the image list
	<white>Ctrl+e</>    Removes the selected image
	<white>Ctrl+f</>    Forces removal of the selected image
	<white>i</>         Shows image history
	<white>Enter</>     Returns low-level information of the selected image

<yellow>Network list keybinds</>
	<white>Enter</>     Returns low-level information of the selected network

<yellow>Node list keybinds</>
	<white>Enter</>     Shows the list of taks running on the selected node

<yellow>Service list keybinds</>
	<white>Enter</>     Shows the list of taks that are part of the selected service
	<white>l</>         Displays the logs of the selected service
	<white>Ctrl+R</>    Removes the selected service

<yellow>Move around in lists</>
	<white>ArrowUp</>   Moves the cursor one line up
	<white>ArrowDown</> Moves the cursor one line down
	<white>g</>         Moves the cursor to the beginning of the list
	<white>G</>         Moves the cursor to the end of the list

<yellow>Move around in logs/inspect buffers</>
	<white>/</>         Searches for a pattern
	<white>F</>         Only show lines that matches a pattern
	<white>g</>         Moves the cursor to the beginning
	<white>G</>         Moves the cursor until the end
	<white>n</>         After a search, it moves forwards to the next search hit
	<white>N</>         After a search, it moves backwards to the previous search hit
	<white>pg up</>     Moves the cursor "screen size" lines up
	<white>pg down</>   Moves the cursor "screen size" lines down

<r> Press ESC to exit help. </r>
`

const (
	commonMappings = "<b>[H]:<darkgrey>Help</> <b>[Q]:<darkgrey>Quit</> <blue>|</> "
	keyMappings    = commonMappings +
		"<b>[F1]:<darkgrey>Sort</> <b>[F2]:<darkgrey>Toggle Show Containers</> <b>[F3]:<darkgrey>Filter(By Name)</> <b>[F5]:<darkgrey>Refresh</> <blue>|</> " +
		"<b>[m]:<darkgrey>Monitor mode</> <b>[2]:<darkgrey>Images</> <b>[3]:<darkgrey>Networks</> <b>[4]:<darkgrey>Nodes</> <b>[5]:<darkgrey>Services</> <blue>|</> <b>[Enter]:<darkgrey>Commands</></>"

	monitorMapping = commonMappings +
		"<b>[m]:<darkgrey>Monitor mode</> <b>[1]:<darkgrey>Containers</> <b>[2]:<darkgrey>Images</> <b>[3]:<darkgrey>Networks</> <b>[4]:<darkgrey>Nodes</> <b>[5]:<darkgrey>Services</>"

	swarmMapping = commonMappings +
		"<b>[m]:<darkgrey>Monitor mode</> <b>[1]:<darkgrey>Containers</> <b>[2]:<darkgrey>Images</> <b>[3]:<darkgrey>Networks</> <b>[4]:<darkgrey>Nodes</> <b>[5]:<darkgrey>Services</>"

	imagesKeyMappings = commonMappings +
		"<b>[F1]:<darkgrey>Sort</> <b>[F5]:<darkgrey>Refresh</> <blue>|</> " +
		"<b>[1]:<darkgrey>Containers</> <b>[3]:<darkgrey>Networks</> <b>[4]:<darkgrey>Nodes</> <b>[5]:<darkgrey>Services</> <blue>|</>" +
		"<b>[Ctrl+D]:<darkgrey>Remove Dangling</> <b>[Ctrl+E]:<darkgrey>Remove</> <b>[Ctrl+F]:<darkgrey>Force Remove</> <b>[I]:<darkgrey>History</>"

	networkKeyMappings = commonMappings +
		"<b>[F1]:<darkgrey>Sort</> <b>[F5]:<darkgrey>Refresh</> <blue>|</> " +
		"<b>[1]:<darkgrey>Containers</> <b>[2]:<darkgrey>Images</> <b>[4]:<darkgrey>Nodes</> <b>[5]:<darkgrey>Services</> <blue>|</>" +
		"<b>[Ctrl+E]:<darkgrey>Remove</> <b>[Enter]:<darkgrey>Inspect</>"

	diskUsageKeyMappings = commonMappings +
		"<b>[1]:<darkgrey>Containers</> <b>[2]:<darkgrey>Images</><blue>|</> <b>[3]:<darkgrey>Networks</> <b>[4]:<darkgrey>Nodes</> <b>[5]:<darkgrey>Services</> <blue>|</>" +
		"<b>[p]:<darkgrey>Prune</>"

	serviceKeyMappings = swarmMapping + " <blue>|</> <b>[F1]:<darkgrey>Sort</> <b>[F5]:<darkgrey>Refresh</> <blue>|</> <b>[l]:<darkgrey>Service logs</> <b>[Ctrl+R]:<darkgrey>Remove Service</> <b>[Ctrl+S]:<darkgrey>Scale service</>"

	nodeKeyMappings = swarmMapping + " <blue>|</> <b>[F1]:<darkgrey>Sort</> <b>[F5]:<darkgrey>Refresh</> <blue>|</>  <b>[Enter]:<darkgrey>Show Node Tasks</> <b>[Ctrl+A]:<darkgrey>Set Availability</>"

	commandsMenuBar = "<b>[Esc]:<darkgrey>Back</> <b>[Up]:<darkgrey>Cursor Up</> <b>[Down]:<darkgrey>Cursor Down</> <b>[Enter]:<darkgrey>Execute Command</>"
)
<|endoftext|>


<commit_before>package app

import (
	"fmt"

	"github.com/moncho/dry/version"
)

//ShortHelp is a short description of dry
const ShortHelp = `
dry

A tool to interact with a Docker Daemon from the terminal.
`

var help = `
<white>dry ` + fmt.Sprintf("version %s, build %s", version.VERSION, version.GITCOMMIT) + `</>` +
	`
A tool to interact with a Docker Daemon from the terminal.

Visit <blue>http://moncho.github.io/dry/</> for more information.

<yellow>Global keybinds</>
	<white>F8</>        Shows Docker disk usage
	<white>F9</>        Shows the last 10 events reported by Docker
	<white>F10</>       Inspects Docker
	<white>1</>         To container list
	<white>2</>         To image list
	<white>3</>         To network list
	<white>4</>         To node list (in Swarm mode)
	<white>5</>         To service list (in Swarm mode)
	<white>6</>         To stack list (in Swarm mode)
	<white>m</>         Show container monitor mode
	<white>h</>         Shows this help screen
	<white>Ctrl+c</>    Quits <white>dry</> immediately
	<white>q</>         Quits <white>dry</>
	<white>esc</>       Goes back to the main screen

<yellow>Global list keybinds</>
	<white>F1</>        Cycles through sort modes
	<white>F5</>        Refreshes the list
	<white>%</>         Filter

<yellow>Container list keybinds</>
	<white>F2</>        Toggles showing all containers (default shows just running)
	<white>e</>         Removes the selected container
	<white>Ctrl+e</>    Removes all stopped containers
	<white>Ctrl+k</>    Kills the selected container
	<white>l</>         Displays the logs of the selected container
	<white>Ctrl+r</>    Restarts selected container
	<white>s</>         Displays a live stream of the selected container resource usage statistics
	<white>Ctrl+t</>    Stops selected container (noop if it is not running)
	<white>Enter</>     Returns low-level information of the selected container

<yellow>Image list keybinds</>
	<white>Ctrl+e</>    Removes the selected image
	<white>Ctrl+f</>    Forces removal of the selected image
	<white>i</>         Shows image history
	<white>Enter</>     Returns low-level information of the selected image

<yellow>Network list keybinds</>
	<white>Enter</>     Returns low-level information of the selected network

<yellow>Node list keybinds</>
	<white>Enter</>     Shows the list of taks running on the selected node

<yellow>Service list keybinds</>
	<white>Enter</>     Shows the list of taks that are part of the selected service
	<white>l</>         Displays the logs of the selected service
	<white>Ctrl+R</>    Removes the selected service
	<white>Ctrl+S</>    Scales the selected service
	<white>Ctrl+U</>    Forces an update of the selected service

<yellow>Stack list keybinds</>
	<white>Enter</>     Shows the list of services of the selected stack
	<white>Ctrl+R</>    Removes the selected stack

<yellow>Move around in lists</>
	<white>ArrowUp</>   Moves the cursor one line up
	<white>ArrowDown</> Moves the cursor one line down
	<white>g</>         Moves the cursor to the beginning of the list
	<white>G</>         Moves the cursor to the end of the list

<yellow>Move around in logs/inspect buffers</>
	<white>/</>         Searches for a pattern
	<white>F</>         Only show lines that matches a pattern
	<white>g</>         Moves the cursor to the beginning
	<white>G</>         Moves the cursor until the end
	<white>n</>         After a search, it moves forwards to the next search hit
	<white>N</>         After a search, it moves backwards to the previous search hit
	<white>pg up</>     Moves the cursor "screen size" lines up
	<white>pg down</>   Moves the cursor "screen size" lines down

<r> Press ESC to exit help. </r>
`

const (
	commonMappings = "<b>[H]:<darkgrey>Help</> <b>[Q]:<darkgrey>Quit</> <blue>|</> "
	keyMappings    = commonMappings +
		"<b>[F1]:<darkgrey>Sort</> <b>[F2]:<darkgrey>Toggle Show Containers</> <b>[F5]:<darkgrey>Refresh</> <b>[%]:<darkgrey>Filter</> <blue>|</> " +
		"<b>[m]:<darkgrey>Monitor mode</> <b>[2]:<darkgrey>Images</> <b>[3]:<darkgrey>Networks</> <b>[4]:<darkgrey>Nodes</> <b>[5]:<darkgrey>Services</> <b>[6]:<darkgrey>Stacks</> <blue>|</> <b>[Enter]:<darkgrey>Commands</></>"

	monitorMapping = commonMappings +
		"<b>[m]:<darkgrey>Monitor mode</> <b>[1]:<darkgrey>Containers</> <b>[2]:<darkgrey>Images</> <b>[3]:<darkgrey>Networks</> <b>[4]:<darkgrey>Nodes</> <b>[5]:<darkgrey>Services</> <b>[6]:<darkgrey>Stacks</>"

	swarmMapping = commonMappings +
		"<b>[m]:<darkgrey>Monitor mode</> <b>[1]:<darkgrey>Containers</> <b>[2]:<darkgrey>Images</> <b>[3]:<darkgrey>Networks</> <b>[4]:<darkgrey>Nodes</> <b>[5]:<darkgrey>Services</> <b>[6]:<darkgrey>Stacks</>"

	imagesKeyMappings = commonMappings +
		"<b>[F1]:<darkgrey>Sort</> <b>[F5]:<darkgrey>Refresh</> <blue>|</> " +
		"<b>[1]:<darkgrey>Containers</> <b>[3]:<darkgrey>Networks</> <b>[4]:<darkgrey>Nodes</> <b>[5]:<darkgrey>Services</> <b>[6]:<darkgrey>Stacks</> <blue>|</>" +
		"<b>[Ctrl+D]:<darkgrey>Remove Dangling</> <b>[Ctrl+E]:<darkgrey>Remove</> <b>[Ctrl+F]:<darkgrey>Force Remove</> <b>[I]:<darkgrey>History</>"

	networkKeyMappings = commonMappings +
		"<b>[F1]:<darkgrey>Sort</> <b>[F5]:<darkgrey>Refresh</> <blue>|</> " +
		"<b>[1]:<darkgrey>Containers</> <b>[2]:<darkgrey>Images</> <b>[4]:<darkgrey>Nodes</> <b>[5]:<darkgrey>Services</> <b>[6]:<darkgrey>Stacks</> <blue>|</>" +
		"<b>[Ctrl+E]:<darkgrey>Remove</> <b>[Enter]:<darkgrey>Inspect</>"

	diskUsageKeyMappings = commonMappings +
		"<b>[1]:<darkgrey>Containers</> <b>[2]:<darkgrey>Images</><blue>|</> <b>[3]:<darkgrey>Networks</> <b>[4]:<darkgrey>Nodes</> <b>[5]:<darkgrey>Services</> <b>[6]:<darkgrey>Stacks</> <blue>|</>" +
		"<b>[p]:<darkgrey>Prune</>"

	serviceKeyMappings = swarmMapping + "<blue>|</> <b>[F1]:<darkgrey>Sort</> <b>[F5]:<darkgrey>Refresh</> <b>[%]:<darkgrey>Filter</> <blue>|</> <b>[l]:<darkgrey>Service logs</> <b>[Ctrl+R]:<darkgrey>Remove Service</> <b>[Ctrl+S]:<darkgrey>Scale service</><b>[Ctrl+K]:<darkgrey>Update service</>"

	stackKeyMappings = swarmMapping + "<blue>|</> <b>[F1]:<darkgrey>Sort</> <b>[F5]:<darkgrey>Refresh</> <b>[%]:<darkgrey>Filter</> <blue>|</> <b>[Ctrl+R]:<darkgrey>Remove Stack</>"

	nodeKeyMappings = swarmMapping + " <blue>|</> <b>[F1]:<darkgrey>Sort</> <b>[F5]:<darkgrey>Refresh</> <blue>|</>  <b>[Enter]:<darkgrey>Show Node Tasks</> <b>[Ctrl+A]:<darkgrey>Set Availability</>"

	commandsMenuBar = "<b>[Esc]:<darkgrey>Back</> <b>[Up]:<darkgrey>Cursor Up</> <b>[Down]:<darkgrey>Cursor Down</> <b>[Enter]:<darkgrey>Execute Command</>"
)
<commit_msg>fix spelling on help screen for node and service list keybinds (#80)<commit_after>package app

import (
	"fmt"

	"github.com/moncho/dry/version"
)

//ShortHelp is a short description of dry
const ShortHelp = `
dry

A tool to interact with a Docker Daemon from the terminal.
`

var help = `
<white>dry ` + fmt.Sprintf("version %s, build %s", version.VERSION, version.GITCOMMIT) + `</>` +
	`
A tool to interact with a Docker Daemon from the terminal.

Visit <blue>http://moncho.github.io/dry/</> for more information.

<yellow>Global keybinds</>
	<white>F8</>        Shows Docker disk usage
	<white>F9</>        Shows the last 10 events reported by Docker
	<white>F10</>       Inspects Docker
	<white>1</>         To container list
	<white>2</>         To image list
	<white>3</>         To network list
	<white>4</>         To node list (in Swarm mode)
	<white>5</>         To service list (in Swarm mode)
	<white>6</>         To stack list (in Swarm mode)
	<white>m</>         Show container monitor mode
	<white>h</>         Shows this help screen
	<white>Ctrl+c</>    Quits <white>dry</> immediately
	<white>q</>         Quits <white>dry</>
	<white>esc</>       Goes back to the main screen

<yellow>Global list keybinds</>
	<white>F1</>        Cycles through sort modes
	<white>F5</>        Refreshes the list
	<white>%</>         Filter

<yellow>Container list keybinds</>
	<white>F2</>        Toggles showing all containers (default shows just running)
	<white>e</>         Removes the selected container
	<white>Ctrl+e</>    Removes all stopped containers
	<white>Ctrl+k</>    Kills the selected container
	<white>l</>         Displays the logs of the selected container
	<white>Ctrl+r</>    Restarts selected container
	<white>s</>         Displays a live stream of the selected container resource usage statistics
	<white>Ctrl+t</>    Stops selected container (noop if it is not running)
	<white>Enter</>     Returns low-level information of the selected container

<yellow>Image list keybinds</>
	<white>Ctrl+e</>    Removes the selected image
	<white>Ctrl+f</>    Forces removal of the selected image
	<white>i</>         Shows image history
	<white>Enter</>     Returns low-level information of the selected image

<yellow>Network list keybinds</>
	<white>Enter</>     Returns low-level information of the selected network

<yellow>Node list keybinds</>
	<white>Enter</>     Shows the list of tasks running on the selected node

<yellow>Service list keybinds</>
	<white>Enter</>     Shows the list of tasks that are part of the selected service
	<white>l</>         Displays the logs of the selected service
	<white>Ctrl+R</>    Removes the selected service
	<white>Ctrl+S</>    Scales the selected service
	<white>Ctrl+U</>    Forces an update of the selected service

<yellow>Stack list keybinds</>
	<white>Enter</>     Shows the list of services of the selected stack
	<white>Ctrl+R</>    Removes the selected stack

<yellow>Move around in lists</>
	<white>ArrowUp</>   Moves the cursor one line up
	<white>ArrowDown</> Moves the cursor one line down
	<white>g</>         Moves the cursor to the beginning of the list
	<white>G</>         Moves the cursor to the end of the list

<yellow>Move around in logs/inspect buffers</>
	<white>/</>         Searches for a pattern
	<white>F</>         Only show lines that matches a pattern
	<white>g</>         Moves the cursor to the beginning
	<white>G</>         Moves the cursor until the end
	<white>n</>         After a search, it moves forwards to the next search hit
	<white>N</>         After a search, it moves backwards to the previous search hit
	<white>pg up</>     Moves the cursor "screen size" lines up
	<white>pg down</>   Moves the cursor "screen size" lines down

<r> Press ESC to exit help. </r>
`

const (
	commonMappings = "<b>[H]:<darkgrey>Help</> <b>[Q]:<darkgrey>Quit</> <blue>|</> "
	keyMappings    = commonMappings +
		"<b>[F1]:<darkgrey>Sort</> <b>[F2]:<darkgrey>Toggle Show Containers</> <b>[F5]:<darkgrey>Refresh</> <b>[%]:<darkgrey>Filter</> <blue>|</> " +
		"<b>[m]:<darkgrey>Monitor mode</> <b>[2]:<darkgrey>Images</> <b>[3]:<darkgrey>Networks</> <b>[4]:<darkgrey>Nodes</> <b>[5]:<darkgrey>Services</> <b>[6]:<darkgrey>Stacks</> <blue>|</> <b>[Enter]:<darkgrey>Commands</></>"

	monitorMapping = commonMappings +
		"<b>[m]:<darkgrey>Monitor mode</> <b>[1]:<darkgrey>Containers</> <b>[2]:<darkgrey>Images</> <b>[3]:<darkgrey>Networks</> <b>[4]:<darkgrey>Nodes</> <b>[5]:<darkgrey>Services</> <b>[6]:<darkgrey>Stacks</>"

	swarmMapping = commonMappings +
		"<b>[m]:<darkgrey>Monitor mode</> <b>[1]:<darkgrey>Containers</> <b>[2]:<darkgrey>Images</> <b>[3]:<darkgrey>Networks</> <b>[4]:<darkgrey>Nodes</> <b>[5]:<darkgrey>Services</> <b>[6]:<darkgrey>Stacks</>"

	imagesKeyMappings = commonMappings +
		"<b>[F1]:<darkgrey>Sort</> <b>[F5]:<darkgrey>Refresh</> <blue>|</> " +
		"<b>[1]:<darkgrey>Containers</> <b>[3]:<darkgrey>Networks</> <b>[4]:<darkgrey>Nodes</> <b>[5]:<darkgrey>Services</> <b>[6]:<darkgrey>Stacks</> <blue>|</>" +
		"<b>[Ctrl+D]:<darkgrey>Remove Dangling</> <b>[Ctrl+E]:<darkgrey>Remove</> <b>[Ctrl+F]:<darkgrey>Force Remove</> <b>[I]:<darkgrey>History</>"

	networkKeyMappings = commonMappings +
		"<b>[F1]:<darkgrey>Sort</> <b>[F5]:<darkgrey>Refresh</> <blue>|</> " +
		"<b>[1]:<darkgrey>Containers</> <b>[2]:<darkgrey>Images</> <b>[4]:<darkgrey>Nodes</> <b>[5]:<darkgrey>Services</> <b>[6]:<darkgrey>Stacks</> <blue>|</>" +
		"<b>[Ctrl+E]:<darkgrey>Remove</> <b>[Enter]:<darkgrey>Inspect</>"

	diskUsageKeyMappings = commonMappings +
		"<b>[1]:<darkgrey>Containers</> <b>[2]:<darkgrey>Images</><blue>|</> <b>[3]:<darkgrey>Networks</> <b>[4]:<darkgrey>Nodes</> <b>[5]:<darkgrey>Services</> <b>[6]:<darkgrey>Stacks</> <blue>|</>" +
		"<b>[p]:<darkgrey>Prune</>"

	serviceKeyMappings = swarmMapping + "<blue>|</> <b>[F1]:<darkgrey>Sort</> <b>[F5]:<darkgrey>Refresh</> <b>[%]:<darkgrey>Filter</> <blue>|</> <b>[l]:<darkgrey>Service logs</> <b>[Ctrl+R]:<darkgrey>Remove Service</> <b>[Ctrl+S]:<darkgrey>Scale service</><b>[Ctrl+K]:<darkgrey>Update service</>"

	stackKeyMappings = swarmMapping + "<blue>|</> <b>[F1]:<darkgrey>Sort</> <b>[F5]:<darkgrey>Refresh</> <b>[%]:<darkgrey>Filter</> <blue>|</> <b>[Ctrl+R]:<darkgrey>Remove Stack</>"

	nodeKeyMappings = swarmMapping + " <blue>|</> <b>[F1]:<darkgrey>Sort</> <b>[F5]:<darkgrey>Refresh</> <blue>|</>  <b>[Enter]:<darkgrey>Show Node Tasks</> <b>[Ctrl+A]:<darkgrey>Set Availability</>"

	commandsMenuBar = "<b>[Esc]:<darkgrey>Back</> <b>[Up]:<darkgrey>Cursor Up</> <b>[Down]:<darkgrey>Cursor Down</> <b>[Enter]:<darkgrey>Execute Command</>"
)
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"github.com/moriyoshi/ik"
	"github.com/moriyoshi/ik/plugins"
	"log"
	"os"
	"path"
	"errors"
)

func usage() {
	fmt.Fprintf(os.Stderr, "Usage of %s:\n", os.Args[0])
	flag.PrintDefaults()
	os.Exit(0)
}

func configureScoreboards(logger *log.Logger, registry *MultiFactoryRegistry, engine ik.Engine, config *ik.Config) error {
       for _, v := range config.Root.Elems {
	       switch v.Name {
		case "scoreboard":
			type_ := v.Attrs["type"]
			scoreboardFactory := registry.LookupScoreboardFactory(type_)
			if scoreboardFactory == nil {
				return errors.New("Could not find scoreboard factory: " + type_)
			}
			scoreboard, err := scoreboardFactory.New(engine, registry, v)
			if err != nil {
				return err
			}
			err = engine.Launch(scoreboard)
			if err != nil {
				return err
			}
			logger.Printf("Scoreboard plugin loaded: %s", scoreboardFactory.Name())
		}
	}
	return nil
}

func main() {
	logger := log.New(os.Stdout, "[ik] ", log.Lmicroseconds)

	var config_file string
	var help bool
	flag.StringVar(&config_file, "c", "/etc/fluent/fluent.conf", "config file path (default: /etc/fluent/fluent.conf)")
	flag.BoolVar(&help, "h", false, "show help")
	flag.Parse()

	if help || config_file == "" {
		usage()
	}

	dir, file := path.Split(config_file)
	opener := ik.DefaultOpener(dir)
	config, err := ik.ParseConfig(opener, file)
	if err != nil {
		println(err.Error())
		return
	}

	scorekeeper := ik.NewScorekeeper(logger)

	registry := NewMultiFactoryRegistry(scorekeeper)

	for _, _plugin := range plugins.GetPlugins() {
		switch plugin := _plugin.(type) {
		case ik.InputFactory:
			registry.RegisterInputFactory(plugin)
		case ik.OutputFactory:
			registry.RegisterOutputFactory(plugin)
		}
	}

	registry.RegisterScoreboardFactory(&HTMLHTTPScoreboardFactory {})

	router := ik.NewFluentRouter()
	engine := ik.NewEngine(logger, scorekeeper, router)
	defer engine.Dispose()

	err = ik.NewFluentConfigurer(logger, registry, registry, router).Configure(engine, config)
	if err != nil {
		println(err.Error())
		return
	}
	err = configureScoreboards(logger, registry, engine, config)
	if err != nil {
		println(err.Error())
		return
	}
	engine.Start()
}

// vim: sts=4 sw=4 ts=4 noet
<commit_msg>255 is better<commit_after>package main

import (
	"flag"
	"fmt"
	"github.com/moriyoshi/ik"
	"github.com/moriyoshi/ik/plugins"
	"log"
	"os"
	"path"
	"errors"
)

func usage() {
	fmt.Fprintf(os.Stderr, "Usage of %s:\n", os.Args[0])
	flag.PrintDefaults()
	os.Exit(255)
}

func configureScoreboards(logger *log.Logger, registry *MultiFactoryRegistry, engine ik.Engine, config *ik.Config) error {
       for _, v := range config.Root.Elems {
	       switch v.Name {
		case "scoreboard":
			type_ := v.Attrs["type"]
			scoreboardFactory := registry.LookupScoreboardFactory(type_)
			if scoreboardFactory == nil {
				return errors.New("Could not find scoreboard factory: " + type_)
			}
			scoreboard, err := scoreboardFactory.New(engine, registry, v)
			if err != nil {
				return err
			}
			err = engine.Launch(scoreboard)
			if err != nil {
				return err
			}
			logger.Printf("Scoreboard plugin loaded: %s", scoreboardFactory.Name())
		}
	}
	return nil
}

func main() {
	logger := log.New(os.Stdout, "[ik] ", log.Lmicroseconds)

	var config_file string
	var help bool
	flag.StringVar(&config_file, "c", "/etc/fluent/fluent.conf", "config file path (default: /etc/fluent/fluent.conf)")
	flag.BoolVar(&help, "h", false, "show help")
	flag.Parse()

	if help || config_file == "" {
		usage()
	}

	dir, file := path.Split(config_file)
	opener := ik.DefaultOpener(dir)
	config, err := ik.ParseConfig(opener, file)
	if err != nil {
		println(err.Error())
		return
	}

	scorekeeper := ik.NewScorekeeper(logger)

	registry := NewMultiFactoryRegistry(scorekeeper)

	for _, _plugin := range plugins.GetPlugins() {
		switch plugin := _plugin.(type) {
		case ik.InputFactory:
			registry.RegisterInputFactory(plugin)
		case ik.OutputFactory:
			registry.RegisterOutputFactory(plugin)
		}
	}

	registry.RegisterScoreboardFactory(&HTMLHTTPScoreboardFactory {})

	router := ik.NewFluentRouter()
	engine := ik.NewEngine(logger, scorekeeper, router)
	defer engine.Dispose()

	err = ik.NewFluentConfigurer(logger, registry, registry, router).Configure(engine, config)
	if err != nil {
		println(err.Error())
		return
	}
	err = configureScoreboards(logger, registry, engine, config)
	if err != nil {
		println(err.Error())
		return
	}
	engine.Start()
}

// vim: sts=4 sw=4 ts=4 noet
<|endoftext|>


<commit_before><commit_msg>add bindings for getSampleRate and getNumChannels (#6)<commit_after><|endoftext|>


<commit_before><commit_msg>cmd/gopherbot: don't consider reopened issues in close-cherry-pick task<commit_after><|endoftext|>


<commit_before><commit_msg>Abort verify at first hash mismatch.<commit_after><|endoftext|>


<commit_before><commit_msg>docker: validate received parts<commit_after><|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"fmt"
	"os"
	"os/exec"
	"strings"
	"time"

	"github.com/aws/aws-lambda-go/lambda"
	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/session"
	"github.com/aws/aws-sdk-go/service/s3"
)

// ClusterInfo holds information about a cluster.
type ClusterInfo struct {
	KopsBucket      string `json:"kops_bucket"`
	PachydermBucket string `json:"pachyderm_bucket"`
	Created         string `json:"created"`
}

// KopsBucket is the s3 bucket used by kops.
const KopsBucket = "pachyderm-travis-state-store-v1"

// MaxClusterTime is the maximimum time a cluster can be up.
const MaxClusterTime = time.Hour * 4

// HandleRequest handles the deletion of old clusters.
func HandleRequest() (string, error) {
	cmd := exec.Command("/bin/sh", "-c", "export PATH=$PATH:/var/task; kops --state=s3://"+KopsBucket+" get clusters | tail -n+2 | awk '{print $1}'")
	cmd.Stderr = os.Stderr
	out, err := cmd.Output()
	if err != nil {
		return "Failed to get clusters", err
	}
	names := strings.Split(string(out), "\n")
	names = names[:len(names)-1]
	svc := s3.New(session.New())
	for _, name := range names {
		infoObject, err := svc.GetObject(
			&s3.GetObjectInput{
				Bucket: aws.String(KopsBucket),
				Key:    aws.String(name + "-info.json"),
			})
		if err != nil {
			return "Failed to get info file", err
		}
		var info ClusterInfo
		if err := json.NewDecoder(infoObject.Body).Decode(&info); err != nil {
			return "Failed to decode info file", err
		}
		createTime, err := time.Parse(time.UnixDate, info.Created)
		if err != nil {
			return "Failed to parse create time", err
		}
		// Cluster has been up for too long
		if createTime.Add(MaxClusterTime).Before(time.Now()) {
			fmt.Println("Cluster being deleted: " + name)
			cmd := exec.Command("/bin/sh", "-c", "export PATH=$PATH:/var/task; kops --state=s3://"+KopsBucket+" delete cluster --name="+name+" --yes")
			cmd.Stderr = os.Stderr
			if err := cmd.Run(); err != nil {
				return "Failed to delete cluster", err
			}
			_, err := svc.DeleteBucket(
				&s3.DeleteBucketInput{
					Bucket: aws.String(info.PachydermBucket),
				})
			if err != nil {
				return "Failed to delete pachyderm bucket", err
			}
			_, err = svc.DeleteObject(
				&s3.DeleteObjectInput{
					Bucket: aws.String(KopsBucket),
					Key:    aws.String(name + "-info.json"),
				})
			if err != nil {
				return "Failed to delete info file", err
			}
		}
	}
	return "Succeeded", nil
}

func main() {
	lambda.Start(HandleRequest)
}
<commit_msg>Change from sh to bash and modified deleted clusters reporting<commit_after>package main

import (
	"encoding/json"
	"os"
	"os/exec"
	"strings"
	"time"

	"github.com/aws/aws-lambda-go/lambda"
	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/session"
	"github.com/aws/aws-sdk-go/service/s3"
)

// ClusterInfo holds information about a cluster.
type ClusterInfo struct {
	KopsBucket      string `json:"kops_bucket"`
	PachydermBucket string `json:"pachyderm_bucket"`
	Created         string `json:"created"`
}

// KopsBucket is the s3 bucket used by kops.
const KopsBucket = "pachyderm-travis-state-store-v1"

// MaxClusterTime is the maximimum time a cluster can be up.
const MaxClusterTime = time.Hour * 4

// HandleRequest handles the deletion of old clusters.
func HandleRequest() (string, error) {
	cmd := exec.Command("/bin/bash", "-c", "export PATH=$PATH:/var/task; kops --state=s3://"+KopsBucket+" get clusters | tail -n+2 | awk '{print $1}'")
	cmd.Stderr = os.Stderr
	out, err := cmd.Output()
	if err != nil {
		return "Failed to get clusters", err
	}
	names := strings.Split(string(out), "\n")
	names = names[:len(names)-1]
	var deleted string
	svc := s3.New(session.New())
	for _, name := range names {
		infoObject, err := svc.GetObject(
			&s3.GetObjectInput{
				Bucket: aws.String(KopsBucket),
				Key:    aws.String(name + "-info.json"),
			})
		if err != nil {
			return "Failed to get info file", err
		}
		var info ClusterInfo
		if err := json.NewDecoder(infoObject.Body).Decode(&info); err != nil {
			return "Failed to decode info file", err
		}
		createTime, err := time.Parse(time.UnixDate, info.Created)
		if err != nil {
			return "Failed to parse create time", err
		}
		// Cluster has been up for too long
		if createTime.Add(MaxClusterTime).Before(time.Now()) {
			deleted += name + ", "
			cmd := exec.Command("/bin/bash", "-c", "export PATH=$PATH:/var/task; kops --state=s3://"+KopsBucket+" delete cluster --name="+name+" --yes")
			cmd.Stderr = os.Stderr
			if err := cmd.Run(); err != nil {
				return "Failed to delete cluster", err
			}
			_, err := svc.DeleteBucket(
				&s3.DeleteBucketInput{
					Bucket: aws.String(info.PachydermBucket),
				})
			if err != nil {
				return "Failed to delete pachyderm bucket", err
			}
			_, err = svc.DeleteObject(
				&s3.DeleteObjectInput{
					Bucket: aws.String(KopsBucket),
					Key:    aws.String(name + "-info.json"),
				})
			if err != nil {
				return "Failed to delete info file", err
			}
		}
	}
	if len(deleted) <= 0 {
		return "No clusters deleted", nil
	}
	deleted = "Clusters deleted: " + deleted
	tmp := []rune(deleted)
	return string(tmp[:len(tmp)-2]), nil
}

func main() {
	lambda.Start(HandleRequest)
}
<|endoftext|>


<commit_before>//This package provides all chatroom-functionality
package chat

import(
	"gofire/user"
	"gofire/message"
	"code.google.com/p/go.net/websocket"
)

type Connection struct{
	User *user.User //User in connection
	conn *websocket.Conn
	send chan *command.Command
}

type ChatRoom struct{
	Name string //The name of the chatroom, also the id of a chatroom
	register chan *Connection
	unregister chan *Connection
	registeredConnections map[*Connection]bool
}
<commit_msg>added Run method for chatroom<commit_after>//This package provides all chatroom-functionality
package chat

import(
	"gofire/user"
	"gofire/message"
	"code.google.com/p/go.net/websocket"
)

type Connection struct{
	User *user.User //User in connection
	conn *websocket.Conn
	send chan *command.Command
}

type ChatRoom struct{
	Name string //The name of the chatroom, also the id of a chatroom
	register chan *Connection
	unregister chan *Connection
	registeredConnections map[*Connection]bool
}

func (chatroom *ChatRoom) Run(){
	for{
		select{
		case c <- chatroom.register:
			chatroom.registeredConnections[c] = true
			//TODO  code for broadcasting login
			break
		case c <- chatroom.unregister:
			delete(chatroom.registeredConnections, c)
			//TODO code for broadcastin logout
			break
		}
	}
}
<|endoftext|>


<commit_before>package pages

import (
	"bytes"
	"html/template"
	"io/ioutil"
	"log"
	"net/http"

	"github.com/gorilla/sessions"
)

// BaseAddress is the base URL of the website
var BaseAddress = "http://upframe.xyz"

// RenderHTML renders an HTML response and send it to the client based on the
// choosen templates
func RenderHTML(w http.ResponseWriter, s *sessions.Session, data interface{}, templates ...string) (int, error) {
	templates = append(templates, "base")
	var tpl *template.Template

	// For each template, add it to the the tpl variable
	for i := range templates {
		// Get the template from the assets
		page, err := ioutil.ReadFile("templates/" + templates[i] + ".tmpl")

		// Check if there is some error. If so, the template doesn't exist
		if err != nil {
			log.Print(err)
			return http.StatusInternalServerError, err
		}

		// If it's the first iteration, creates a new template and add the
		// functions map
		if i == 0 {
			tpl, err = template.New(templates[i]).Parse(string(page))
		} else {
			tpl, err = tpl.Parse(string(page))
		}

		if err != nil {
			log.Print(err)
			return http.StatusInternalServerError, err
		}
	}

	buf := &bytes.Buffer{}
	err := tpl.Execute(buf, buildPageData(s, data))

	if err != nil {
		return http.StatusInternalServerError, err
	}

	w.Header().Set("Content-Type", "text/html; charset=utf-8")
	_, err = buf.WriteTo(w)
	return http.StatusOK, nil
}

// IsLoggedIn checks if an user is logged in
func IsLoggedIn(s *sessions.Session) bool {
	switch s.Values["IsLoggedIn"].(type) {
	case bool:
		return s.Values["IsLoggedIn"].(bool)
	}

	return false
}

// IsAdmin checks if an user is admin
func IsAdmin(s *sessions.Session) bool {
	switch s.Values["IsAdmin"].(type) {
	case bool:
		return s.Values["IsAdmin"].(bool)
	}

	return false
}

// Redirect redirects the user to a page
func Redirect(w http.ResponseWriter, r *http.Request, path string) (int, error) {
	http.Redirect(w, r, path, http.StatusTemporaryRedirect)
	return http.StatusOK, nil
}

// page is the type that contains the information that goes into the page
type page struct {
	IsLoggedIn bool
	Data       interface{}
	Session    struct {
		FirstName string
		LastName  string
		IsAdmin   bool
	}
}

// buildPageData builds a page variable based on session and data
func buildPageData(s *sessions.Session, data interface{}) *page {
	p := &page{
		IsLoggedIn: IsLoggedIn(s),
		Data:       data,
	}

	if p.IsLoggedIn {
		p.Session.FirstName = s.Values["FirstName"].(string)
		p.Session.LastName = s.Values["LastName"].(string)
		p.Session.IsAdmin = s.Values["IsAdmin"].(bool)
	}

	return p
}
<commit_msg>little change on pages<commit_after>package pages

import (
	"bytes"
	"html/template"
	"io/ioutil"
	"log"
	"net/http"

	"github.com/gorilla/sessions"
)

// BaseAddress is the base URL of the website
var BaseAddress = "http://upframe.xyz"

// page is the type that contains the information that goes into the page
type page struct {
	IsLoggedIn bool
	Data       interface{}
	Session    struct {
		FirstName string
		LastName  string
		IsAdmin   bool
	}
}

// RenderHTML renders an HTML response and send it to the client based on the
// choosen templates
func RenderHTML(w http.ResponseWriter, s *sessions.Session, data interface{}, templates ...string) (int, error) {
	templates = append(templates, "base")
	var tpl *template.Template

	// For each template, add it to the the tpl variable
	for i := range templates {
		// Get the template from the assets
		page, err := ioutil.ReadFile("templates/" + templates[i] + ".tmpl")

		// Check if there is some error. If so, the template doesn't exist
		if err != nil {
			log.Print(err)
			return http.StatusInternalServerError, err
		}

		// If it's the first iteration, creates a new template and add the
		// functions map
		if i == 0 {
			tpl, err = template.New(templates[i]).Parse(string(page))
		} else {
			tpl, err = tpl.Parse(string(page))
		}

		if err != nil {
			log.Print(err)
			return http.StatusInternalServerError, err
		}
	}

	p := &page{
		IsLoggedIn: IsLoggedIn(s),
		Data:       data,
	}

	if p.IsLoggedIn {
		p.Session.FirstName = s.Values["FirstName"].(string)
		p.Session.LastName = s.Values["LastName"].(string)
		p.Session.IsAdmin = s.Values["IsAdmin"].(bool)
	}

	buf := &bytes.Buffer{}
	err := tpl.Execute(buf, p)

	if err != nil {
		return http.StatusInternalServerError, err
	}

	w.Header().Set("Content-Type", "text/html; charset=utf-8")
	_, err = buf.WriteTo(w)
	return http.StatusOK, nil
}

// IsLoggedIn checks if an user is logged in
func IsLoggedIn(s *sessions.Session) bool {
	switch s.Values["IsLoggedIn"].(type) {
	case bool:
		return s.Values["IsLoggedIn"].(bool)
	}

	return false
}

// IsAdmin checks if an user is admin
func IsAdmin(s *sessions.Session) bool {
	switch s.Values["IsAdmin"].(type) {
	case bool:
		return s.Values["IsAdmin"].(bool)
	}

	return false
}

// Redirect redirects the user to a page
func Redirect(w http.ResponseWriter, r *http.Request, path string) (int, error) {
	http.Redirect(w, r, path, http.StatusTemporaryRedirect)
	return http.StatusOK, nil
}
<|endoftext|>


<commit_before>package ordnance

import (
	"errors"
	"math/rand"
	"sync"
	"time"

	"github.com/dysolution/sleepwalker"
)

import "github.com/Sirupsen/logrus"

var log *logrus.Logger

func init() {
}

type Armory struct {
	Weapons map[string]ArmedWeapon `json:"weapons"`
}

func NewArmory(logger *logrus.Logger) Armory {
	log = logger
	weapons := make(map[string]ArmedWeapon)
	return Armory{Weapons: weapons}
}

func (a *Armory) NewBomb(client sleepwalker.RESTClient, name string, method string, url string, payload sleepwalker.RESTObject) {
	var payloadPresent bool
	if payload != nil {
		payloadPresent = true
	} else {
		payloadPresent = false
	}
	log.WithFields(logrus.Fields{
		"name":             name,
		"method":           method,
		"path":             url,
		"payload_included": payloadPresent,
	}).Debugf("Armory.NewBomb")

	a.Weapons[name] = Bomb{
		Client:  client,
		Name:    name,
		Method:  method,
		URL:     url,
		Payload: payload,
	}
}

func (a *Armory) NewMissile(client sleepwalker.RESTClient, name string, op func(sleepwalker.RESTClient) (sleepwalker.Result, error)) {
	log.WithFields(logrus.Fields{
		"name":      name,
		"operation": op,
	}).Debugf("Armory.NewMissile")
	a.Weapons[name] = Missile{
		Client:    client,
		Name:      name,
		Operation: op,
	}
}

func (a Armory) GetWeapon(name string) ArmedWeapon {
	desc := "Armory.GetWeapon"
	if a.Weapons[name] == nil {
		err := errors.New("undefined weapon")
		log.WithFields(logrus.Fields{
			"name":  name,
			"error": err,
		}).Error(desc)
		return nil
	}
	log.WithFields(logrus.Fields{
		"name": name,
	}).Debug(desc)
	return a.Weapons[name]
}

func (a *Armory) GetRandomWeaponNames(count int) []string {
	desc := "Armory.GetRandomWeaponNames"
	var names []string
	for i := count; i > 0; i-- {
		names = append(names, a.getRandomWeapon())
	}

	log.WithFields(logrus.Fields{
		"weapons": names,
	}).Debug(desc)
	return names
}

func (a *Armory) getRandomWeapon() string {
	rand.Seed(time.Now().UTC().UnixNano())
	m := sync.Mutex{}

	// build a slice of weapon names
	var weapons []string
	m.Lock()
	for name, _ := range a.Weapons {
		weapons = append(weapons, name)
	}
	m.Unlock()

	return weapons[rand.Intn(len(weapons))]
}

func (a Armory) GetArsenal(names ...string) Arsenal {
	var arsenal Arsenal
	for _, name := range names {
		arsenal = append(arsenal, a.GetWeapon(name))
	}
	return arsenal
}
<commit_msg>docs: obey the linter<commit_after>package ordnance

import (
	"errors"
	"math/rand"
	"sync"
	"time"

	"github.com/dysolution/sleepwalker"
)

import "github.com/Sirupsen/logrus"

var log *logrus.Logger

func init() {
}

// An Armory maintains a collection of weapons that can be retrieved by name
// or at random.
type Armory struct {
	Weapons map[string]ArmedWeapon `json:"weapons"`
}

// NewArmory allows the logger to be specified.
func NewArmory(logger *logrus.Logger) Armory {
	log = logger
	weapons := make(map[string]ArmedWeapon)
	return Armory{Weapons: weapons}
}

func (a *Armory) NewBomb(client sleepwalker.RESTClient, name string, method string, url string, payload sleepwalker.RESTObject) {
	var payloadPresent bool
	if payload != nil {
		payloadPresent = true
	} else {
		payloadPresent = false
	}
	log.WithFields(logrus.Fields{
		"name":             name,
		"method":           method,
		"path":             url,
		"payload_included": payloadPresent,
	}).Debugf("Armory.NewBomb")

	a.Weapons[name] = Bomb{
		Client:  client,
		Name:    name,
		Method:  method,
		URL:     url,
		Payload: payload,
	}
}

func (a *Armory) NewMissile(client sleepwalker.RESTClient, name string, op func(sleepwalker.RESTClient) (sleepwalker.Result, error)) {
	log.WithFields(logrus.Fields{
		"name":      name,
		"operation": op,
	}).Debugf("Armory.NewMissile")
	a.Weapons[name] = Missile{
		Client:    client,
		Name:      name,
		Operation: op,
	}
}

func (a Armory) GetWeapon(name string) ArmedWeapon {
	desc := "Armory.GetWeapon"
	if a.Weapons[name] == nil {
		err := errors.New("undefined weapon")
		log.WithFields(logrus.Fields{
			"name":  name,
			"error": err,
		}).Error(desc)
		return nil
	}
	log.WithFields(logrus.Fields{
		"name": name,
	}).Debug(desc)
	return a.Weapons[name]
}

func (a *Armory) GetRandomWeaponNames(count int) []string {
	desc := "Armory.GetRandomWeaponNames"
	var names []string
	for i := count; i > 0; i-- {
		names = append(names, a.getRandomWeapon())
	}

	log.WithFields(logrus.Fields{
		"weapons": names,
	}).Debug(desc)
	return names
}

func (a *Armory) getRandomWeapon() string {
	rand.Seed(time.Now().UTC().UnixNano())
	m := sync.Mutex{}

	// build a slice of weapon names
	var weapons []string
	m.Lock()
	for name, _ := range a.Weapons {
		weapons = append(weapons, name)
	}
	m.Unlock()

	return weapons[rand.Intn(len(weapons))]
}

func (a Armory) GetArsenal(names ...string) Arsenal {
	var arsenal Arsenal
	for _, name := range names {
		arsenal = append(arsenal, a.GetWeapon(name))
	}
	return arsenal
}
<|endoftext|>


<commit_before>package main

import (
	"../nsq"
	"../util"
	"bytes"
	"io"
	"log"
	"net"
	"net/http"
	"strings"
)

import _ "net/http/pprof"

func HttpServer(listener net.Listener) {
	log.Printf("HTTP: listening on %s", listener.Addr().String())
	handler := http.NewServeMux()
	handler.HandleFunc("/ping", pingHandler)
	handler.HandleFunc("/put", putHandler)
	handler.HandleFunc("/mput", mputHandler)
	handler.HandleFunc("/stats", statsHandler)
	handler.HandleFunc("/empty", emptyHandler)
	server := &http.Server{Handler: handler}
	err := server.Serve(listener)
	// theres no direct way to detect this error because it is not exposed
	if err != nil && !strings.Contains(err.Error(), "use of closed network connection") {
		log.Printf("ERROR: http.Serve() - %s", err.Error())
	}
}

func pingHandler(w http.ResponseWriter, req *http.Request) {
	w.Header().Set("Content-Length", "2")
	io.WriteString(w, "OK")
}

func putHandler(w http.ResponseWriter, req *http.Request) {
	reqParams, err := util.NewReqParams(req)
	if err != nil {
		log.Printf("ERROR: failed to parse request params - %s", err.Error())
		w.Write(util.ApiResponse(500, "INVALID_REQUEST", nil))
		return
	}

	topicName, err := reqParams.Query("topic")
	if err != nil {
		w.Write(util.ApiResponse(500, "MISSING_ARG_TOPIC", nil))
		return
	}

	if len(topicName) > nsq.MaxNameLength {
		w.Write(util.ApiResponse(500, "INVALID_ARG_TOPIC", nil))
		return
	}

	topic := nsqd.GetTopic(topicName)
	msg := nsq.NewMessage(<-nsqd.idChan, reqParams.Body)
	topic.PutMessage(msg)

	w.Header().Set("Content-Length", "2")
	io.WriteString(w, "OK")
}

func mputHandler(w http.ResponseWriter, req *http.Request) {
	reqParams, err := util.NewReqParams(req)
	if err != nil {
		log.Printf("ERROR: failed to parse request params - %s", err.Error())
		w.Write(util.ApiResponse(500, "INVALID_REQUEST", nil))
		return
	}

	topicName, err := reqParams.Query("topic")
	if err != nil {
		w.Write(util.ApiResponse(500, "MISSING_ARG_TOPIC", nil))
		return
	}

	if len(topicName) > nsq.MaxNameLength {
		w.Write(util.ApiResponse(500, "INVALID_ARG_TOPIC", nil))
		return
	}

	topic := nsqd.GetTopic(topicName)
	for _, block := range bytes.Split(reqParams.Body, []byte("\n")) {
		if len(block) != 0 {
			msg := nsq.NewMessage(<-nsqd.idChan, block)
			topic.PutMessage(msg)
		}
	}

	w.Header().Set("Content-Length", "2")
	io.WriteString(w, "OK")
}

func emptyHandler(w http.ResponseWriter, req *http.Request) {
	reqParams, err := util.NewReqParams(req)
	if err != nil {
		log.Printf("ERROR: failed to parse request params - %s", err.Error())
		w.Write(util.ApiResponse(500, "INVALID_REQUEST", nil))
		return
	}

	topicName, err := reqParams.Query("topic")
	if err != nil {
		w.Write(util.ApiResponse(500, "MISSING_ARG_TOPIC", nil))
		return
	}

	if len(topicName) > nsq.MaxNameLength {
		w.Write(util.ApiResponse(500, "INVALID_ARG_TOPIC", nil))
		return
	}

	channelName, err := reqParams.Query("channel")
	if err != nil {
		w.Write(util.ApiResponse(500, "MISSING_ARG_CHANNEL", nil))
		return
	}

	if len(topicName) > nsq.MaxNameLength {
		w.Write(util.ApiResponse(500, "INVALID_ARG_CHANNEL", nil))
		return
	}

	topic := nsqd.GetTopic(topicName)
	channel := topic.GetChannel(channelName)
	err = EmptyQueue(channel)
	if err != nil {
		w.Write(util.ApiResponse(500, "INTERNAL_ERROR", nil))
		return
	}

	w.Header().Set("Content-Length", "2")
	io.WriteString(w, "OK")
}
<commit_msg>add /mem_profile HTTP endpoint to dump memory profile to disk<commit_after>package main

import (
	"../nsq"
	"../util"
	"bytes"
	"io"
	"log"
	"net"
	"net/http"
	"os"
	"runtime/pprof"
	"strings"
)

import _ "net/http/pprof"

func HttpServer(listener net.Listener) {
	log.Printf("HTTP: listening on %s", listener.Addr().String())
	handler := http.NewServeMux()
	handler.HandleFunc("/ping", pingHandler)
	handler.HandleFunc("/put", putHandler)
	handler.HandleFunc("/mput", mputHandler)
	handler.HandleFunc("/stats", statsHandler)
	handler.HandleFunc("/empty", emptyHandler)
	handler.HandleFunc("/mem_profile", memProfileHandler)
	server := &http.Server{Handler: handler}
	err := server.Serve(listener)
	// theres no direct way to detect this error because it is not exposed
	if err != nil && !strings.Contains(err.Error(), "use of closed network connection") {
		log.Printf("ERROR: http.Serve() - %s", err.Error())
	}
}

func memProfileHandler(w http.ResponseWriter, req *http.Request) {
	log.Printf("MEMORY Profiling Enabled")
	f, err := os.Create("nsqd.mprof")
	if err != nil {
		log.Fatal(err)
	}
	pprof.WriteHeapProfile(f)
	f.Close()

	w.Header().Set("Content-Length", "2")
	io.WriteString(w, "OK")
}

func pingHandler(w http.ResponseWriter, req *http.Request) {
	w.Header().Set("Content-Length", "2")
	io.WriteString(w, "OK")
}

func putHandler(w http.ResponseWriter, req *http.Request) {
	reqParams, err := util.NewReqParams(req)
	if err != nil {
		log.Printf("ERROR: failed to parse request params - %s", err.Error())
		w.Write(util.ApiResponse(500, "INVALID_REQUEST", nil))
		return
	}

	topicName, err := reqParams.Query("topic")
	if err != nil {
		w.Write(util.ApiResponse(500, "MISSING_ARG_TOPIC", nil))
		return
	}

	if len(topicName) > nsq.MaxNameLength {
		w.Write(util.ApiResponse(500, "INVALID_ARG_TOPIC", nil))
		return
	}

	topic := nsqd.GetTopic(topicName)
	msg := nsq.NewMessage(<-nsqd.idChan, reqParams.Body)
	topic.PutMessage(msg)

	w.Header().Set("Content-Length", "2")
	io.WriteString(w, "OK")
}

func mputHandler(w http.ResponseWriter, req *http.Request) {
	reqParams, err := util.NewReqParams(req)
	if err != nil {
		log.Printf("ERROR: failed to parse request params - %s", err.Error())
		w.Write(util.ApiResponse(500, "INVALID_REQUEST", nil))
		return
	}

	topicName, err := reqParams.Query("topic")
	if err != nil {
		w.Write(util.ApiResponse(500, "MISSING_ARG_TOPIC", nil))
		return
	}

	if len(topicName) > nsq.MaxNameLength {
		w.Write(util.ApiResponse(500, "INVALID_ARG_TOPIC", nil))
		return
	}

	topic := nsqd.GetTopic(topicName)
	for _, block := range bytes.Split(reqParams.Body, []byte("\n")) {
		if len(block) != 0 {
			msg := nsq.NewMessage(<-nsqd.idChan, block)
			topic.PutMessage(msg)
		}
	}

	w.Header().Set("Content-Length", "2")
	io.WriteString(w, "OK")
}

func emptyHandler(w http.ResponseWriter, req *http.Request) {
	reqParams, err := util.NewReqParams(req)
	if err != nil {
		log.Printf("ERROR: failed to parse request params - %s", err.Error())
		w.Write(util.ApiResponse(500, "INVALID_REQUEST", nil))
		return
	}

	topicName, err := reqParams.Query("topic")
	if err != nil {
		w.Write(util.ApiResponse(500, "MISSING_ARG_TOPIC", nil))
		return
	}

	if len(topicName) > nsq.MaxNameLength {
		w.Write(util.ApiResponse(500, "INVALID_ARG_TOPIC", nil))
		return
	}

	channelName, err := reqParams.Query("channel")
	if err != nil {
		w.Write(util.ApiResponse(500, "MISSING_ARG_CHANNEL", nil))
		return
	}

	if len(topicName) > nsq.MaxNameLength {
		w.Write(util.ApiResponse(500, "INVALID_ARG_CHANNEL", nil))
		return
	}

	topic := nsqd.GetTopic(topicName)
	channel := topic.GetChannel(channelName)
	err = EmptyQueue(channel)
	if err != nil {
		w.Write(util.ApiResponse(500, "INTERNAL_ERROR", nil))
		return
	}

	w.Header().Set("Content-Length", "2")
	io.WriteString(w, "OK")
}
<|endoftext|>


<commit_before>package num2word

import "math"

// how many digit's groups to process
const GROUPS_NUMBER int = 4

var _smallNumbers = []string{
	"zero", "one", "two", "three", "four",
	"five", "six", "seven", "eight", "nine",
	"ten", "eleven", "twelve", "thirteen", "fourteen",
	"fifteen", "sixteen", "seventeen", "eighteen", "nineteen",
}
var _tens = []string{
	"", "", "twenty", "thirty", "forty", "fifty",
	"sixty", "seventy", "eighty", "ninety",
}
var _scaleNumbers = []string{
	"", "thousand", "million", "billion",
}

type digitGroup int

// Number2Word converts number into the words representation.
func Convert(number int) (combined string) {
	// Zero rule
	if number == 0 {
		return _smallNumbers[0]
	}

	// Divide into three-digits group
	var groups [GROUPS_NUMBER]digitGroup
	positive := math.Abs(float64(number))

	// Form three-digit groups
	for i := 0; i < GROUPS_NUMBER; i++ {
		groups[i] = digitGroup(math.Mod(positive, 1000))
		positive /= 1000
	}

	var textGroup [GROUPS_NUMBER]string
	for i := 0; i < GROUPS_NUMBER; i++ {
		textGroup[i] = digitGroup2Text(groups[i])
	}
	combined = textGroup[0]
	appendAnd := groups[0] > 0 && groups[0] < 100

	for i := 1; i < GROUPS_NUMBER; i++ {
		if groups[i] != 0 {
			prefix := textGroup[i] + " " + _scaleNumbers[i]

			if len(combined) != 0 {
				if appendAnd {
					prefix += " and "
				} else {
					prefix += ", "
				}
			}

			appendAnd = false

			combined = prefix + combined
		}
	}

	if number < 0 {
		combined = "minus " + combined
	}

	return combined
}

func intMod(x, y int) int {
	return int(math.Mod(float64(x), float64(y)))
}

func digitGroup2Text(group digitGroup) (ret string) {
	hundreds := group / 100
	tensUnits := intMod(int(group), 100)

	if hundreds != 0 {
		ret += _smallNumbers[hundreds] + " hundred"

		if tensUnits != 0 {
			ret += " and "
		}
	}

	tens := tensUnits / 10
	units := intMod(tensUnits, 10)

	if tens >= 2 {
		ret += _tens[tens]

		if units != 0 {
			ret += " " + _smallNumbers[units]
		}
	} else if tensUnits != 0 {
		ret += _smallNumbers[tensUnits]
	}

	return
}
<commit_msg>Decapitalized constants<commit_after>package num2word

import "math"

// how many digit's groups to process
const groups_number int = 4

var _smallNumbers = []string{
	"zero", "one", "two", "three", "four",
	"five", "six", "seven", "eight", "nine",
	"ten", "eleven", "twelve", "thirteen", "fourteen",
	"fifteen", "sixteen", "seventeen", "eighteen", "nineteen",
}
var _tens = []string{
	"", "", "twenty", "thirty", "forty", "fifty",
	"sixty", "seventy", "eighty", "ninety",
}
var _scaleNumbers = []string{
	"", "thousand", "million", "billion",
}

type digitGroup int

// Number2Word converts number into the words representation.
func Convert(number int) (combined string) {
	// Zero rule
	if number == 0 {
		return _smallNumbers[0]
	}

	// Divide into three-digits group
	var groups [groups_number]digitGroup
	positive := math.Abs(float64(number))

	// Form three-digit groups
	for i := 0; i < groups_number; i++ {
		groups[i] = digitGroup(math.Mod(positive, 1000))
		positive /= 1000
	}

	var textGroup [groups_number]string
	for i := 0; i < groups_number; i++ {
		textGroup[i] = digitGroup2Text(groups[i])
	}
	combined = textGroup[0]
	appendAnd := groups[0] > 0 && groups[0] < 100

	for i := 1; i < groups_number; i++ {
		if groups[i] != 0 {
			prefix := textGroup[i] + " " + _scaleNumbers[i]

			if len(combined) != 0 {
				if appendAnd {
					prefix += " and "
				} else {
					prefix += ", "
				}
			}

			appendAnd = false

			combined = prefix + combined
		}
	}

	if number < 0 {
		combined = "minus " + combined
	}

	return combined
}

func intMod(x, y int) int {
	return int(math.Mod(float64(x), float64(y)))
}

func digitGroup2Text(group digitGroup) (ret string) {
	hundreds := group / 100
	tensUnits := intMod(int(group), 100)

	if hundreds != 0 {
		ret += _smallNumbers[hundreds] + " hundred"

		if tensUnits != 0 {
			ret += " and "
		}
	}

	tens := tensUnits / 10
	units := intMod(tensUnits, 10)

	if tens >= 2 {
		ret += _tens[tens]

		if units != 0 {
			ret += " " + _smallNumbers[units]
		}
	} else if tensUnits != 0 {
		ret += _smallNumbers[tensUnits]
	}

	return
}
<|endoftext|>


<commit_before>package gofakeit

// Language will return a random language
func Language() string {
	return getRandValue(globalFaker.Rand, []string{"language", "long"})
}

// LanguageAbbreviation will return a random language abbreviation
func LanguageAbbreviation() string {
	return getRandValue(globalFaker.Rand, []string{"language", "short"})
}

// ProgrammingLanguage will return a random programming language
func ProgrammingLanguage() string {
	return getRandValue(globalFaker.Rand, []string{"language", "programming"})
}

// ProgrammingLanguageBest will return a random programming language
func ProgrammingLanguageBest() string {
	return "Go"
}

func addLanguagesLookup() {
	AddFuncLookup("language", Info{
		Display:     "Language",
		Category:    "language",
		Description: "Random language",
		Example:     "Kazakh",
		Output:      "string",
		Call: func(m *map[string][]string, info *Info) (interface{}, error) {
			return Language(), nil
		},
	})

	AddFuncLookup("languageabbreviation", Info{
		Display:     "Language Abbreviation",
		Category:    "language",
		Description: "Random abbreviated language",
		Example:     "kk",
		Output:      "string",
		Call: func(m *map[string][]string, info *Info) (interface{}, error) {
			return LanguageAbbreviation(), nil
		},
	})

	AddFuncLookup("programminglanguage", Info{
		Display:     "Programming Language",
		Category:    "language",
		Description: "Random programming language",
		Example:     "Go",
		Output:      "string",
		Call: func(m *map[string][]string, info *Info) (interface{}, error) {
			return ProgrammingLanguage(), nil
		},
	})
}
<commit_msg>languages - added languages methods<commit_after>package gofakeit

import rand "math/rand"

// Language will return a random language
func Language() string { return language(globalFaker.Rand) }

// Language will return a random language
func (f *Faker) Language() string { return language(f.Rand) }

func language(r *rand.Rand) string { return getRandValue(r, []string{"language", "long"}) }

// LanguageAbbreviation will return a random language abbreviation
func LanguageAbbreviation() string { return languageAbbreviation(globalFaker.Rand) }

// LanguageAbbreviation will return a random language abbreviation
func (f *Faker) LanguageAbbreviation() string { return languageAbbreviation(f.Rand) }

func languageAbbreviation(r *rand.Rand) string { return getRandValue(r, []string{"language", "short"}) }

// ProgrammingLanguage will return a random programming language
func ProgrammingLanguage() string { return programmingLanguage(globalFaker.Rand) }

// ProgrammingLanguage will return a random programming language
func (f *Faker) ProgrammingLanguage() string { return programmingLanguage(f.Rand) }

func programmingLanguage(r *rand.Rand) string {
	return getRandValue(r, []string{"language", "programming"})
}

// ProgrammingLanguageBest will return a random programming language
func ProgrammingLanguageBest() string { return programmingLanguage(globalFaker.Rand) }

// ProgrammingLanguageBest will return a random programming language
func (f *Faker) ProgrammingLanguageBest() string { return programmingLanguage(f.Rand) }

// ProgrammingLanguageBest will return a random programming language
func programmingLanguageBest() string { return "Go" }

func addLanguagesLookup() {
	AddFuncLookup("language", Info{
		Display:     "Language",
		Category:    "language",
		Description: "Random language",
		Example:     "Kazakh",
		Output:      "string",
		Call: func(m *map[string][]string, info *Info) (interface{}, error) {
			return Language(), nil
		},
	})

	AddFuncLookup("languageabbreviation", Info{
		Display:     "Language Abbreviation",
		Category:    "language",
		Description: "Random abbreviated language",
		Example:     "kk",
		Output:      "string",
		Call: func(m *map[string][]string, info *Info) (interface{}, error) {
			return LanguageAbbreviation(), nil
		},
	})

	AddFuncLookup("programminglanguage", Info{
		Display:     "Programming Language",
		Category:    "language",
		Description: "Random programming language",
		Example:     "Go",
		Output:      "string",
		Call: func(m *map[string][]string, info *Info) (interface{}, error) {
			return ProgrammingLanguage(), nil
		},
	})
}
<|endoftext|>


<commit_before>package tests

import (
	"io/ioutil"
	"os"
	"os/exec"
)

type cleanFunc func()

func noop() {}

func createFixtureRepo() (string, cleanFunc, error) {
	dir, err := ioutil.TempDir("/tmp", "monocle_test_")
	if err != nil {
		return "", noop, err
	}

	if err = exec.Command("git", "init", dir).Run(); err != nil {
		return "", noop, err
	}

	return dir, func() {
		exec.Command("rm", "-rf", dir).Run()
	}, nil
}

func seedSimpleCommit(dir string, err error) error {
	if err != nil {
		return err
	}

	cwd, err := os.Getwd()
	if err != nil {
		return err
	}
	defer os.Chdir(cwd)

	if err = os.Chdir(dir); err != nil {
		return err
	}

	if err = ioutil.WriteFile("a", []byte{'a', 'b', 'c', '\n'}, 0644); err != nil {
		return err
	}

	if err = exec.Command("git", "add", ".").Run(); err != nil {
		return err
	}

	if err = exec.Command("git", "commit", "-am", "First commit!").Run(); err != nil {
		return err
	}

	return nil
}
<commit_msg>Show command stdout and stderr together for exec.Command<commit_after>package tests

import (
	"fmt"
	"io/ioutil"
	"os"
	"os/exec"
)

type cleanFunc func()

func noop() {}

func createFixtureRepo() (string, cleanFunc, error) {
	dir, err := ioutil.TempDir("/tmp", "monocle_test_")
	if err != nil {
		return "", noop, err
	}

	if output, err := exec.Command("git", "init", dir).CombinedOutput(); err != nil {
		return "", noop, fmt.Errorf("err: %s\nerr: %s", output, err.Error())
	}

	return dir, func() {
		exec.Command("rm", "-rf", dir).Run()
	}, nil
}

func seedSimpleCommit(dir string, err error) error {
	if err != nil {
		return err
	}

	cwd, err := os.Getwd()
	if err != nil {
		return err
	}
	defer os.Chdir(cwd)

	if err = os.Chdir(dir); err != nil {
		return err
	}

	if err = ioutil.WriteFile("a", []byte{'a', 'b', 'c', '\n'}, 0644); err != nil {
		return err
	}

	if output, err := exec.Command("git", "add", ".").CombinedOutput(); err != nil {
		return fmt.Errorf("err: %s\nerr: %s", output, err.Error())
	}

	if output, err := exec.Command("git", "commit", "-am", "First commit!").CombinedOutput(); err != nil {
		return fmt.Errorf("err: %s\nerr: %s", output, err.Error())
	}

	return nil
}
<|endoftext|>


<commit_before><commit_msg>Fix unreachable code<commit_after><|endoftext|>


<commit_before>package readline

import "io"

type Operation struct {
	cfg     *Config
	t       *Terminal
	buf     *RuneBuffer
	outchan chan []rune

	*opHistory
	*opSearch
	*opCompleter
}

type wrapWriter struct {
	r      *Operation
	t      *Terminal
	target io.Writer
}

func (w *wrapWriter) Write(b []byte) (int, error) {
	buf := w.r.buf
	buf.Clean()
	n, err := w.target.Write(b)
	if w.t.IsReading() {
		w.r.buf.Refresh(nil)
	}
	if w.r.IsSearchMode() {
		w.r.SearchRefresh(-1)
	}
	if w.r.IsInCompleteMode() {
		w.r.CompleteRefresh()
	}
	return n, err
}

func NewOperation(t *Terminal, cfg *Config) *Operation {
	op := &Operation{
		cfg:       cfg,
		t:         t,
		buf:       NewRuneBuffer(t, cfg.Prompt),
		outchan:   make(chan []rune),
		opHistory: newOpHistory(cfg.HistoryFile),
	}
	op.opSearch = newOpSearch(op.buf.w, op.buf, op.opHistory)
	op.opCompleter = newOpCompleter(op.buf.w, op)
	go op.ioloop()
	return op
}

func (o *Operation) ioloop() {
	for {
		keepInSearchMode := false
		keepInCompleteMode := false
		r := o.t.ReadRune()

		if o.IsInCompleteSelectMode() {
			keepInCompleteMode = o.HandleCompleteSelect(r)
			if keepInCompleteMode {
				continue
			}

			o.buf.Refresh(nil)
			switch r {
			case CharEnter, CharCtrlJ:
				o.UpdateHistory(o.buf.Runes(), false)
				fallthrough
			case CharInterrupt:
				o.t.KickRead()
				fallthrough
			case CharCancel:
				continue
			}
		}

		switch r {
		case 'i':
			o.buf.Clean()
		case CharCancel:
			if o.IsSearchMode() {
				o.ExitSearchMode(true)
				o.buf.Refresh(nil)
			}
			if o.IsInCompleteMode() {
				o.ExitCompleteMode(true)
				o.buf.Refresh(nil)
			}
		case CharTab:
			if o.opCompleter == nil {
				break
			}
			o.OnComplete()
			keepInCompleteMode = true
		case CharBckSearch:
			o.SearchMode(S_DIR_BCK)
			keepInSearchMode = true
		case CharFwdSearch:
			o.SearchMode(S_DIR_FWD)
			keepInSearchMode = true
		case CharKill:
			o.buf.Kill()
			keepInCompleteMode = true
		case MetaNext:
			o.buf.MoveToNextWord()
		case CharTranspose:
			o.buf.Transpose()
		case MetaPrev:
			o.buf.MoveToPrevWord()
		case MetaDelete:
			o.buf.DeleteWord()
		case CharLineStart:
			o.buf.MoveToLineStart()
		case CharLineEnd:
			o.buf.MoveToLineEnd()
		case CharDelete:
			o.buf.Delete()
		case CharBackspace, CharCtrlH:
			if o.IsSearchMode() {
				o.SearchBackspace()
				keepInSearchMode = true
				break
			}

			if o.buf.Len() == 0 {
				break
			}
			o.buf.Backspace()
			if o.IsInCompleteMode() {
				o.OnComplete()
			}
		case MetaBackspace, CharCtrlW:
			o.buf.BackEscapeWord()
		case CharEnter, CharCtrlJ:
			if o.IsSearchMode() {
				o.ExitSearchMode(false)
			}
			o.buf.MoveToLineEnd()
			o.buf.WriteRune('\n')
			data := o.buf.Reset()
			data = data[:len(data)-1] // trim \n
			o.outchan <- data
			o.NewHistory(data)
		case CharBackward:
			o.buf.MoveBackward()
		case CharForward:
			o.buf.MoveForward()
		case CharPrev:
			buf := o.PrevHistory()
			if buf != nil {
				o.buf.Set(buf)
			}
		case CharNext:
			buf, ok := o.NextHistory()
			if ok {
				o.buf.Set(buf)
			}
		case CharInterrupt:
			if o.IsSearchMode() {
				o.t.KickRead()
				o.ExitSearchMode(true)
				break
			}
			if o.IsInCompleteMode() {
				o.t.KickRead()
				o.ExitCompleteMode(true)
				o.buf.Refresh(nil)
				break
			}
			o.buf.MoveToLineEnd()
			o.buf.Refresh(nil)
			o.buf.WriteString("^C\n")
			o.outchan <- nil
		default:
			if o.IsSearchMode() {
				o.SearchChar(r)
				keepInSearchMode = true
				break
			}
			o.buf.WriteRune(r)
			if o.IsInCompleteMode() {
				o.OnComplete()
				keepInCompleteMode = true
			}
		}
		if !keepInSearchMode && o.IsSearchMode() {
			o.ExitSearchMode(false)
			o.buf.Refresh(nil)
		} else if o.IsInCompleteMode() {
			if !keepInCompleteMode {
				o.ExitCompleteMode(false)
				o.buf.Refresh(nil)
			} else {
				o.buf.Refresh(nil)
				o.CompleteRefresh()
			}
		}
		if !o.IsSearchMode() {
			o.UpdateHistory(o.buf.Runes(), false)
		}
	}
}

func (o *Operation) Stderr() io.Writer {
	return &wrapWriter{target: o.cfg.Stderr, r: o, t: o.t}
}

func (o *Operation) Stdout() io.Writer {
	return &wrapWriter{target: o.cfg.Stdout, r: o, t: o.t}
}

func (o *Operation) String() (string, error) {
	r, err := o.Runes()
	if err != nil {
		return "", err
	}
	return string(r), nil
}

func (o *Operation) Runes() ([]rune, error) {
	o.buf.Refresh(nil) // print prompt
	o.t.KickRead()
	r := <-o.outchan
	if r == nil {
		return nil, io.EOF
	}
	return r, nil
}

func (o *Operation) Slice() ([]byte, error) {
	r, err := o.Runes()
	if err != nil {
		return nil, err
	}
	return []byte(string(r)), nil
}

func (o *Operation) Close() {
	o.opHistory.Close()
}
<commit_msg>remove test code<commit_after>package readline

import "io"

type Operation struct {
	cfg     *Config
	t       *Terminal
	buf     *RuneBuffer
	outchan chan []rune

	*opHistory
	*opSearch
	*opCompleter
}

type wrapWriter struct {
	r      *Operation
	t      *Terminal
	target io.Writer
}

func (w *wrapWriter) Write(b []byte) (int, error) {
	buf := w.r.buf
	buf.Clean()
	n, err := w.target.Write(b)
	if w.t.IsReading() {
		w.r.buf.Refresh(nil)
	}
	if w.r.IsSearchMode() {
		w.r.SearchRefresh(-1)
	}
	if w.r.IsInCompleteMode() {
		w.r.CompleteRefresh()
	}
	return n, err
}

func NewOperation(t *Terminal, cfg *Config) *Operation {
	op := &Operation{
		cfg:       cfg,
		t:         t,
		buf:       NewRuneBuffer(t, cfg.Prompt),
		outchan:   make(chan []rune),
		opHistory: newOpHistory(cfg.HistoryFile),
	}
	op.opSearch = newOpSearch(op.buf.w, op.buf, op.opHistory)
	op.opCompleter = newOpCompleter(op.buf.w, op)
	go op.ioloop()
	return op
}

func (o *Operation) ioloop() {
	for {
		keepInSearchMode := false
		keepInCompleteMode := false
		r := o.t.ReadRune()

		if o.IsInCompleteSelectMode() {
			keepInCompleteMode = o.HandleCompleteSelect(r)
			if keepInCompleteMode {
				continue
			}

			o.buf.Refresh(nil)
			switch r {
			case CharEnter, CharCtrlJ:
				o.UpdateHistory(o.buf.Runes(), false)
				fallthrough
			case CharInterrupt:
				o.t.KickRead()
				fallthrough
			case CharCancel:
				continue
			}
		}

		switch r {
		case CharCancel:
			if o.IsSearchMode() {
				o.ExitSearchMode(true)
				o.buf.Refresh(nil)
			}
			if o.IsInCompleteMode() {
				o.ExitCompleteMode(true)
				o.buf.Refresh(nil)
			}
		case CharTab:
			if o.opCompleter == nil {
				break
			}
			o.OnComplete()
			keepInCompleteMode = true
		case CharBckSearch:
			o.SearchMode(S_DIR_BCK)
			keepInSearchMode = true
		case CharFwdSearch:
			o.SearchMode(S_DIR_FWD)
			keepInSearchMode = true
		case CharKill:
			o.buf.Kill()
			keepInCompleteMode = true
		case MetaNext:
			o.buf.MoveToNextWord()
		case CharTranspose:
			o.buf.Transpose()
		case MetaPrev:
			o.buf.MoveToPrevWord()
		case MetaDelete:
			o.buf.DeleteWord()
		case CharLineStart:
			o.buf.MoveToLineStart()
		case CharLineEnd:
			o.buf.MoveToLineEnd()
		case CharDelete:
			o.buf.Delete()
		case CharBackspace, CharCtrlH:
			if o.IsSearchMode() {
				o.SearchBackspace()
				keepInSearchMode = true
				break
			}

			if o.buf.Len() == 0 {
				break
			}
			o.buf.Backspace()
			if o.IsInCompleteMode() {
				o.OnComplete()
			}
		case MetaBackspace, CharCtrlW:
			o.buf.BackEscapeWord()
		case CharEnter, CharCtrlJ:
			if o.IsSearchMode() {
				o.ExitSearchMode(false)
			}
			o.buf.MoveToLineEnd()
			o.buf.WriteRune('\n')
			data := o.buf.Reset()
			data = data[:len(data)-1] // trim \n
			o.outchan <- data
			o.NewHistory(data)
		case CharBackward:
			o.buf.MoveBackward()
		case CharForward:
			o.buf.MoveForward()
		case CharPrev:
			buf := o.PrevHistory()
			if buf != nil {
				o.buf.Set(buf)
			}
		case CharNext:
			buf, ok := o.NextHistory()
			if ok {
				o.buf.Set(buf)
			}
		case CharInterrupt:
			if o.IsSearchMode() {
				o.t.KickRead()
				o.ExitSearchMode(true)
				break
			}
			if o.IsInCompleteMode() {
				o.t.KickRead()
				o.ExitCompleteMode(true)
				o.buf.Refresh(nil)
				break
			}
			o.buf.MoveToLineEnd()
			o.buf.Refresh(nil)
			o.buf.WriteString("^C\n")
			o.outchan <- nil
		default:
			if o.IsSearchMode() {
				o.SearchChar(r)
				keepInSearchMode = true
				break
			}
			o.buf.WriteRune(r)
			if o.IsInCompleteMode() {
				o.OnComplete()
				keepInCompleteMode = true
			}
		}
		if !keepInSearchMode && o.IsSearchMode() {
			o.ExitSearchMode(false)
			o.buf.Refresh(nil)
		} else if o.IsInCompleteMode() {
			if !keepInCompleteMode {
				o.ExitCompleteMode(false)
				o.buf.Refresh(nil)
			} else {
				o.buf.Refresh(nil)
				o.CompleteRefresh()
			}
		}
		if !o.IsSearchMode() {
			o.UpdateHistory(o.buf.Runes(), false)
		}
	}
}

func (o *Operation) Stderr() io.Writer {
	return &wrapWriter{target: o.cfg.Stderr, r: o, t: o.t}
}

func (o *Operation) Stdout() io.Writer {
	return &wrapWriter{target: o.cfg.Stdout, r: o, t: o.t}
}

func (o *Operation) String() (string, error) {
	r, err := o.Runes()
	if err != nil {
		return "", err
	}
	return string(r), nil
}

func (o *Operation) Runes() ([]rune, error) {
	o.buf.Refresh(nil) // print prompt
	o.t.KickRead()
	r := <-o.outchan
	if r == nil {
		return nil, io.EOF
	}
	return r, nil
}

func (o *Operation) Slice() ([]byte, error) {
	r, err := o.Runes()
	if err != nil {
		return nil, err
	}
	return []byte(string(r)), nil
}

func (o *Operation) Close() {
	o.opHistory.Close()
}
<|endoftext|>


<commit_before>package lib

type VirtualMachineName struct {
	VirtualMachine string
	Group          string
	Account        string
}
type GroupName struct {
	Group   string
	Account string
}

type Disc struct {
	Label        string `json:"label"`
	StorageGrade string `json:"storage_grade"`
	Size         int    `json:"size"`

	Id               int    `json:"id"`
	VirtualMachineId int    `json:"virtual_machine_id"`
	StoragePool      string `json:"storage_pool"`
}

type ImageInstall struct {
	Distribution string `json:"distribution"`
	RootPassword string `json:"root_password"`
}

type IP struct {
	RDns string `json:"rdns"`

	// this cannot be set.
	Ip string `json:"ip"`
}

type NetworkInterface struct {
	Label string `json:"label"`

	Mac string `json:"mac"`

	// the following can't be set (or at least, so I'm assuming..)

	Id               int               `json:"id"`
	VlanNum          int               `json:"vlan_num"`
	Ips              []string          `json:"ips"`
	ExtraIps         map[string]string `json:"extra_ips"`
	VirtualMachineId int               `json:"virtual_machine_id"`
}

type User struct {
	Username       string `json:"username"`
	Email          string `json:"email"`
	AuthorizedKeys string `json:"authorized_keys"`
	Password       string `json:"password"`

	// "users can be created (using POST) without authentication. If the
	// request has no authentication, it will also accept an account_name
	// parameter and create an account at the same time."
	AccountName string `json:"account_name"`
}

// TODO(telyn): new fields (last_imaged_with and
type VirtualMachine struct {
	Autoreboot            bool   `json:"autoreboot_on"`
	CdromUrl              string `json:"cdrom_url"`
	Cores                 int    `json:"cores"`
	Memory                int    `json:"memory"`
	Name                  string `json:"name"`
	PowerOn               bool   `json:"power_on"`
	HardwareProfile       string `json:"hardware_profile"`
	HardwareProfileLocked bool   `json:"hardware_profile_locked"`
	GroupId               int    `json:"group_id"`

	// zone name can be set during creation but not changed
	ZoneName string `json:"zone_name"`

	// the following cannot be set
	Discs             []*Disc             `json:"discs"`
	Id                int                 `json:"id"`
	ManagementAddress string              `json:"management_address"`
	Deleted           bool                `json:"deleted"`
	Hostname          string              `json:"hostname"`
	Head              string              `json:"head"`
	NetworkInterfaces []*NetworkInterface `json:"network_interfaces"`
}

type VirtualMachineSpec struct {
	VirtualMachine VirtualMachine `json:"virtual_machine"`
	Discs          []Disc         `json:"discs"`
	Reimage        ImageInstall   `json:"reimage"`
}

type Group struct {
	Name string `json:name"`

	// the following cannot be set
	AccountId       int              `json:"account_id"`
	Id              int              `json:"id"`
	VirtualMachines []VirtualMachine `json:"virtual_machines"`
}

type Account struct {
	Name string `json:"name"`

	// the following cannot be set
	Id        int      `json:"id"`
	Suspended bool     `json:"suspended"`
	Groups    []*Group `json:"groups"`
}
<commit_msg>Fix typo in lib.Group<commit_after>package lib

type VirtualMachineName struct {
	VirtualMachine string
	Group          string
	Account        string
}
type GroupName struct {
	Group   string
	Account string
}

type Disc struct {
	Label        string `json:"label"`
	StorageGrade string `json:"storage_grade"`
	Size         int    `json:"size"`

	Id               int    `json:"id"`
	VirtualMachineId int    `json:"virtual_machine_id"`
	StoragePool      string `json:"storage_pool"`
}

type ImageInstall struct {
	Distribution string `json:"distribution"`
	RootPassword string `json:"root_password"`
}

type IP struct {
	RDns string `json:"rdns"`

	// this cannot be set.
	Ip string `json:"ip"`
}

type NetworkInterface struct {
	Label string `json:"label"`

	Mac string `json:"mac"`

	// the following can't be set (or at least, so I'm assuming..)

	Id               int               `json:"id"`
	VlanNum          int               `json:"vlan_num"`
	Ips              []string          `json:"ips"`
	ExtraIps         map[string]string `json:"extra_ips"`
	VirtualMachineId int               `json:"virtual_machine_id"`
}

type User struct {
	Username       string `json:"username"`
	Email          string `json:"email"`
	AuthorizedKeys string `json:"authorized_keys"`
	Password       string `json:"password"`

	// "users can be created (using POST) without authentication. If the
	// request has no authentication, it will also accept an account_name
	// parameter and create an account at the same time."
	AccountName string `json:"account_name"`
}

// TODO(telyn): new fields (last_imaged_with and
type VirtualMachine struct {
	Autoreboot            bool   `json:"autoreboot_on"`
	CdromUrl              string `json:"cdrom_url"`
	Cores                 int    `json:"cores"`
	Memory                int    `json:"memory"`
	Name                  string `json:"name"`
	PowerOn               bool   `json:"power_on"`
	HardwareProfile       string `json:"hardware_profile"`
	HardwareProfileLocked bool   `json:"hardware_profile_locked"`
	GroupId               int    `json:"group_id"`

	// zone name can be set during creation but not changed
	ZoneName string `json:"zone_name"`

	// the following cannot be set
	Discs             []*Disc             `json:"discs"`
	Id                int                 `json:"id"`
	ManagementAddress string              `json:"management_address"`
	Deleted           bool                `json:"deleted"`
	Hostname          string              `json:"hostname"`
	Head              string              `json:"head"`
	NetworkInterfaces []*NetworkInterface `json:"network_interfaces"`
}

type VirtualMachineSpec struct {
	VirtualMachine VirtualMachine `json:"virtual_machine"`
	Discs          []Disc         `json:"discs"`
	Reimage        ImageInstall   `json:"reimage"`
}

type Group struct {
	Name string `json:"name"`

	// the following cannot be set
	AccountId       int              `json:"account_id"`
	Id              int              `json:"id"`
	VirtualMachines []VirtualMachine `json:"virtual_machines"`
}

type Account struct {
	Name string `json:"name"`

	// the following cannot be set
	Id        int      `json:"id"`
	Suspended bool     `json:"suspended"`
	Groups    []*Group `json:"groups"`
}
<|endoftext|>


<commit_before>package snickers_test

import (
	"bytes"
	"encoding/json"
	"net/http"
	"net/http/httptest"

	"github.com/flavioribeiro/snickers/db"
	"github.com/flavioribeiro/snickers/rest"
	"github.com/flavioribeiro/snickers/types"
	"github.com/gorilla/mux"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
)

var _ = Describe("Rest API", func() {
	Context("/presets location", func() {
		var (
			response   *httptest.ResponseRecorder
			server     *mux.Router
			dbInstance db.DatabaseInterface
		)

		BeforeEach(func() {
			response = httptest.NewRecorder()
			server = rest.NewRouter()
			dbInstance, _ = db.GetDatabase()
			dbInstance.ClearDatabase()
		})

		It("GET should return application/json on its content type", func() {
			request, _ := http.NewRequest("GET", "/presets", nil)
			server.ServeHTTP(response, request)
			Expect(response.HeaderMap["Content-Type"][0]).To(Equal("application/json; charset=UTF-8"))
		})

		It("GET should return stored presets", func() {
			examplePreset1 := types.Preset{Name: "a"}
			examplePreset2 := types.Preset{Name: "b"}
			dbInstance.StorePreset(examplePreset1)
			dbInstance.StorePreset(examplePreset2)

			expected1, _ := json.Marshal(`[{"name":"a","video":{},"audio":{}},{"name":"b","video":{},"audio":{}}]`)
			expected2, _ := json.Marshal(`[{"name":"b","video":{},"audio":{}},{"name":"a","video":{},"audio":{}}]`)

			request, _ := http.NewRequest("GET", "/presets", nil)
			server.ServeHTTP(response, request)
			responseBody, _ := json.Marshal(response.Body.String())

			Expect(response.Code).To(Equal(http.StatusOK))
			Expect(responseBody).To(SatisfyAny(Equal(expected1), Equal(expected2)))
		})

		It("POST should save a new preset", func() {
			preset := []byte(`{"name": "storedPreset", "video": {},"audio": {}}`)
			request, _ := http.NewRequest("POST", "/presets", bytes.NewBuffer(preset))
			server.ServeHTTP(response, request)

			presets, _ := dbInstance.GetPresets()
			Expect(response.Code).To(Equal(http.StatusOK))
			Expect(response.HeaderMap["Content-Type"][0]).To(Equal("application/json; charset=UTF-8"))
			Expect(len(presets)).To(Equal(1))
		})

		It("POST with malformed preset should return bad request", func() {
			preset := []byte(`{"neime: "badPreset}}`)
			request, _ := http.NewRequest("POST", "/presets", bytes.NewBuffer(preset))
			server.ServeHTTP(response, request)

			Expect(response.Code).To(Equal(http.StatusBadRequest))
			Expect(response.HeaderMap["Content-Type"][0]).To(Equal("application/json; charset=UTF-8"))
		})

		It("PUT with a new preset should update the preset", func() {
			dbInstance.StorePreset(types.Preset{Name: "examplePreset"})
			preset := []byte(`{"name":"examplePreset","Description": "new description","video": {},"audio": {}}`)

			request, _ := http.NewRequest("PUT", "/presets", bytes.NewBuffer(preset))
			server.ServeHTTP(response, request)

			presets, _ := dbInstance.GetPresets()
			newPreset := presets[0]
			Expect(response.Code).To(Equal(http.StatusOK))
			Expect(response.HeaderMap["Content-Type"][0]).To(Equal("application/json; charset=UTF-8"))
			Expect(newPreset.Description).To(Equal("new description"))
		})

		It("PUT with malformed preset should return bad request", func() {
			dbInstance.StorePreset(types.Preset{Name: "examplePreset"})
			preset := []byte(`{"name":"examplePreset","Description: "new description","video": {},"audio": {}}`)

			request, _ := http.NewRequest("PUT", "/presets", bytes.NewBuffer(preset))
			server.ServeHTTP(response, request)

			Expect(response.Code).To(Equal(http.StatusBadRequest))
			Expect(response.HeaderMap["Content-Type"][0]).To(Equal("application/json; charset=UTF-8"))
		})

		It("GET for a given preset should return preset details", func() {
			examplePreset := types.Preset{
				Name:         "examplePreset",
				Description:  "This is an example of preset",
				Container:    "mp4",
				Profile:      "high",
				ProfileLevel: "3.1",
				RateControl:  "VBR",
				Video: types.VideoPreset{
					Width:         "720",
					Height:        "1080",
					Codec:         "h264",
					Bitrate:       "10000",
					GopSize:       "90",
					GopMode:       "fixed",
					InterlaceMode: "progressive",
				},
				Audio: types.AudioPreset{
					Codec:   "aac",
					Bitrate: "64000",
				},
			}
			dbInstance.StorePreset(examplePreset)
			expected, _ := json.Marshal(examplePreset)

			request, _ := http.NewRequest("GET", "/presets/examplePreset", nil)
			server.ServeHTTP(response, request)

			Expect(response.Code).To(Equal(http.StatusOK))
			Expect(response.HeaderMap["Content-Type"][0]).To(Equal("application/json; charset=UTF-8"))
			Expect(response.Body.String()).To(Equal(string(expected)))
		})
	})
})
<commit_msg>db/rest: ensure we're triggering an error when trying to get a preset that doesn't exists<commit_after>package snickers_test

import (
	"bytes"
	"encoding/json"
	"net/http"
	"net/http/httptest"

	"github.com/flavioribeiro/snickers/db"
	"github.com/flavioribeiro/snickers/rest"
	"github.com/flavioribeiro/snickers/types"
	"github.com/gorilla/mux"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
)

var _ = Describe("Rest API", func() {
	Context("/presets location", func() {
		var (
			response   *httptest.ResponseRecorder
			server     *mux.Router
			dbInstance db.DatabaseInterface
		)

		BeforeEach(func() {
			response = httptest.NewRecorder()
			server = rest.NewRouter()
			dbInstance, _ = db.GetDatabase()
			dbInstance.ClearDatabase()
		})

		It("GET should return application/json on its content type", func() {
			request, _ := http.NewRequest("GET", "/presets", nil)
			server.ServeHTTP(response, request)
			Expect(response.HeaderMap["Content-Type"][0]).To(Equal("application/json; charset=UTF-8"))
		})

		It("GET should return stored presets", func() {
			examplePreset1 := types.Preset{Name: "a"}
			examplePreset2 := types.Preset{Name: "b"}
			dbInstance.StorePreset(examplePreset1)
			dbInstance.StorePreset(examplePreset2)

			expected1, _ := json.Marshal(`[{"name":"a","video":{},"audio":{}},{"name":"b","video":{},"audio":{}}]`)
			expected2, _ := json.Marshal(`[{"name":"b","video":{},"audio":{}},{"name":"a","video":{},"audio":{}}]`)

			request, _ := http.NewRequest("GET", "/presets", nil)
			server.ServeHTTP(response, request)
			responseBody, _ := json.Marshal(response.Body.String())

			Expect(response.Code).To(Equal(http.StatusOK))
			Expect(responseBody).To(SatisfyAny(Equal(expected1), Equal(expected2)))
		})

		It("POST should save a new preset", func() {
			preset := []byte(`{"name": "storedPreset", "video": {},"audio": {}}`)
			request, _ := http.NewRequest("POST", "/presets", bytes.NewBuffer(preset))
			server.ServeHTTP(response, request)

			presets, _ := dbInstance.GetPresets()
			Expect(response.Code).To(Equal(http.StatusOK))
			Expect(response.HeaderMap["Content-Type"][0]).To(Equal("application/json; charset=UTF-8"))
			Expect(len(presets)).To(Equal(1))
		})

		It("POST with malformed preset should return bad request", func() {
			preset := []byte(`{"neime: "badPreset}}`)
			request, _ := http.NewRequest("POST", "/presets", bytes.NewBuffer(preset))
			server.ServeHTTP(response, request)

			Expect(response.Code).To(Equal(http.StatusBadRequest))
			Expect(response.HeaderMap["Content-Type"][0]).To(Equal("application/json; charset=UTF-8"))
		})

		It("PUT with a new preset should update the preset", func() {
			dbInstance.StorePreset(types.Preset{Name: "examplePreset"})
			preset := []byte(`{"name":"examplePreset","Description": "new description","video": {},"audio": {}}`)

			request, _ := http.NewRequest("PUT", "/presets", bytes.NewBuffer(preset))
			server.ServeHTTP(response, request)

			presets, _ := dbInstance.GetPresets()
			newPreset := presets[0]
			Expect(response.Code).To(Equal(http.StatusOK))
			Expect(response.HeaderMap["Content-Type"][0]).To(Equal("application/json; charset=UTF-8"))
			Expect(newPreset.Description).To(Equal("new description"))
		})

		It("PUT with malformed preset should return bad request", func() {
			dbInstance.StorePreset(types.Preset{Name: "examplePreset"})
			preset := []byte(`{"name":"examplePreset","Description: "new description","video": {},"audio": {}}`)

			request, _ := http.NewRequest("PUT", "/presets", bytes.NewBuffer(preset))
			server.ServeHTTP(response, request)

			Expect(response.Code).To(Equal(http.StatusBadRequest))
			Expect(response.HeaderMap["Content-Type"][0]).To(Equal("application/json; charset=UTF-8"))
		})

		It("GET for a given preset should return preset details", func() {
			examplePreset := types.Preset{
				Name:         "examplePreset",
				Description:  "This is an example of preset",
				Container:    "mp4",
				Profile:      "high",
				ProfileLevel: "3.1",
				RateControl:  "VBR",
				Video: types.VideoPreset{
					Width:         "720",
					Height:        "1080",
					Codec:         "h264",
					Bitrate:       "10000",
					GopSize:       "90",
					GopMode:       "fixed",
					InterlaceMode: "progressive",
				},
				Audio: types.AudioPreset{
					Codec:   "aac",
					Bitrate: "64000",
				},
			}
			dbInstance.StorePreset(examplePreset)
			expected, _ := json.Marshal(examplePreset)

			request, _ := http.NewRequest("GET", "/presets/examplePreset", nil)
			server.ServeHTTP(response, request)

			Expect(response.Code).To(Equal(http.StatusOK))
			Expect(response.HeaderMap["Content-Type"][0]).To(Equal("application/json; charset=UTF-8"))
			Expect(response.Body.String()).To(Equal(string(expected)))
		})

		It("GET to /presets/presetName should return BadRequest if the preset doesn't exist", func() {
			request, _ := http.NewRequest("GET", "/presets/yoyoyo", nil)
			server.ServeHTTP(response, request)
			expected, _ := json.Marshal(`{"error": "retrieving preset: preset not found"}`)
			responseBody, _ := json.Marshal(string(response.Body.String()))
			Expect(responseBody).To(Equal(expected))
			Expect(response.Code).To(Equal(http.StatusBadRequest))
			Expect(response.HeaderMap["Content-Type"][0]).To(Equal("application/json; charset=UTF-8"))
		})

	})
})
<|endoftext|>


<commit_before>package db

import (
	"bufio"
	"database/sql"
	"fmt"
	"time"

	"io"

	"github.com/lib/pq"
	_ "github.com/lib/pq"
	"github.com/syou6162/go-active-learning/lib/example"
	"github.com/syou6162/go-active-learning/lib/util"
	"github.com/syou6162/go-active-learning/lib/util/file"
)

func CreateDBConnection() (*sql.DB, error) {
	host := util.GetEnv("POSTGRES_HOST", "localhost")
	dbUser := util.GetEnv("DB_USER", "nobody")
	dbPassword := util.GetEnv("DB_PASSWORD", "nobody")
	dbName := util.GetEnv("DB_NAME", "go-active-learning")
	return sql.Open("postgres", fmt.Sprintf("host=%s user=%s password=%s dbname=%s sslmode=disable", host, dbUser, dbPassword, dbName))
}

func InsertOrUpdateExample(db *sql.DB, e *example.Example) (sql.Result, error) {
	var label example.LabelType
	now := time.Now()

	url := e.FinalUrl
	if url == "" {
		url = e.Url
	}

	err := db.QueryRow(`SELECT label FROM example WHERE url = $1`, url).Scan(&label)
	switch {
	case err == sql.ErrNoRows:
		return db.Exec(`INSERT INTO example (url, label, created_at, updated_at) VALUES ($1, $2, $3, $4)`, url, e.Label, now, now)
	case err != nil:
		return nil, err
	default:
		if label != e.Label {
			return db.Exec(`UPDATE example SET label = $2, updated_at = $3 WHERE url = $1 `, url, e.Label, now)
		}
		return nil, nil
	}
}

func InsertExampleFromScanner(db *sql.DB, scanner *bufio.Scanner) (*example.Example, error) {
	line := scanner.Text()
	e, err := file.ParseLine(line)
	if err != nil {
		return nil, err
	}
	_, err = InsertOrUpdateExample(db, e)
	if err != nil {
		return nil, err
	}
	return e, nil
}

func InsertExamplesFromReader(r io.Reader) error {
	scanner := bufio.NewScanner(r)

	conn, err := CreateDBConnection()
	if err != nil {
		return err
	}
	defer conn.Close()

	for scanner.Scan() {
		_, err := InsertExampleFromScanner(conn, scanner)
		if err != nil {
			return err
		}
	}
	if err := scanner.Err(); err != nil {
		return err
	}
	return nil
}

func readExamples(db *sql.DB, query string, args ...interface{}) ([]*example.Example, error) {
	rows, err := db.Query(query, args...)
	if err != nil {
		return nil, err
	}
	defer rows.Close()

	var examples example.Examples

	for rows.Next() {
		var label example.LabelType
		var url string
		if err := rows.Scan(&url, &label); err != nil {
			return nil, err
		}
		e := example.Example{Url: url, Label: label}
		examples = append(examples, &e)
	}

	if err := rows.Err(); err != nil {
		return nil, err
	}

	return examples, nil
}

func ReadExamples(db *sql.DB) ([]*example.Example, error) {
	query := `SELECT url, label FROM example;`
	return readExamples(db, query)
}

func ReadRecentExamples(db *sql.DB, from time.Time) ([]*example.Example, error) {
	query := `SELECT url, label FROM example WHERE created_at > $1 ORDER BY updated_at DESC;`
	return readExamples(db, query, from)
}

func ReadLabeledExamples(db *sql.DB, limit int) ([]*example.Example, error) {
	query := `SELECT url, label FROM example WHERE label != 0 ORDER BY updated_at DESC LIMIT $1;`
	return readExamples(db, query, limit)
}

func ReadUnabeledExamples(db *sql.DB, limit int) ([]*example.Example, error) {
	query := `SELECT url, label FROM example WHERE label = 0 ORDER BY created_at DESC LIMIT $1;`
	return readExamples(db, query, limit)
}

func SearchExamplesByUlrs(db *sql.DB, urls []string) (example.Examples, error) {
	// ref: https://godoc.org/github.com/lib/pq#Array
	query := `SELECT url, label FROM example WHERE url = ANY($1);`
	return readExamples(db, query, pq.Array(urls))
}

func DeleteAllExamples(db *sql.DB) (sql.Result, error) {
	return db.Exec(`DELETE FROM example`)
}
<commit_msg>util的な関数を追加<commit_after>package db

import (
	"bufio"
	"database/sql"
	"fmt"
	"time"

	"io"

	"github.com/lib/pq"
	_ "github.com/lib/pq"
	"github.com/syou6162/go-active-learning/lib/example"
	"github.com/syou6162/go-active-learning/lib/util"
	"github.com/syou6162/go-active-learning/lib/util/file"
)

func CreateDBConnection() (*sql.DB, error) {
	host := util.GetEnv("POSTGRES_HOST", "localhost")
	dbUser := util.GetEnv("DB_USER", "nobody")
	dbPassword := util.GetEnv("DB_PASSWORD", "nobody")
	dbName := util.GetEnv("DB_NAME", "go-active-learning")
	return sql.Open("postgres", fmt.Sprintf("host=%s user=%s password=%s dbname=%s sslmode=disable", host, dbUser, dbPassword, dbName))
}

func InsertOrUpdateExample(db *sql.DB, e *example.Example) (sql.Result, error) {
	var label example.LabelType
	now := time.Now()

	url := e.FinalUrl
	if url == "" {
		url = e.Url
	}

	err := db.QueryRow(`SELECT label FROM example WHERE url = $1`, url).Scan(&label)
	switch {
	case err == sql.ErrNoRows:
		return db.Exec(`INSERT INTO example (url, label, created_at, updated_at) VALUES ($1, $2, $3, $4)`, url, e.Label, now, now)
	case err != nil:
		return nil, err
	default:
		if label != e.Label {
			return db.Exec(`UPDATE example SET label = $2, updated_at = $3 WHERE url = $1 `, url, e.Label, now)
		}
		return nil, nil
	}
}

func InsertExampleFromScanner(db *sql.DB, scanner *bufio.Scanner) (*example.Example, error) {
	line := scanner.Text()
	e, err := file.ParseLine(line)
	if err != nil {
		return nil, err
	}
	_, err = InsertOrUpdateExample(db, e)
	if err != nil {
		return nil, err
	}
	return e, nil
}

func InsertExamplesFromReader(r io.Reader) error {
	scanner := bufio.NewScanner(r)

	conn, err := CreateDBConnection()
	if err != nil {
		return err
	}
	defer conn.Close()

	for scanner.Scan() {
		_, err := InsertExampleFromScanner(conn, scanner)
		if err != nil {
			return err
		}
	}
	if err := scanner.Err(); err != nil {
		return err
	}
	return nil
}

func readExamples(db *sql.DB, query string, args ...interface{}) ([]*example.Example, error) {
	rows, err := db.Query(query, args...)
	if err != nil {
		return nil, err
	}
	defer rows.Close()

	var examples example.Examples

	for rows.Next() {
		var label example.LabelType
		var url string
		if err := rows.Scan(&url, &label); err != nil {
			return nil, err
		}
		e := example.Example{Url: url, Label: label}
		examples = append(examples, &e)
	}

	if err := rows.Err(); err != nil {
		return nil, err
	}

	return examples, nil
}

func ReadExamples(db *sql.DB) ([]*example.Example, error) {
	query := `SELECT url, label FROM example;`
	return readExamples(db, query)
}

func ReadRecentExamples(db *sql.DB, from time.Time) ([]*example.Example, error) {
	query := `SELECT url, label FROM example WHERE created_at > $1 ORDER BY updated_at DESC;`
	return readExamples(db, query, from)
}

func ReadExamplesByLabel(db *sql.DB, label example.LabelType, limit int) ([]*example.Example, error) {
	query := `SELECT url, label FROM example WHERE label = $1 ORDER BY updated_at DESC LIMIT $2;`
	return readExamples(db, query, label, limit)
}

func ReadLabeledExamples(db *sql.DB, limit int) ([]*example.Example, error) {
	query := `SELECT url, label FROM example WHERE label != 0 ORDER BY updated_at DESC LIMIT $1;`
	return readExamples(db, query, limit)
}

func ReadPositiveExamples(db *sql.DB, limit int) ([]*example.Example, error) {
	return ReadExamplesByLabel(db, example.POSITIVE, limit)
}

func ReadNegativeExamples(db *sql.DB, limit int) ([]*example.Example, error) {
	return ReadExamplesByLabel(db, example.NEGATIVE, limit)
}

func ReadUnlabeledExamples(db *sql.DB, limit int) ([]*example.Example, error) {
	return ReadExamplesByLabel(db, example.UNLABELED, limit)
}

func SearchExamplesByUlrs(db *sql.DB, urls []string) (example.Examples, error) {
	// ref: https://godoc.org/github.com/lib/pq#Array
	query := `SELECT url, label FROM example WHERE url = ANY($1);`
	return readExamples(db, query, pq.Array(urls))
}

func DeleteAllExamples(db *sql.DB) (sql.Result, error) {
	return db.Exec(`DELETE FROM example`)
}
<|endoftext|>