<commit_before>/*
Copyright 2014 The Kubernetes Authors.

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

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

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

package cmd

import (
	"fmt"
	"io"
	"time"

	"github.com/spf13/cobra"

	"k8s.io/kubernetes/pkg/api"
	"k8s.io/kubernetes/pkg/api/errors"
	"k8s.io/kubernetes/pkg/api/meta"
	"k8s.io/kubernetes/pkg/apis/meta/v1/unstructured"
	"k8s.io/kubernetes/pkg/kubectl"
	"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
	cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
	"k8s.io/kubernetes/pkg/kubectl/resource"
	"k8s.io/kubernetes/pkg/util/wait"
)

var (
	delete_long = templates.LongDesc(`
		Delete resources by filenames, stdin, resources and names, or by resources and label selector.

		JSON and YAML formats are accepted. Only one type of the arguments may be specified: filenames,
		resources and names, or resources and label selector.

		Some resources, such as pods, support graceful deletion. These resources define a default period
		before they are forcibly terminated (the grace period) but you may override that value with
		the --grace-period flag, or pass --now to set a grace-period of 1. Because these resources often
		represent entities in the cluster, deletion may not be acknowledged immediately. If the node
		hosting a pod is down or cannot reach the API server, termination may take significantly longer
		than the grace period. To force delete a resource,	you must pass a grace	period of 0 and specify
		the --force flag.

		IMPORTANT: Force deleting pods does not wait for confirmation that the pod's processes have been
		terminated, which can leave those processes running until the node detects the deletion and
		completes graceful deletion. If your processes use shared storage or talk to a remote API and
		depend on the name of the pod to identify themselves, force deleting those pods may result in
		multiple processes running on different machines using the same identification which may lead
		to data corruption or inconsistency. Only force delete pods when you are sure the pod is
		terminated, or if your application can tolerate multiple copies of the same pod running at once.
		Also, if you force delete pods the scheduler may place new pods on those nodes before the node
		has released those resources and causing those pods to be evicted immediately.

		Note that the delete command does NOT do resource version checks, so if someone
		submits an update to a resource right when you submit a delete, their update
		will be lost along with the rest of the resource.`)

	delete_example = templates.Examples(`
		# Delete a pod using the type and name specified in pod.json.
		kubectl delete -f ./pod.json

		# Delete a pod based on the type and name in the JSON passed into stdin.
		cat pod.json | kubectl delete -f -

		# Delete pods and services with same names "baz" and "foo"
		kubectl delete pod,service baz foo

		# Delete pods and services with label name=myLabel.
		kubectl delete pods,services -l name=myLabel

		# Delete a pod with minimal delay
		kubectl delete pod foo --now

		# Force delete a pod on a dead node
		kubectl delete pod foo --grace-period=0 --force

		# Delete a pod with UID 1234-56-7890-234234-456456.
		kubectl delete pod 1234-56-7890-234234-456456

		# Delete all pods
		kubectl delete pods --all`)
)

func NewCmdDelete(f cmdutil.Factory, out, errOut io.Writer) *cobra.Command {
	options := &resource.FilenameOptions{}

	// retrieve a list of handled resources from printer as valid args
	validArgs, argAliases := []string{}, []string{}
	p, err := f.Printer(nil, kubectl.PrintOptions{
		ColumnLabels: []string{},
	})
	cmdutil.CheckErr(err)
	if p != nil {
		validArgs = p.HandledResources()
		argAliases = kubectl.ResourceAliases(validArgs)
	}

	cmd := &cobra.Command{
		Use:     "delete ([-f FILENAME] | TYPE [(NAME | -l label | --all)])",
		Short:   "Delete resources by filenames, stdin, resources and names, or by resources and label selector",
		Long:    delete_long,
		Example: delete_example,
		Run: func(cmd *cobra.Command, args []string) {
			cmdutil.CheckErr(cmdutil.ValidateOutputArgs(cmd))
			err := RunDelete(f, out, errOut, cmd, args, options)
			cmdutil.CheckErr(err)
		},
		SuggestFor: []string{"rm"},
		ValidArgs:  validArgs,
		ArgAliases: argAliases,
	}
	usage := "containing the resource to delete."
	cmdutil.AddFilenameOptionFlags(cmd, options, usage)
	cmd.Flags().StringP("selector", "l", "", "Selector (label query) to filter on.")
	cmd.Flags().Bool("all", false, "[-all] to select all the specified resources.")
	cmd.Flags().Bool("ignore-not-found", false, "Treat \"resource not found\" as a successful delete. Defaults to \"true\" when --all is specified.")
	cmd.Flags().Bool("cascade", true, "If true, cascade the deletion of the resources managed by this resource (e.g. Pods created by a ReplicationController).  Default true.")
	cmd.Flags().Int("grace-period", -1, "Period of time in seconds given to the resource to terminate gracefully. Ignored if negative.")
	cmd.Flags().Bool("now", false, "If true, resources are signaled for immediate shutdown (same as --grace-period=1).")
	cmd.Flags().Bool("force", false, "Immediate deletion of some resources may result in inconsistency or data loss and requires confirmation.")
	cmd.Flags().Duration("timeout", 0, "The length of time to wait before giving up on a delete, zero means determine a timeout from the size of the object")
	cmdutil.AddOutputFlagsForMutation(cmd)
	cmdutil.AddInclude3rdPartyFlags(cmd)
	return cmd
}

func RunDelete(f cmdutil.Factory, out, errOut io.Writer, cmd *cobra.Command, args []string, options *resource.FilenameOptions) error {
	cmdNamespace, enforceNamespace, err := f.DefaultNamespace()
	if err != nil {
		return err
	}
	deleteAll := cmdutil.GetFlagBool(cmd, "all")
	mapper, typer, err := f.UnstructuredObject()
	if err != nil {
		return err
	}
	r := resource.NewBuilder(mapper, typer, resource.ClientMapperFunc(f.UnstructuredClientForMapping), unstructured.UnstructuredJSONScheme).
		ContinueOnError().
		NamespaceParam(cmdNamespace).DefaultNamespace().
		FilenameParam(enforceNamespace, options).
		SelectorParam(cmdutil.GetFlagString(cmd, "selector")).
		SelectAllParam(deleteAll).
		ResourceTypeOrNameArgs(false, args...).RequireObject(false).
		Flatten().
		Do()
	err = r.Err()
	if err != nil {
		return err
	}

	ignoreNotFound := cmdutil.GetFlagBool(cmd, "ignore-not-found")
	if deleteAll {
		f := cmd.Flags().Lookup("ignore-not-found")
		// The flag should never be missing
		if f == nil {
			return fmt.Errorf("missing --ignore-not-found flag")
		}
		// If the user didn't explicitly set the option, default to ignoring NotFound errors when used with --all
		if !f.Changed {
			ignoreNotFound = true
		}
	}

	gracePeriod := cmdutil.GetFlagInt(cmd, "grace-period")
	force := cmdutil.GetFlagBool(cmd, "force")
	if cmdutil.GetFlagBool(cmd, "now") {
		if gracePeriod != -1 {
			return fmt.Errorf("--now and --grace-period cannot be specified together")
		}
		gracePeriod = 1
	}
	wait := false
	if gracePeriod == 0 {
		if force {
			fmt.Fprintf(errOut, "warning: Immediate deletion does not wait for confirmation that the running resource has been terminated. The resource may continue to run on the cluster indefinitely.\n")
		} else {
			// To preserve backwards compatibility, but prevent accidental data loss, we convert --grace-period=0
			// into --grace-period=1 and wait until the object is successfully deleted. Users may provide --force
			// to bypass this wait.
			wait = true
			gracePeriod = 1
		}
	}

	shortOutput := cmdutil.GetFlagString(cmd, "output") == "name"
	// By default use a reaper to delete all related resources.
	if cmdutil.GetFlagBool(cmd, "cascade") {
		return ReapResult(r, f, out, cmdutil.GetFlagBool(cmd, "cascade"), ignoreNotFound, cmdutil.GetFlagDuration(cmd, "timeout"), gracePeriod, wait, shortOutput, mapper, false)
	}
	return DeleteResult(r, out, ignoreNotFound, shortOutput, mapper)
}

func ReapResult(r *resource.Result, f cmdutil.Factory, out io.Writer, isDefaultDelete, ignoreNotFound bool, timeout time.Duration, gracePeriod int, waitForDeletion, shortOutput bool, mapper meta.RESTMapper, quiet bool) error {
	found := 0
	if ignoreNotFound {
		r = r.IgnoreErrors(errors.IsNotFound)
	}
	err := r.Visit(func(info *resource.Info, err error) error {
		if err != nil {
			return err
		}
		found++
		reaper, err := f.Reaper(info.Mapping)
		if err != nil {
			// If there is no reaper for this resources and the user didn't explicitly ask for stop.
			if kubectl.IsNoSuchReaperError(err) && isDefaultDelete {
				return deleteResource(info, out, shortOutput, mapper)
			}
			return cmdutil.AddSourceToErr("reaping", info.Source, err)
		}
		var options *api.DeleteOptions
		if gracePeriod >= 0 {
			options = api.NewDeleteOptions(int64(gracePeriod))
		}
		if err := reaper.Stop(info.Namespace, info.Name, timeout, options); err != nil {
			return cmdutil.AddSourceToErr("stopping", info.Source, err)
		}
		if waitForDeletion {
			if err := waitForObjectDeletion(info, timeout); err != nil {
				return cmdutil.AddSourceToErr("stopping", info.Source, err)
			}
		}
		if !quiet {
			cmdutil.PrintSuccess(mapper, shortOutput, out, info.Mapping.Resource, info.Name, false, "deleted")
		}
		return nil
	})
	if err != nil {
		return err
	}
	if found == 0 {
		fmt.Fprintf(out, "No resources found\n")
	}
	return nil
}

func DeleteResult(r *resource.Result, out io.Writer, ignoreNotFound bool, shortOutput bool, mapper meta.RESTMapper) error {
	found := 0
	if ignoreNotFound {
		r = r.IgnoreErrors(errors.IsNotFound)
	}
	err := r.Visit(func(info *resource.Info, err error) error {
		if err != nil {
			return err
		}
		found++
		return deleteResource(info, out, shortOutput, mapper)
	})
	if err != nil {
		return err
	}
	if found == 0 {
		fmt.Fprintf(out, "No resources found\n")
	}
	return nil
}

func deleteResource(info *resource.Info, out io.Writer, shortOutput bool, mapper meta.RESTMapper) error {
	if err := resource.NewHelper(info.Client, info.Mapping).Delete(info.Namespace, info.Name); err != nil {
		return cmdutil.AddSourceToErr("deleting", info.Source, err)
	}
	cmdutil.PrintSuccess(mapper, shortOutput, out, info.Mapping.Resource, info.Name, false, "deleted")
	return nil
}

// objectDeletionWaitInterval is the interval to wait between checks for deletion. Exposed for testing.
var objectDeletionWaitInterval = time.Second

// waitForObjectDeletion refreshes the object, waiting until it is deleted, a timeout is reached, or
// an error is encountered. It checks once a second.
func waitForObjectDeletion(info *resource.Info, timeout time.Duration) error {
	copied := *info
	info = &copied
	// TODO: refactor Reaper so that we can pass the "wait" option into it, and then check for UID change.
	return wait.PollImmediate(objectDeletionWaitInterval, timeout, func() (bool, error) {
		switch err := info.Get(); {
		case err == nil:
			return false, nil
		case errors.IsNotFound(err):
			return true, nil
		default:
			return false, err
		}
	})
}
<commit_msg>remove the delete-pod-uid spec<commit_after>/*
Copyright 2014 The Kubernetes Authors.

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

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

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

package cmd

import (
	"fmt"
	"io"
	"time"

	"github.com/spf13/cobra"

	"k8s.io/kubernetes/pkg/api"
	"k8s.io/kubernetes/pkg/api/errors"
	"k8s.io/kubernetes/pkg/api/meta"
	"k8s.io/kubernetes/pkg/apis/meta/v1/unstructured"
	"k8s.io/kubernetes/pkg/kubectl"
	"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
	cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
	"k8s.io/kubernetes/pkg/kubectl/resource"
	"k8s.io/kubernetes/pkg/util/wait"
)

var (
	delete_long = templates.LongDesc(`
		Delete resources by filenames, stdin, resources and names, or by resources and label selector.

		JSON and YAML formats are accepted. Only one type of the arguments may be specified: filenames,
		resources and names, or resources and label selector.

		Some resources, such as pods, support graceful deletion. These resources define a default period
		before they are forcibly terminated (the grace period) but you may override that value with
		the --grace-period flag, or pass --now to set a grace-period of 1. Because these resources often
		represent entities in the cluster, deletion may not be acknowledged immediately. If the node
		hosting a pod is down or cannot reach the API server, termination may take significantly longer
		than the grace period. To force delete a resource,	you must pass a grace	period of 0 and specify
		the --force flag.

		IMPORTANT: Force deleting pods does not wait for confirmation that the pod's processes have been
		terminated, which can leave those processes running until the node detects the deletion and
		completes graceful deletion. If your processes use shared storage or talk to a remote API and
		depend on the name of the pod to identify themselves, force deleting those pods may result in
		multiple processes running on different machines using the same identification which may lead
		to data corruption or inconsistency. Only force delete pods when you are sure the pod is
		terminated, or if your application can tolerate multiple copies of the same pod running at once.
		Also, if you force delete pods the scheduler may place new pods on those nodes before the node
		has released those resources and causing those pods to be evicted immediately.

		Note that the delete command does NOT do resource version checks, so if someone
		submits an update to a resource right when you submit a delete, their update
		will be lost along with the rest of the resource.`)

	delete_example = templates.Examples(`
		# Delete a pod using the type and name specified in pod.json.
		kubectl delete -f ./pod.json

		# Delete a pod based on the type and name in the JSON passed into stdin.
		cat pod.json | kubectl delete -f -

		# Delete pods and services with same names "baz" and "foo"
		kubectl delete pod,service baz foo

		# Delete pods and services with label name=myLabel.
		kubectl delete pods,services -l name=myLabel

		# Delete a pod with minimal delay
		kubectl delete pod foo --now

		# Force delete a pod on a dead node
		kubectl delete pod foo --grace-period=0 --force

		# Delete all pods
		kubectl delete pods --all`)
)

func NewCmdDelete(f cmdutil.Factory, out, errOut io.Writer) *cobra.Command {
	options := &resource.FilenameOptions{}

	// retrieve a list of handled resources from printer as valid args
	validArgs, argAliases := []string{}, []string{}
	p, err := f.Printer(nil, kubectl.PrintOptions{
		ColumnLabels: []string{},
	})
	cmdutil.CheckErr(err)
	if p != nil {
		validArgs = p.HandledResources()
		argAliases = kubectl.ResourceAliases(validArgs)
	}

	cmd := &cobra.Command{
		Use:     "delete ([-f FILENAME] | TYPE [(NAME | -l label | --all)])",
		Short:   "Delete resources by filenames, stdin, resources and names, or by resources and label selector",
		Long:    delete_long,
		Example: delete_example,
		Run: func(cmd *cobra.Command, args []string) {
			cmdutil.CheckErr(cmdutil.ValidateOutputArgs(cmd))
			err := RunDelete(f, out, errOut, cmd, args, options)
			cmdutil.CheckErr(err)
		},
		SuggestFor: []string{"rm"},
		ValidArgs:  validArgs,
		ArgAliases: argAliases,
	}
	usage := "containing the resource to delete."
	cmdutil.AddFilenameOptionFlags(cmd, options, usage)
	cmd.Flags().StringP("selector", "l", "", "Selector (label query) to filter on.")
	cmd.Flags().Bool("all", false, "[-all] to select all the specified resources.")
	cmd.Flags().Bool("ignore-not-found", false, "Treat \"resource not found\" as a successful delete. Defaults to \"true\" when --all is specified.")
	cmd.Flags().Bool("cascade", true, "If true, cascade the deletion of the resources managed by this resource (e.g. Pods created by a ReplicationController).  Default true.")
	cmd.Flags().Int("grace-period", -1, "Period of time in seconds given to the resource to terminate gracefully. Ignored if negative.")
	cmd.Flags().Bool("now", false, "If true, resources are signaled for immediate shutdown (same as --grace-period=1).")
	cmd.Flags().Bool("force", false, "Immediate deletion of some resources may result in inconsistency or data loss and requires confirmation.")
	cmd.Flags().Duration("timeout", 0, "The length of time to wait before giving up on a delete, zero means determine a timeout from the size of the object")
	cmdutil.AddOutputFlagsForMutation(cmd)
	cmdutil.AddInclude3rdPartyFlags(cmd)
	return cmd
}

func RunDelete(f cmdutil.Factory, out, errOut io.Writer, cmd *cobra.Command, args []string, options *resource.FilenameOptions) error {
	cmdNamespace, enforceNamespace, err := f.DefaultNamespace()
	if err != nil {
		return err
	}
	deleteAll := cmdutil.GetFlagBool(cmd, "all")
	mapper, typer, err := f.UnstructuredObject()
	if err != nil {
		return err
	}
	r := resource.NewBuilder(mapper, typer, resource.ClientMapperFunc(f.UnstructuredClientForMapping), unstructured.UnstructuredJSONScheme).
		ContinueOnError().
		NamespaceParam(cmdNamespace).DefaultNamespace().
		FilenameParam(enforceNamespace, options).
		SelectorParam(cmdutil.GetFlagString(cmd, "selector")).
		SelectAllParam(deleteAll).
		ResourceTypeOrNameArgs(false, args...).RequireObject(false).
		Flatten().
		Do()
	err = r.Err()
	if err != nil {
		return err
	}

	ignoreNotFound := cmdutil.GetFlagBool(cmd, "ignore-not-found")
	if deleteAll {
		f := cmd.Flags().Lookup("ignore-not-found")
		// The flag should never be missing
		if f == nil {
			return fmt.Errorf("missing --ignore-not-found flag")
		}
		// If the user didn't explicitly set the option, default to ignoring NotFound errors when used with --all
		if !f.Changed {
			ignoreNotFound = true
		}
	}

	gracePeriod := cmdutil.GetFlagInt(cmd, "grace-period")
	force := cmdutil.GetFlagBool(cmd, "force")
	if cmdutil.GetFlagBool(cmd, "now") {
		if gracePeriod != -1 {
			return fmt.Errorf("--now and --grace-period cannot be specified together")
		}
		gracePeriod = 1
	}
	wait := false
	if gracePeriod == 0 {
		if force {
			fmt.Fprintf(errOut, "warning: Immediate deletion does not wait for confirmation that the running resource has been terminated. The resource may continue to run on the cluster indefinitely.\n")
		} else {
			// To preserve backwards compatibility, but prevent accidental data loss, we convert --grace-period=0
			// into --grace-period=1 and wait until the object is successfully deleted. Users may provide --force
			// to bypass this wait.
			wait = true
			gracePeriod = 1
		}
	}

	shortOutput := cmdutil.GetFlagString(cmd, "output") == "name"
	// By default use a reaper to delete all related resources.
	if cmdutil.GetFlagBool(cmd, "cascade") {
		return ReapResult(r, f, out, cmdutil.GetFlagBool(cmd, "cascade"), ignoreNotFound, cmdutil.GetFlagDuration(cmd, "timeout"), gracePeriod, wait, shortOutput, mapper, false)
	}
	return DeleteResult(r, out, ignoreNotFound, shortOutput, mapper)
}

func ReapResult(r *resource.Result, f cmdutil.Factory, out io.Writer, isDefaultDelete, ignoreNotFound bool, timeout time.Duration, gracePeriod int, waitForDeletion, shortOutput bool, mapper meta.RESTMapper, quiet bool) error {
	found := 0
	if ignoreNotFound {
		r = r.IgnoreErrors(errors.IsNotFound)
	}
	err := r.Visit(func(info *resource.Info, err error) error {
		if err != nil {
			return err
		}
		found++
		reaper, err := f.Reaper(info.Mapping)
		if err != nil {
			// If there is no reaper for this resources and the user didn't explicitly ask for stop.
			if kubectl.IsNoSuchReaperError(err) && isDefaultDelete {
				return deleteResource(info, out, shortOutput, mapper)
			}
			return cmdutil.AddSourceToErr("reaping", info.Source, err)
		}
		var options *api.DeleteOptions
		if gracePeriod >= 0 {
			options = api.NewDeleteOptions(int64(gracePeriod))
		}
		if err := reaper.Stop(info.Namespace, info.Name, timeout, options); err != nil {
			return cmdutil.AddSourceToErr("stopping", info.Source, err)
		}
		if waitForDeletion {
			if err := waitForObjectDeletion(info, timeout); err != nil {
				return cmdutil.AddSourceToErr("stopping", info.Source, err)
			}
		}
		if !quiet {
			cmdutil.PrintSuccess(mapper, shortOutput, out, info.Mapping.Resource, info.Name, false, "deleted")
		}
		return nil
	})
	if err != nil {
		return err
	}
	if found == 0 {
		fmt.Fprintf(out, "No resources found\n")
	}
	return nil
}

func DeleteResult(r *resource.Result, out io.Writer, ignoreNotFound bool, shortOutput bool, mapper meta.RESTMapper) error {
	found := 0
	if ignoreNotFound {
		r = r.IgnoreErrors(errors.IsNotFound)
	}
	err := r.Visit(func(info *resource.Info, err error) error {
		if err != nil {
			return err
		}
		found++
		return deleteResource(info, out, shortOutput, mapper)
	})
	if err != nil {
		return err
	}
	if found == 0 {
		fmt.Fprintf(out, "No resources found\n")
	}
	return nil
}

func deleteResource(info *resource.Info, out io.Writer, shortOutput bool, mapper meta.RESTMapper) error {
	if err := resource.NewHelper(info.Client, info.Mapping).Delete(info.Namespace, info.Name); err != nil {
		return cmdutil.AddSourceToErr("deleting", info.Source, err)
	}
	cmdutil.PrintSuccess(mapper, shortOutput, out, info.Mapping.Resource, info.Name, false, "deleted")
	return nil
}

// objectDeletionWaitInterval is the interval to wait between checks for deletion. Exposed for testing.
var objectDeletionWaitInterval = time.Second

// waitForObjectDeletion refreshes the object, waiting until it is deleted, a timeout is reached, or
// an error is encountered. It checks once a second.
func waitForObjectDeletion(info *resource.Info, timeout time.Duration) error {
	copied := *info
	info = &copied
	// TODO: refactor Reaper so that we can pass the "wait" option into it, and then check for UID change.
	return wait.PollImmediate(objectDeletionWaitInterval, timeout, func() (bool, error) {
		switch err := info.Get(); {
		case err == nil:
			return false, nil
		case errors.IsNotFound(err):
			return true, nil
		default:
			return false, err
		}
	})
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"flag"
	"bufio"
	"log"
	"os"
	"math/rand"
	"strconv"
	"time"
)

var SAMPLE_TYPE int
const (
	INTEGER = iota
	PERCENTAGE
	)

var SAMPLE_MAP map[int]string
var SAMPLE_VALUE int // either a percentage or an integer value

var command = os.Args[0]
var invocation = fmt.Sprintf("%s [[sample size]%%] [file path]\n", command)

var logger *log.Logger

// flag.Usage help message override
var Usage = func() {
	fmt.Fprintf(os.Stderr, "Usage: %s", invocation)
}

func init() {
	logger = log.New(os.Stderr, "[SNL] ", log.LstdFlags|log.Lshortfile)
	SAMPLE_MAP = make(map[int]string)
	rand.Seed(time.Now().UTC().UnixNano())

	flag.Usage = Usage
	flag.Parse()
}

// parseValue determines if the value is a percentage or
// an integer, and sets the global value `SAMPLE_VALUE`,
func parseValue(s string) {
	var value string
	if string(s[len(s) - 1]) == "%" {
		SAMPLE_TYPE = PERCENTAGE
		value = s[:len(s)-1]
	} else {
		SAMPLE_TYPE = INTEGER
		value = s
	}

	// convert value to integer
	intValue, err := strconv.Atoi(value)
	if err != nil {
		logger.Printf("[Error] error converting sample_size: %s to integer: %s", value, err)
		fmt.Printf("Usage: %s", invocation)
		os.Exit(1)
	}
	SAMPLE_VALUE = intValue
}

// parseFile validates a string and returns an *os.File
func parseFile(s string) (file *os.File){
	if s == "" {
		logger.Print("[Error] missing filename argument")
		fmt.Printf("Usage: %s", invocation)
		os.Exit(1)
	}

	file, err := os.Open(s)
	if err != nil {
		logger.Fatalf("[Error] error opening %s: %s", s, err)
	}

	return file
}

func main () {
	var count int // a count of how many lines have been collected
	var candidate int // tmp variable for choosing a random number
	var done int // number of lines printed so far
	var totalOut int // number of total lines to print after calling parseValue

	sampleSize := flag.Arg(0)
	parseValue(sampleSize)

	fileName := flag.Arg(1)

	file := parseFile(fileName)
	defer file.Close()

	scanner := bufio.NewScanner(file)
	for scanner.Scan() {
		// store all lines in a map with a line number index
		SAMPLE_MAP[count] = fmt.Sprint(scanner.Text())
		count++
	}

	// a log of which line numbers we have seen
	seen := make(map[int]bool)

	// calulate the number of values we need to print to stdout
	if SAMPLE_TYPE == INTEGER {
		totalOut = SAMPLE_VALUE
	} else if SAMPLE_TYPE == PERCENTAGE {
		totalOut = int((float64(SAMPLE_VALUE) / 100.0) * float64(count))
	}

	for {
		candidate = rand.Intn(count)

		// if we haven't printed this line before, print to stdout
		if seen[candidate] != true {
			fmt.Println(SAMPLE_MAP[candidate])
			seen[candidate] = true
			done++
		}
		if done == totalOut {
			os.Exit(0)
		}
	}
}
<commit_msg>correct sampling<commit_after>package main

import (
	"fmt"
	"flag"
	"bufio"
	"log"
	"os"
	"math/rand"
	"strconv"
	"time"
)

var SAMPLE_TYPE int
const (
	INTEGER = iota
	PERCENTAGE
	)

var COUNT int // a count of how many lines have been collected
var SAMPLE = make([]string, 0)
var SAMPLE_VALUE int // either a percentage or a sum to keep

var command = os.Args[0]
var invocation = fmt.Sprintf("%s [[sample size]%%] [file path]\n", command)

var logger *log.Logger

// flag.Usage help message override
var Usage = func() {
	fmt.Fprintf(os.Stderr, "Usage: %s", invocation)
}

func init() {
	logger = log.New(os.Stderr, "[SNL] ", log.LstdFlags|log.Lshortfile)
	rand.Seed(time.Now().UTC().UnixNano())

	flag.Usage = Usage
	flag.Parse()
}

// parseValue determines if the value is a percentage or
// an integer, and sets the global value `SAMPLE_VALUE`,
func parseValue(s string) {
	var value string
	if string(s[len(s) - 1]) == "%" {
		SAMPLE_TYPE = PERCENTAGE
		value = s[:len(s)-1]
	} else {
		SAMPLE_TYPE = INTEGER
		value = s
	}

	// convert value to integer
	intValue, err := strconv.Atoi(value)
	if err != nil {
		logger.Printf("[Error] error converting sample_size: %s to integer: %s", value, err)
		fmt.Printf("Usage: %s", invocation)
		os.Exit(1)
	}
	SAMPLE_VALUE = intValue
}

// parseFile validates a string and returns an *os.File
func parseFile(s string) (file *os.File) {
	if s == "" {
		logger.Print("[Error] missing filename argument")
		fmt.Printf("Usage: %s", invocation)
		os.Exit(1)
	}

	file, err := os.Open(s)
	if err != nil {
		logger.Fatalf("[Error] error opening %s: %s", s, err)
	}

	return file
}

// keepPercentage returns a function that closes over
// an argument that represents a percentage. The function it returns
// accepts a count and it returns.
func keepPercentage(percentage float64) (fn func(int) int){
	return func(count int) int {
		return int(percentage * float64(count))
	}
}

// forgetOrReplace will choose a number, N, between
// 0 and count, if N is >= threshold we return the sample;
// if N is < len(`sample`) we replace it with `value`
func forgetOrReplace(sample []string, count, threshold int, value string){
	var candidate = rand.Intn(count)

	if candidate < threshold {
		sample[candidate] = value
	}
}

func printSample() {
	for _, line := range SAMPLE {
		fmt.Println(line)
	}
}

func main () {

	var file *os.File

	sampleSize := flag.Arg(0)
	parseValue(sampleSize)

	if SAMPLE_TYPE == INTEGER {
		SAMPLE = make([]string, SAMPLE_VALUE)
	} else if SAMPLE_TYPE == PERCENTAGE {
		// make a default size to collect
	}

	fileName := flag.Arg(1)
	if fileName == "-" {
		file = os.Stdin
	} else {
		file = parseFile(fileName)
		defer file.Close()
	}

	var line string
	scanner := bufio.NewScanner(file)
	for scanner.Scan() {
		line = fmt.Sprint(scanner.Text())

		if SAMPLE_TYPE == PERCENTAGE {

			logger.Println("percentage sampling not implemented yet")
			os.Exit(0)
		}

		if COUNT < SAMPLE_VALUE {
			SAMPLE[COUNT] = line
		} else {
			forgetOrReplace(SAMPLE, COUNT, SAMPLE_VALUE, line)
		}
		COUNT++
	}
	printSample()
}
<|endoftext|>


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

// Package libinit creates the environment and root file system for u-root.
package libinit

import (
	"fmt"
	"os"
	"runtime"
	"strconv"
	"syscall"

	"github.com/u-root/u-root/pkg/cmdline"
	"github.com/u-root/u-root/pkg/ulog"
	"golang.org/x/sys/unix"
)

type creator interface {
	create() error
	fmt.Stringer
}

type dir struct {
	Name string
	Mode os.FileMode
}

func (d dir) create() error {
	return os.MkdirAll(d.Name, d.Mode)
}

func (d dir) String() string {
	return fmt.Sprintf("dir %q (mode %#o)", d.Name, d.Mode)
}

type symlink struct {
	Target  string
	NewPath string
}

func (s symlink) create() error {
	os.Remove(s.NewPath)
	return os.Symlink(s.Target, s.NewPath)
}

func (s symlink) String() string {
	return fmt.Sprintf("symlink %q -> %q", s.NewPath, s.Target)
}

type dev struct {
	Name string
	Mode uint32
	Dev  int
}

func (d dev) create() error {
	os.Remove(d.Name)
	return syscall.Mknod(d.Name, d.Mode, d.Dev)
}

func (d dev) String() string {
	return fmt.Sprintf("dev %q (mode %#o; magic %d)", d.Name, d.Mode, d.Dev)
}

type mount struct {
	Source string
	Target string
	FSType string
	Flags  uintptr
	Opts   string
}

func (m mount) create() error {
	return syscall.Mount(m.Source, m.Target, m.FSType, m.Flags, m.Opts)
}

func (m mount) String() string {
	return fmt.Sprintf("mount -t %q -o %s %q %q flags %#x", m.FSType, m.Opts, m.Source, m.Target, m.Flags)
}

var (
	// These have to be created / mounted first, so that the logging works correctly.
	preNamespace = []creator{
		dir{Name: "/dev", Mode: 0777},

		// Kernel must be compiled with CONFIG_DEVTMPFS.
		mount{Source: "devtmpfs", Target: "/dev", FSType: "devtmpfs"},
	}
	namespace = []creator{
		dir{Name: "/buildbin", Mode: 0777},
		dir{Name: "/ubin", Mode: 0777},
		dir{Name: "/tmp", Mode: 0777},
		dir{Name: "/env", Mode: 0777},
		dir{Name: "/tcz", Mode: 0777},
		dir{Name: "/lib", Mode: 0777},
		dir{Name: "/usr/lib", Mode: 0777},
		dir{Name: "/var/log", Mode: 0777},
		dir{Name: "/go/pkg/linux_amd64", Mode: 0777},

		dir{Name: "/etc", Mode: 0777},

		dir{Name: "/proc", Mode: 0555},
		mount{Source: "proc", Target: "/proc", FSType: "proc"},
		mount{Source: "tmpfs", Target: "/tmp", FSType: "tmpfs"},

		dev{Name: "/dev/tty", Mode: syscall.S_IFCHR | 0666, Dev: 0x0500},
		dev{Name: "/dev/urandom", Mode: syscall.S_IFCHR | 0444, Dev: 0x0109},
		dev{Name: "/dev/port", Mode: syscall.S_IFCHR | 0640, Dev: 0x0104},

		dir{Name: "/dev/pts", Mode: 0777},
		mount{Source: "devpts", Target: "/dev/pts", FSType: "devpts", Opts: "ptmxmode=666,gid=5,mode=620"},
		dev{Name: "/dev/ptmx", Mode: syscall.S_IFCHR | 0666, Dev: 0x0502},
		// Note: shm is required at least for Chrome. If you don't mount
		// it chrome throws a bogus "out of memory" error, not the more
		// useful "I can't open /dev/shm/whatever". SAD!
		dir{Name: "/dev/shm", Mode: 0777},
		mount{Source: "tmpfs", Target: "/dev/shm", FSType: "tmpfs"},

		dir{Name: "/sys", Mode: 0555},
		mount{Source: "sysfs", Target: "/sys", FSType: "sysfs"},
		mount{Source: "securityfs", Target: "/sys/kernel/security", FSType: "securityfs"},
	}
	cgroupsnamespace = []creator{
		mount{Source: "cgroup", Target: "/sys/fs/cgroup", FSType: "tmpfs"},
		dir{Name: "/sys/fs/cgroup/memory", Mode: 0555},
		dir{Name: "/sys/fs/cgroup/freezer", Mode: 0555},
		dir{Name: "/sys/fs/cgroup/devices", Mode: 0555},
		dir{Name: "/sys/fs/cgroup/cpu,cpuacct", Mode: 0555},
		dir{Name: "/sys/fs/cgroup/blkio", Mode: 0555},
		dir{Name: "/sys/fs/cgroup/cpuset", Mode: 0555},
		dir{Name: "/sys/fs/cgroup/pids", Mode: 0555},
		dir{Name: "/sys/fs/cgroup/net_cls,net_prio", Mode: 0555},
		dir{Name: "/sys/fs/cgroup/hugetlb", Mode: 0555},
		dir{Name: "/sys/fs/cgroup/perf_event", Mode: 0555},
		symlink{NewPath: "/sys/fs/cgroup/cpu", Target: "/sys/fs/cgroup/cpu,cpuacct"},
		symlink{NewPath: "/sys/fs/cgroup/cpuacct", Target: "/sys/fs/cgroup/cpu,cpuacct"},
		symlink{NewPath: "/sys/fs/cgroup/net_cls", Target: "/sys/fs/cgroup/net_cls,net_prio"},
		symlink{NewPath: "/sys/fs/cgroup/net_prio", Target: "/sys/fs/cgroup/net_cls,net_prio"},
		mount{Source: "cgroup", Target: "/sys/fs/cgroup/memory", FSType: "cgroup", Opts: "memory"},
		mount{Source: "cgroup", Target: "/sys/fs/cgroup/freezer", FSType: "cgroup", Opts: "freezer"},
		mount{Source: "cgroup", Target: "/sys/fs/cgroup/devices", FSType: "cgroup", Opts: "devices"},
		mount{Source: "cgroup", Target: "/sys/fs/cgroup/cpu,cpuacct", FSType: "cgroup", Opts: "cpu,cpuacct"},
		mount{Source: "cgroup", Target: "/sys/fs/cgroup/blkio", FSType: "cgroup", Opts: "blkio"},
		mount{Source: "cgroup", Target: "/sys/fs/cgroup/cpuset", FSType: "cgroup", Opts: "cpuset"},
		mount{Source: "cgroup", Target: "/sys/fs/cgroup/pids", FSType: "cgroup", Opts: "pids"},
		mount{Source: "cgroup", Target: "/sys/fs/cgroup/net_cls,net_prio", FSType: "cgroup", Opts: "net_cls,net_prio"},
		mount{Source: "cgroup", Target: "/sys/fs/cgroup/hugetlb", FSType: "cgroup", Opts: "hugetlb"},
		mount{Source: "cgroup", Target: "/sys/fs/cgroup/perf_event", FSType: "cgroup", Opts: "perf_event"},
	}
)

func goBin() string {
	return fmt.Sprintf("/go/bin/%s_%s:/go/bin:/go/pkg/tool/%s_%s", runtime.GOOS, runtime.GOARCH, runtime.GOOS, runtime.GOARCH)
}

func create(namespace []creator) {
	// Clear umask bits so that we get stuff like ptmx right.
	m := unix.Umask(0)
	defer unix.Umask(m)
	for _, c := range namespace {
		if err := c.create(); err != nil {
			ulog.KernelLog.Printf("u-root init: error creating %s: %v", c, err)
		}
	}
}

// SetEnv sets the default u-root environment.
func SetEnv() {
	env := map[string]string{
		"LD_LIBRARY_PATH": "/usr/local/lib",
		"GOROOT":          "/go",
		"GOPATH":          "/",
		"GOBIN":           "/ubin",
		"CGO_ENABLED":     "0",
	}

	// Not all these paths may be populated or even exist but OTOH they might.
	path := "/ubin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/local/bin:/usr/local/sbin:/buildbin:/bbin"

	env["PATH"] = fmt.Sprintf("%v:%v", goBin(), path)
	for k, v := range env {
		os.Setenv(k, v)
	}
}

// CreateRootfs creates the default u-root file system.
func CreateRootfs() {
	// Mount devtmpfs, then open /dev/kmsg with Reinit.
	create(preNamespace)
	ulog.KernelLog.Reinit()

	create(namespace)

	// systemd gets upset when it discovers something has already setup cgroups
	// We have to do this after the base namespace is created, so we have /proc
	initFlags := cmdline.GetInitFlagMap()
	systemd, present := initFlags["systemd"]
	systemdEnabled, boolErr := strconv.ParseBool(systemd)
	if !present || boolErr != nil || !systemdEnabled {
		create(cgroupsnamespace)
	}
}
<commit_msg>mount devpts with "newinstance", but make /dev/ptmx a symlink to /dev/pts/ptmx<commit_after>// Copyright 2014-2019 the u-root Authors. All rights reserved
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package libinit creates the environment and root file system for u-root.
package libinit

import (
	"fmt"
	"os"
	"runtime"
	"strconv"
	"syscall"

	"github.com/u-root/u-root/pkg/cmdline"
	"github.com/u-root/u-root/pkg/ulog"
	"golang.org/x/sys/unix"
)

type creator interface {
	create() error
	fmt.Stringer
}

type dir struct {
	Name string
	Mode os.FileMode
}

func (d dir) create() error {
	return os.MkdirAll(d.Name, d.Mode)
}

func (d dir) String() string {
	return fmt.Sprintf("dir %q (mode %#o)", d.Name, d.Mode)
}

type symlink struct {
	Target  string
	NewPath string
}

func (s symlink) create() error {
	os.Remove(s.NewPath)
	return os.Symlink(s.Target, s.NewPath)
}

func (s symlink) String() string {
	return fmt.Sprintf("symlink %q -> %q", s.NewPath, s.Target)
}

type dev struct {
	Name string
	Mode uint32
	Dev  int
}

func (d dev) create() error {
	os.Remove(d.Name)
	return syscall.Mknod(d.Name, d.Mode, d.Dev)
}

func (d dev) String() string {
	return fmt.Sprintf("dev %q (mode %#o; magic %d)", d.Name, d.Mode, d.Dev)
}

type mount struct {
	Source string
	Target string
	FSType string
	Flags  uintptr
	Opts   string
}

func (m mount) create() error {
	return syscall.Mount(m.Source, m.Target, m.FSType, m.Flags, m.Opts)
}

func (m mount) String() string {
	return fmt.Sprintf("mount -t %q -o %s %q %q flags %#x", m.FSType, m.Opts, m.Source, m.Target, m.Flags)
}

var (
	// These have to be created / mounted first, so that the logging works correctly.
	preNamespace = []creator{
		dir{Name: "/dev", Mode: 0777},

		// Kernel must be compiled with CONFIG_DEVTMPFS.
		mount{Source: "devtmpfs", Target: "/dev", FSType: "devtmpfs"},
	}
	namespace = []creator{
		dir{Name: "/buildbin", Mode: 0777},
		dir{Name: "/ubin", Mode: 0777},
		dir{Name: "/tmp", Mode: 0777},
		dir{Name: "/env", Mode: 0777},
		dir{Name: "/tcz", Mode: 0777},
		dir{Name: "/lib", Mode: 0777},
		dir{Name: "/usr/lib", Mode: 0777},
		dir{Name: "/var/log", Mode: 0777},
		dir{Name: "/go/pkg/linux_amd64", Mode: 0777},

		dir{Name: "/etc", Mode: 0777},

		dir{Name: "/proc", Mode: 0555},
		mount{Source: "proc", Target: "/proc", FSType: "proc"},
		mount{Source: "tmpfs", Target: "/tmp", FSType: "tmpfs"},

		dev{Name: "/dev/tty", Mode: syscall.S_IFCHR | 0666, Dev: 0x0500},
		dev{Name: "/dev/urandom", Mode: syscall.S_IFCHR | 0444, Dev: 0x0109},
		dev{Name: "/dev/port", Mode: syscall.S_IFCHR | 0640, Dev: 0x0104},

		dir{Name: "/dev/pts", Mode: 0777},
		mount{Source: "devpts", Target: "/dev/pts", FSType: "devpts", Opts: "newinstance,ptmxmode=666,gid=5,mode=620"},
		// Note: if we mount /dev/pts with "newinstance", we *must* make "/dev/ptmx" a symlink to "/dev/pts/ptmx"
		symlink{NewPath: "/dev/ptmx", Target: "/dev/pts/ptmx"},
		// Note: shm is required at least for Chrome. If you don't mount
		// it chrome throws a bogus "out of memory" error, not the more
		// useful "I can't open /dev/shm/whatever". SAD!
		dir{Name: "/dev/shm", Mode: 0777},
		mount{Source: "tmpfs", Target: "/dev/shm", FSType: "tmpfs"},

		dir{Name: "/sys", Mode: 0555},
		mount{Source: "sysfs", Target: "/sys", FSType: "sysfs"},
		mount{Source: "securityfs", Target: "/sys/kernel/security", FSType: "securityfs"},
	}
	cgroupsnamespace = []creator{
		mount{Source: "cgroup", Target: "/sys/fs/cgroup", FSType: "tmpfs"},
		dir{Name: "/sys/fs/cgroup/memory", Mode: 0555},
		dir{Name: "/sys/fs/cgroup/freezer", Mode: 0555},
		dir{Name: "/sys/fs/cgroup/devices", Mode: 0555},
		dir{Name: "/sys/fs/cgroup/cpu,cpuacct", Mode: 0555},
		dir{Name: "/sys/fs/cgroup/blkio", Mode: 0555},
		dir{Name: "/sys/fs/cgroup/cpuset", Mode: 0555},
		dir{Name: "/sys/fs/cgroup/pids", Mode: 0555},
		dir{Name: "/sys/fs/cgroup/net_cls,net_prio", Mode: 0555},
		dir{Name: "/sys/fs/cgroup/hugetlb", Mode: 0555},
		dir{Name: "/sys/fs/cgroup/perf_event", Mode: 0555},
		symlink{NewPath: "/sys/fs/cgroup/cpu", Target: "/sys/fs/cgroup/cpu,cpuacct"},
		symlink{NewPath: "/sys/fs/cgroup/cpuacct", Target: "/sys/fs/cgroup/cpu,cpuacct"},
		symlink{NewPath: "/sys/fs/cgroup/net_cls", Target: "/sys/fs/cgroup/net_cls,net_prio"},
		symlink{NewPath: "/sys/fs/cgroup/net_prio", Target: "/sys/fs/cgroup/net_cls,net_prio"},
		mount{Source: "cgroup", Target: "/sys/fs/cgroup/memory", FSType: "cgroup", Opts: "memory"},
		mount{Source: "cgroup", Target: "/sys/fs/cgroup/freezer", FSType: "cgroup", Opts: "freezer"},
		mount{Source: "cgroup", Target: "/sys/fs/cgroup/devices", FSType: "cgroup", Opts: "devices"},
		mount{Source: "cgroup", Target: "/sys/fs/cgroup/cpu,cpuacct", FSType: "cgroup", Opts: "cpu,cpuacct"},
		mount{Source: "cgroup", Target: "/sys/fs/cgroup/blkio", FSType: "cgroup", Opts: "blkio"},
		mount{Source: "cgroup", Target: "/sys/fs/cgroup/cpuset", FSType: "cgroup", Opts: "cpuset"},
		mount{Source: "cgroup", Target: "/sys/fs/cgroup/pids", FSType: "cgroup", Opts: "pids"},
		mount{Source: "cgroup", Target: "/sys/fs/cgroup/net_cls,net_prio", FSType: "cgroup", Opts: "net_cls,net_prio"},
		mount{Source: "cgroup", Target: "/sys/fs/cgroup/hugetlb", FSType: "cgroup", Opts: "hugetlb"},
		mount{Source: "cgroup", Target: "/sys/fs/cgroup/perf_event", FSType: "cgroup", Opts: "perf_event"},
	}
)

func goBin() string {
	return fmt.Sprintf("/go/bin/%s_%s:/go/bin:/go/pkg/tool/%s_%s", runtime.GOOS, runtime.GOARCH, runtime.GOOS, runtime.GOARCH)
}

func create(namespace []creator) {
	// Clear umask bits so that we get stuff like ptmx right.
	m := unix.Umask(0)
	defer unix.Umask(m)
	for _, c := range namespace {
		if err := c.create(); err != nil {
			ulog.KernelLog.Printf("u-root init: error creating %s: %v", c, err)
		}
	}
}

// SetEnv sets the default u-root environment.
func SetEnv() {
	env := map[string]string{
		"LD_LIBRARY_PATH": "/usr/local/lib",
		"GOROOT":          "/go",
		"GOPATH":          "/",
		"GOBIN":           "/ubin",
		"CGO_ENABLED":     "0",
	}

	// Not all these paths may be populated or even exist but OTOH they might.
	path := "/ubin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/local/bin:/usr/local/sbin:/buildbin:/bbin"

	env["PATH"] = fmt.Sprintf("%v:%v", goBin(), path)
	for k, v := range env {
		os.Setenv(k, v)
	}
}

// CreateRootfs creates the default u-root file system.
func CreateRootfs() {
	// Mount devtmpfs, then open /dev/kmsg with Reinit.
	create(preNamespace)
	ulog.KernelLog.Reinit()

	create(namespace)

	// systemd gets upset when it discovers something has already setup cgroups
	// We have to do this after the base namespace is created, so we have /proc
	initFlags := cmdline.GetInitFlagMap()
	systemd, present := initFlags["systemd"]
	systemdEnabled, boolErr := strconv.ParseBool(systemd)
	if !present || boolErr != nil || !systemdEnabled {
		create(cgroupsnamespace)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"github.com/google/go-github/github"
	"github.com/howeyc/gopass"
	"github.com/libgit2/git2go"
	"golang.org/x/oauth2"
	"os"
	"os/exec"
	"os/user"
	"strings"
)

var client *github.Client
var passphrase string

const CLONE_PATH = "/tmp/cloned"

func main() {
	err := checkPubPrivSSHKeyExists()
	if err != nil {
		panic(err)
	}

	askForSSHPassphrase()
	accessToken := askForGithubAccessToken()

	client = githubClient(accessToken)

	allRepos := getAllRepos()
	forks := filterOnlyForks(allRepos)
	studentForks := filterOnlyStudentRepos(forks)
	duplicateRepositories(studentForks)

}

func checkPubPrivSSHKeyExists() error {
	usr, err := user.Current()
	if err != nil {
		panic(err)
	}

	publicKey := usr.HomeDir + "/.ssh/id_rsa.pub"
	privateKey := usr.HomeDir + "/.ssh/id_rsa"

	if _, err := os.Stat(publicKey); os.IsNotExist(err) {
		return fmt.Errorf("Couldn't find your public key. Looking in: %v", publicKey)
	}
	if _, err := os.Stat(usr.HomeDir + "/.ssh/id_rsa"); os.IsNotExist(err) {
		return fmt.Errorf("Couldn't find your private key. Looking in: %v", privateKey)
	}
	return nil
}

func askForSSHPassphrase() {
	fmt.Print("Enter your ssh passphrase: ")
	passphrase = string(gopass.GetPasswd())
	passphrase = strings.TrimSpace(passphrase)
}

func askForGithubAccessToken() string {
	accessToken := ""

	for accessToken == "" {
		fmt.Println("Head over to https://github.com/settings/tokens and click Generate Token")
		fmt.Print("Paste the token that is created here:")
		fmt.Scanf("%s", &accessToken)
		accessToken = strings.TrimSpace(accessToken)
	}
	return accessToken
}

func githubClient(accessToken string) *github.Client {
	oauthToken := oauth2.StaticTokenSource(
		&oauth2.Token{AccessToken: accessToken},
	)

	tc := oauth2.NewClient(oauth2.NoContext, oauthToken)
	return github.NewClient(tc)
}

func getAllRepos() []github.Repository {
	options := &github.RepositoryListOptions{
		ListOptions: github.ListOptions{PerPage: 100},
		Type:        "owner",
	}

	var allRepos []github.Repository
	fmt.Println("Getting all your repos")
	currentPage := 1
	for {
		repos, resp, err := client.Repositories.List("", options)

		fmt.Printf("Downloading Page %v of %v\n", currentPage, resp.LastPage+1)
		currentPage++

		if err != nil {
			errorMessage := fmt.Sprintf("Had trouble receiving repos: %v", err)
			panic(errorMessage)
		}

		allRepos = append(allRepos, repos...)
		if resp.NextPage == 0 {
			break
		}

		options.ListOptions.Page = resp.NextPage
	}

	fmt.Println("Finished downloading all your repos")
	return allRepos
}

func filterOnlyForks(allRepos []github.Repository) []github.Repository {
	fmt.Println("Finding only your forks")
	forks := allRepos[:0]
	for _, repo := range allRepos {
		if *repo.Fork {
			forks = append(forks, repo)
		}
	}
	fmt.Println("Found all your forks")
	return forks
}

func filterOnlyStudentRepos(resolvedRepos []github.Repository) []github.Repository {
	fmt.Println("Finding just the learn-co-students forks")
	studentForks := resolvedRepos[:0]
	for _, repo := range resolvedRepos {
		fullRepo, _, err := client.Repositories.Get(*repo.Owner.Login, *repo.Name)
		if err == nil && *fullRepo.Parent.Owner.Login == "learn-co-students" {
			studentForks = append(studentForks, repo)
		}

	}

	fmt.Println("Found your learn-co-students forks")

	return studentForks
}

func duplicateRepositories(repos []github.Repository) {
	fmt.Println("Duplicating Repos")
	for _, studentFork := range repos {
		fmt.Printf("Duplicating %v\n", *studentFork.Name)
		duplicateRepository(studentFork)
		// client.Repositories.Delete(*studentFork.Owner.Login, *studentFork.Name+"-public")
	}
	fmt.Println("Finished Duplicating")

	cleanUpCloneDir(CLONE_PATH)

}

func duplicateRepository(repo github.Repository) {
	bareCloneRepo(repo, CLONE_PATH)
	githubRepo, err := createNewPublicRepo(repo)
	if err != nil {
		panic(err)
	}
	err = mirrorPushRepoToGihub(*githubRepo, CLONE_PATH)
	if err != nil {
		fmt.Println(err)
		return
	}
}

func bareCloneRepo(repo github.Repository, clonedPath string) {
	fmt.Printf("Bare Cloning %v\n", *repo.Name)
	cloneOptions := &git.CloneOptions{
		Bare: true,
	}
	cloneOptions.FetchOptions = &git.FetchOptions{
		RemoteCallbacks: git.RemoteCallbacks{
			CredentialsCallback:      credentialsCallback,
			CertificateCheckCallback: certificateCheckCallback,
		},
	}

	exec.Command("rm", "-Rf", clonedPath).Run()
	_, err := git.Clone(*repo.SSHURL, clonedPath, cloneOptions)
	if err != nil {
		fmt.Println(err)
		return
	}
}

func createNewPublicRepo(repo github.Repository) (*github.Repository, error) {
	newRepo := &github.Repository{
		Name: github.String(*repo.Name + "-public"),
	}
	fmt.Printf("Creating New Public Repo %v\n", *newRepo.Name)
	githubRepo, _, githuberr := client.Repositories.Create("", newRepo)
	if githuberr != nil {
		err := fmt.Errorf("Having trouble print %v: error: %v", *repo.Name, githuberr)
		return nil, err
	}
	return githubRepo, nil

}

func mirrorPushRepoToGihub(repo github.Repository, clonedPath string) error {
	fmt.Printf("Pushing to %v\n", *repo.Name)
	os.Chdir(clonedPath)
	_, giterror := exec.Command("git", "push", "--mirror", *repo.SSHURL).CombinedOutput()
	if giterror != nil {
		return fmt.Errorf("Having trouble pushing repo %v. Error: %v", *repo.Name, giterror)
	}
	return nil

}

func cleanUpCloneDir(clonedPath string) {
	exec.Command("rm", "-Rf", clonedPath).Run()
}

func credentialsCallback(url string, username string, allowedTypes git.CredType) (git.ErrorCode, *git.Cred) {

	usr, err := user.Current()
	if err != nil {
		panic(err)
	}
	ret, cred := git.NewCredSshKey("git", usr.HomeDir+"/.ssh/id_rsa.pub", usr.HomeDir+"/.ssh/id_rsa", passphrase)
	return git.ErrorCode(ret), &cred
}

// Made this one just return 0 during troubleshooting...
func certificateCheckCallback(cert *git.Certificate, valid bool, hostname string) git.ErrorCode {
	return 0
}
<commit_msg>Removing ssh key check<commit_after>package main

import (
	"fmt"
	"github.com/google/go-github/github"
	"github.com/howeyc/gopass"
	"golang.org/x/oauth2"
	"os"
	"os/exec"
	"os/user"
	"strings"
)

var client *github.Client
var passphrase string

const CLONE_PATH = "/tmp/cloned"

func main() {
	err := checkPubPrivSSHKeyExists()
	if err != nil {
		panic(err)
	}

	// askForSSHPassphrase()
	accessToken := askForGithubAccessToken()

	client = githubClient(accessToken)

	allRepos := getAllRepos()
	forks := filterOnlyForks(allRepos)
	studentForks := filterOnlyStudentRepos(forks)
	duplicateRepositories(studentForks)

}

func checkPubPrivSSHKeyExists() error {
	usr, err := user.Current()
	if err != nil {
		panic(err)
	}

	publicKey := usr.HomeDir + "/.ssh/id_rsa.pub"
	privateKey := usr.HomeDir + "/.ssh/id_rsa"

	if _, err := os.Stat(publicKey); os.IsNotExist(err) {
		return fmt.Errorf("Couldn't find your public key. Looking in: %v", publicKey)
	}
	if _, err := os.Stat(usr.HomeDir + "/.ssh/id_rsa"); os.IsNotExist(err) {
		return fmt.Errorf("Couldn't find your private key. Looking in: %v", privateKey)
	}
	return nil
}

func askForSSHPassphrase() {
	fmt.Print("Enter your ssh passphrase: ")
	passphrase = string(gopass.GetPasswd())
	passphrase = strings.TrimSpace(passphrase)
}

func askForGithubAccessToken() string {
	accessToken := ""

	for accessToken == "" {
		fmt.Println("Head over to https://github.com/settings/tokens and click Generate Token")
		fmt.Print("Paste the token that is created here:")
		fmt.Scanf("%s", &accessToken)
		accessToken = strings.TrimSpace(accessToken)
	}
	return accessToken
}

func githubClient(accessToken string) *github.Client {
	oauthToken := oauth2.StaticTokenSource(
		&oauth2.Token{AccessToken: accessToken},
	)

	tc := oauth2.NewClient(oauth2.NoContext, oauthToken)
	return github.NewClient(tc)
}

func getAllRepos() []github.Repository {
	options := &github.RepositoryListOptions{
		ListOptions: github.ListOptions{PerPage: 100},
		Type:        "owner",
	}

	var allRepos []github.Repository
	fmt.Println("Getting all your repos")
	currentPage := 1
	for {
		repos, resp, err := client.Repositories.List("", options)

		fmt.Printf("Downloading Page %v of %v\n", currentPage, resp.LastPage+1)
		currentPage++

		if err != nil {
			errorMessage := fmt.Sprintf("Had trouble receiving repos: %v", err)
			panic(errorMessage)
		}

		allRepos = append(allRepos, repos...)
		if resp.NextPage == 0 {
			break
		}

		options.ListOptions.Page = resp.NextPage
	}

	fmt.Println("Finished downloading all your repos")
	return allRepos
}

func filterOnlyForks(allRepos []github.Repository) []github.Repository {
	fmt.Println("Finding only your forks")
	forks := allRepos[:0]
	for _, repo := range allRepos {
		if *repo.Fork {
			forks = append(forks, repo)
		}
	}
	fmt.Println("Found all your forks")
	return forks
}

func filterOnlyStudentRepos(resolvedRepos []github.Repository) []github.Repository {
	fmt.Println("Finding just the learn-co-students forks")
	studentForks := resolvedRepos[:0]
	for _, repo := range resolvedRepos {
		fullRepo, _, err := client.Repositories.Get(*repo.Owner.Login, *repo.Name)
		if err == nil && *fullRepo.Parent.Owner.Login == "learn-co-students" {
			studentForks = append(studentForks, repo)
		}

	}

	fmt.Println("Found your learn-co-students forks")

	return studentForks
}

func duplicateRepositories(repos []github.Repository) {
	fmt.Println("Duplicating Repos")
	for _, studentFork := range repos {
		fmt.Printf("Duplicating %v\n", *studentFork.Name)
		duplicateRepository(studentFork)
		// client.Repositories.Delete(*studentFork.Owner.Login, *studentFork.Name+"-public")
	}
	fmt.Println("Finished Duplicating")

	cleanUpCloneDir(CLONE_PATH)

}

func duplicateRepository(repo github.Repository) {
	bareCloneRepo(repo, CLONE_PATH)
	githubRepo, err := createNewPublicRepo(repo)
	if err != nil {
		panic(err)
	}
	err = mirrorPushRepoToGihub(*githubRepo, CLONE_PATH)
	if err != nil {
		fmt.Println(err)
		return
	}
}

func bareCloneRepo(repo github.Repository, clonedPath string) {
	fmt.Printf("Bare Cloning %v\n", *repo.Name)

	exec.Command("rm", "-Rf", clonedPath).Run()
	os.Chdir("/tmp")
	output, err := exec.Command("git", "clone", "--bare", *repo.SSHURL, clonedPath).CombinedOutput()
	fmt.Println(string(output))
	if err != nil {
		fmt.Println(err)
		return
	}
}

func createNewPublicRepo(repo github.Repository) (*github.Repository, error) {
	newRepo := &github.Repository{
		Name: github.String(*repo.Name + "-public"),
	}
	fmt.Printf("Creating New Public Repo %v\n", *newRepo.Name)
	githubRepo, _, githuberr := client.Repositories.Create("", newRepo)
	if githuberr != nil {
		err := fmt.Errorf("Having trouble print %v: error: %v", *repo.Name, githuberr)
		return nil, err
	}
	return githubRepo, nil

}

func mirrorPushRepoToGihub(repo github.Repository, clonedPath string) error {
	fmt.Printf("Pushing to %v\n", *repo.Name)
	os.Chdir(clonedPath)
	output, giterror := exec.Command("git", "push", "--mirror", *repo.SSHURL).CombinedOutput()
	fmt.Println(string(output))
	if giterror != nil {
		return fmt.Errorf("Having trouble pushing repo %v. Error: %v", *repo.Name, giterror)
	}
	return nil

}

func cleanUpCloneDir(clonedPath string) {
	exec.Command("rm", "-Rf", clonedPath).Run()
}
<|endoftext|>


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

package main

import (
	"fmt"
	"os"

	"github.com/danryan/hal"
	_ "github.com/danryan/hal/adapter/irc"
	_ "github.com/danryan/hal/adapter/shell"
	_ "github.com/danryan/hal/store/memory"
	_ "github.com/danryan/hal/store/redis"
)

// VERSION contians the current verison number and revison if need be
const VERSION = "2015-04-15"

// handler is an interface for objects to implement in order to respond to messages.
type handler interface {
	Handle(res *hal.Response) error
}

var helpMessages = make(map[string]string)

var pingHandler = hear(`ping`, "ping", "Causes Ash to reply with PONG", func(res *hal.Response) error {
	return res.Send("PONG")
})

var fooHandler = hear(`foo`, "foo", "Causes Ash to reply with a BAR", func(res *hal.Response) error {
	return res.Send("BAR")
})

var synHandler = hear(`SYN`, "SYN", "Causes Ash to reply with ACK", func(res *hal.Response) error {
	return res.Send("ACK")
})

var selfHandler = hear(`who are you`, "self", "", func(res *hal.Response) error {
	return res.Send("I'm Ash, the friendly #chadev bot.  I can preform a variety of tasks, and I am learning new tricks all the time.  I am open source, and pull requests are welcome!")
})

var quitHandler = hear(`(.*)+/quit(.*)+`, "quit", "", func(res *hal.Response) error {
	name := res.UserName()
	return res.Send(fmt.Sprintf("No!  Bad %s!", name))
})

var helpHandler = hear(`help`, "help", "Displays this message", func(res *hal.Response) error {
	helpMsg := []string{
		"HAL Chadev IRC Edition build: " + VERSION + "\n",
		"Supported commands:\n",
	}

	for command, message := range helpMessages {
		if command != "" && message != "" {
			helpMsg = append(helpMsg, command+" - "+message+"\n")
		}
	}

	var text string
	for _, msg := range helpMsg {
		text = text + msg
	}

	text = uploadHelpMsg(text)
	res.Send(fmt.Sprintf("My usage information can be found at %s", text))

	return nil
})

func hear(pattern string, command string, message string, fn func(res *hal.Response) error) handler {
	addHelpMessage(command, message)
	return hal.Hear("^(?i)Ash "+pattern, fn)
}

func addHelpMessage(command string, message string) {
	helpMessages[command] = message
}

func main() {
	os.Exit(run())
}

func run() int {
	robot, err := hal.NewRobot()
	if err != nil {
		hal.Logger.Error(err)
		return 1
	}

	robot.Handle(
		fooHandler,
		tableFlipHandler,
		eventHandler,
		synHandler,
		helpHandler,
		pingHandler,
		sourceHandler,
		issueHandler,
		cageMeHandler,
		whoisHandler,
		whoamHandler,
		isHandler,
		selfHandler,
		quitHandler,
		fizzBuzzHandler,
		noteStoreHandler,
		noteGetHandler,
		noteRemoveHandler,
		chadevCountHandler,
		chadevListAllHandler,
		chadevInfoHandler,
		fatherHandler,
		partyHandler,
		whoBackHandler,
		whatAreHandler,
		musicHandler,
		lunchHandler,
		talkHandler,
		addTalkHandler,
		devTalkLinkHandler,
		isAliveHandler,
	)

	if err := robot.Run(); err != nil {
		hal.Logger.Error(err)
		return 1
	}
	return 0
}
<commit_msg>Version Bump<commit_after>// Copyright 2014-2015 Chadev. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package main

import (
	"fmt"
	"os"

	"github.com/danryan/hal"
	_ "github.com/danryan/hal/adapter/irc"
	_ "github.com/danryan/hal/adapter/shell"
	_ "github.com/danryan/hal/store/memory"
	_ "github.com/danryan/hal/store/redis"
)

// VERSION contians the current verison number and revison if need be
const VERSION = "2015-04-20"

// handler is an interface for objects to implement in order to respond to messages.
type handler interface {
	Handle(res *hal.Response) error
}

var helpMessages = make(map[string]string)

var pingHandler = hear(`ping`, "ping", "Causes Ash to reply with PONG", func(res *hal.Response) error {
	return res.Send("PONG")
})

var fooHandler = hear(`foo`, "foo", "Causes Ash to reply with a BAR", func(res *hal.Response) error {
	return res.Send("BAR")
})

var synHandler = hear(`SYN`, "SYN", "Causes Ash to reply with ACK", func(res *hal.Response) error {
	return res.Send("ACK")
})

var selfHandler = hear(`who are you`, "self", "", func(res *hal.Response) error {
	return res.Send("I'm Ash, the friendly #chadev bot.  I can preform a variety of tasks, and I am learning new tricks all the time.  I am open source, and pull requests are welcome!")
})

var quitHandler = hear(`(.*)+/quit(.*)+`, "quit", "", func(res *hal.Response) error {
	name := res.UserName()
	return res.Send(fmt.Sprintf("No!  Bad %s!", name))
})

var helpHandler = hear(`help`, "help", "Displays this message", func(res *hal.Response) error {
	helpMsg := []string{
		"HAL Chadev IRC Edition build: " + VERSION + "\n",
		"Supported commands:\n",
	}

	for command, message := range helpMessages {
		if command != "" && message != "" {
			helpMsg = append(helpMsg, command+" - "+message+"\n")
		}
	}

	var text string
	for _, msg := range helpMsg {
		text = text + msg
	}

	text = uploadHelpMsg(text)
	res.Send(fmt.Sprintf("My usage information can be found at %s", text))

	return nil
})

func hear(pattern string, command string, message string, fn func(res *hal.Response) error) handler {
	addHelpMessage(command, message)
	return hal.Hear("^(?i)Ash "+pattern, fn)
}

func addHelpMessage(command string, message string) {
	helpMessages[command] = message
}

func main() {
	os.Exit(run())
}

func run() int {
	robot, err := hal.NewRobot()
	if err != nil {
		hal.Logger.Error(err)
		return 1
	}

	robot.Handle(
		fooHandler,
		tableFlipHandler,
		eventHandler,
		synHandler,
		helpHandler,
		pingHandler,
		sourceHandler,
		issueHandler,
		cageMeHandler,
		whoisHandler,
		whoamHandler,
		isHandler,
		selfHandler,
		quitHandler,
		fizzBuzzHandler,
		noteStoreHandler,
		noteGetHandler,
		noteRemoveHandler,
		chadevCountHandler,
		chadevListAllHandler,
		chadevInfoHandler,
		fatherHandler,
		partyHandler,
		whoBackHandler,
		whatAreHandler,
		musicHandler,
		lunchHandler,
		talkHandler,
		addTalkHandler,
		devTalkLinkHandler,
		isAliveHandler,
	)

	if err := robot.Run(); err != nil {
		hal.Logger.Error(err)
		return 1
	}
	return 0
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"log"
	"net/http"
	_ "net/http/pprof"
	"os"
	"os/signal"
	"regexp"
	"syscall"

	"runtime"

	"github.com/dghubble/go-twitter/twitter"
)

var configFlag = flag.String("c", "./config.json", "path to config.json")

func main() {
	os.Exit(run())
}

func run() int {
	// pprof
	runtime.SetBlockProfileRate(1)
	go func() {
		log.Println(http.ListenAndServe("localhost:6060", nil))
	}()

	log.Print("launch!")
	flag.Parse()

	// load config
	config, err := newConfig(*configFlag)
	if err != nil {
		log.Print("invalid config file:", err)
		return 1
	}

	// make twitter client
	client := newClient(config)
	sendLog := func(s string) (*twitter.DirectMessage, *http.Response, error) {
		log.Printf("send DM to author: %q", s)
		dm, resp, err := client.DirectMessages.New(&twitter.DirectMessageNewParams{
			ScreenName: config.TwitterParam.LogToScreenName,
			Text:       s,
		})
		if err != nil {
			log.Print("logging DM send error:", err)
		}
		return dm, resp, err
	}

	// make channels
	sampleStr := make(chan string, 100)
	randMorphs := make(chan Morphs, 100)
	rhymes := make(chan []Morphs, 100)

	// connect twitter sample
	stream, err := client.Streams.Sample(&twitter.StreamSampleParams{
		StallWarnings: twitter.Bool(true),
		Language:      []string{"ja"},
	})
	if err != nil {
		log.Print("cannot connect twitter stream sample", err)
		return 1
	}
	defer stream.Stop()

	demuxStrm := twitter.NewSwitchDemux()
	demuxStrm.Tweet = func(tweet *twitter.Tweet) {
		// filter
		for _, level := range config.TwitterParam.Filter {
			if tweet.FilterLevel == level {
				return
			}
		}
		if tweet.RetweetedStatus != nil {
			return
		}
		if tweet.User.FavouritesCount < 10 {
			return
		}

		// remove some invalid sentence
		url := regexp.MustCompile(`(^|\p{Zs})(http|https|ttp|ttps)://.*?($|\p{Zs})`)
		mention := regexp.MustCompile(`(^|\p{Zs}|\.)@.*?($|\p{Zs})`)
		hashtag := regexp.MustCompile(`(^|\p{Zs})(♯|＃|#).*?($|\p{Zs})`)
		toWhite := regexp.MustCompile(
			`(「|」|\[|\]|（|）|\(|\)|。|、|\,|\.|，|．|【|】|『|』|〈|〉|［|］|《|》|？|！|\?|\!|…|〜)`,
		)

		text := tweet.Text

		text = url.ReplaceAllString(text, " ")
		text = mention.ReplaceAllString(text, " ")
		text = hashtag.ReplaceAllString(text, " ")
		text = toWhite.ReplaceAllString(text, " ")

		if text == "" {
			return
		}
		for _, t := range regexp.MustCompile(`\p{Zs}.+`).Split(text, -1) {
			sampleStr <- t
		}
	}
	demuxStrm.StreamDisconnect = func(dscn *twitter.StreamDisconnect) {
		log.Printf("sample stream disconnected: code: %v, stream_name: %q, reason: %q",
			dscn.Code, dscn.Reason, dscn.StreamName)
		sendLog("sample stream disconnected")
	}
	demuxStrm.Warning = func(warning *twitter.StallWarning) {
		log.Printf("sample stream stall warning: code: %q, message: %q, percent_full: %q",
			warning.Code, warning.Message, warning.PercentFull)
	}
	demuxStrm.FriendsList = func(_ *twitter.FriendsList) {
		log.Print("stream sample connected")
	}
	go demuxStrm.HandleChan(stream.Messages)

	// tokenize tweet text
	parsedMorphs, _ := NewMorphizer(sampleStr)

	// learn Markov and generate random Morphs
	for _, param := range config.MarkovParams {
		out := MarkovServer(param, parsedMorphs)
		go func() {
			for ms := range out {
				if len(ms) == 0 {
					continue
				}
				randMorphs <- ms
			}
		}()
	}

	// generate rhymes
	for _, param := range config.RhymerParams {
		r := NewRhymer(param, randMorphs)
		out := r.Server()
		go func() {
			for rhyme := range out {
				rhymes <- rhyme
			}
		}()
	}

	// print
	go func() {
		for rhyme := range rhymes {
			for _, ms := range rhyme {
				p, _ := ms.Surface()
				fmt.Println(p)
			}
			fmt.Println("")
		}
	}()

	// ctrl+c
	sig := make(chan os.Signal, 1)
	signal.Notify(sig, syscall.SIGINT)
	<-sig
	log.Print("interrupted")

	return 0
}
<commit_msg>added buffer<commit_after>package main

import (
	"flag"
	"fmt"
	"log"
	"net/http"
	_ "net/http/pprof"
	"os"
	"os/signal"
	"regexp"
	"runtime"
	"syscall"
	"time"

	"github.com/dghubble/go-twitter/twitter"
)

var configFlag = flag.String("c", "./config.json", "path to config.json")

func main() {
	os.Exit(run())
}

func run() int {
	// pprof
	runtime.SetBlockProfileRate(1)
	go func() {
		log.Println(http.ListenAndServe("localhost:6060", nil))
	}()

	log.Print("launch!")
	flag.Parse()

	// load config
	config, err := newConfig(*configFlag)
	if err != nil {
		log.Print("invalid config file:", err)
		return 1
	}

	// make twitter client
	client := newClient(config)
	sendLog := func(s string) (*twitter.DirectMessage, *http.Response, error) {
		log.Printf("send DM to author: %q", s)
		dm, resp, err := client.DirectMessages.New(&twitter.DirectMessageNewParams{
			ScreenName: config.TwitterParam.LogToScreenName,
			Text:       s,
		})
		if err != nil {
			log.Print("logging DM send error:", err)
		}
		return dm, resp, err
	}

	// make channels
	sampleStr := make(chan string, 100)
	randMorphs := make(chan Morphs, 100)
	rhymes := make(chan []Morphs, 100)

	// connect twitter sample
	stream, err := client.Streams.Sample(&twitter.StreamSampleParams{
		StallWarnings: twitter.Bool(true),
		Language:      []string{"ja"},
	})
	if err != nil {
		log.Print("cannot connect twitter stream sample", err)
		return 1
	}
	defer stream.Stop()

	demuxStrm := twitter.NewSwitchDemux()
	demuxStrm.Tweet = func(tweet *twitter.Tweet) {
		// filter
		for _, level := range config.TwitterParam.Filter {
			if tweet.FilterLevel == level {
				return
			}
		}
		if tweet.RetweetedStatus != nil {
			return
		}
		if tweet.User.FavouritesCount < 10 {
			return
		}

		// remove some invalid sentence
		url := regexp.MustCompile(`(^|\p{Zs})(http|https|ttp|ttps)://.*?($|\p{Zs})`)
		mention := regexp.MustCompile(`(^|\p{Zs}|\.)@.*?($|\p{Zs})`)
		hashtag := regexp.MustCompile(`(^|\p{Zs})(♯|＃|#).*?($|\p{Zs})`)
		toWhite := regexp.MustCompile(
			`(「|」|\[|\]|（|）|\(|\)|。|、|\,|\.|，|．|【|】|『|』|〈|〉|［|］|《|》|？|！|\?|\!|…|〜)`,
		)

		text := tweet.Text

		text = url.ReplaceAllString(text, " ")
		text = mention.ReplaceAllString(text, " ")
		text = hashtag.ReplaceAllString(text, " ")
		text = toWhite.ReplaceAllString(text, " ")

		if text == "" {
			return
		}
		for _, t := range regexp.MustCompile(`\p{Zs}.+`).Split(text, -1) {
			sampleStr <- t
		}
	}
	demuxStrm.StreamDisconnect = func(dscn *twitter.StreamDisconnect) {
		log.Printf("sample stream disconnected: code: %v, stream_name: %q, reason: %q",
			dscn.Code, dscn.Reason, dscn.StreamName)
		sendLog("sample stream disconnected")
	}
	demuxStrm.Warning = func(warning *twitter.StallWarning) {
		log.Printf("sample stream stall warning: code: %q, message: %q, percent_full: %q",
			warning.Code, warning.Message, warning.PercentFull)
	}
	demuxStrm.FriendsList = func(_ *twitter.FriendsList) {
		log.Print("stream sample connected")
	}
	go demuxStrm.HandleChan(stream.Messages)

	// tokenize tweet text
	parsedMorphs, _ := NewMorphizer(sampleStr)

	// learn Markov and generate random Morphs
	for _, param := range config.MarkovParams {
		out := MarkovServer(param, parsedMorphs)
		go func() {
			for ms := range out {
				if len(ms) == 0 {
					continue
				}
				randMorphs <- ms
			}
		}()
	}

	// generate rhymes
	for _, param := range config.RhymerParams {
		r := NewRhymer(param, randMorphs)
		out := r.Server()
		go func() {
			for rhyme := range out {
				rhymes <- rhyme
			}
		}()
	}

	// buffer rhymes
	raps := make(chan []Morphs)
	NewStackServer(raps, rhymes, config.StackParam)

	// print
	go func() {
		for rhyme := range raps {
			for _, ms := range rhyme {
				p, _ := ms.Surface()
				fmt.Println(p)
			}
			fmt.Println("")
			time.Sleep(10 * time.Hour)
		}
	}()

	// ctrl+c
	sig := make(chan os.Signal, 1)
	signal.Notify(sig, syscall.SIGINT)
	<-sig
	log.Print("interrupted")

	return 0
}
<|endoftext|>


<commit_before>/*
Copyright 2017 The Kubernetes Authors.

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

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

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

package proto

import (
	"fmt"
	"sort"
	"strings"
)

// Defines openapi types.
const (
	Integer = "integer"
	Number  = "number"
	String  = "string"
	Boolean = "boolean"

	// These types are private as they should never leak, and are
	// represented by actual structs.
	array  = "array"
	object = "object"
)

// Models interface describe a model provider. They can give you the
// schema for a specific model.
type Models interface {
	LookupModel(string) Schema
	ListModels() []string
}

// SchemaVisitor is an interface that you need to implement if you want
// to "visit" an openapi schema. A dispatch on the Schema type will call
// the appropriate function based on its actual type:
// - Array is a list of one and only one given subtype
// - Map is a map of string to one and only one given subtype
// - Primitive can be string, integer, number and boolean.
// - Kind is an object with specific fields mapping to specific types.
// - Reference is a link to another definition.
type SchemaVisitor interface {
	VisitArray(*Array)
	VisitMap(*Map)
	VisitPrimitive(*Primitive)
	VisitKind(*Kind)
	VisitArbitrary(*Arbitrary)
	VisitReference(Reference)
}

// Schema is the base definition of an openapi type.
type Schema interface {
	// Giving a visitor here will let you visit the actual type.
	Accept(SchemaVisitor)

	// Pretty print the name of the type.
	GetName() string
	// Describes how to access this field.
	GetPath() *Path
	// Describes the field.
	GetDescription() string
	// Returns type extensions.
	GetExtensions() map[string]interface{}
}

// Path helps us keep track of type paths
type Path struct {
	parent *Path
	key    string
}

func NewPath(key string) Path {
	return Path{key: key}
}

func (p *Path) Get() []string {
	if p == nil {
		return []string{}
	}
	if p.key == "" {
		return p.parent.Get()
	}
	return append(p.parent.Get(), p.key)
}

func (p *Path) Len() int {
	return len(p.Get())
}

func (p *Path) String() string {
	return strings.Join(p.Get(), "")
}

// ArrayPath appends an array index and creates a new path
func (p *Path) ArrayPath(i int) Path {
	return Path{
		parent: p,
		key:    fmt.Sprintf("[%d]", i),
	}
}

// FieldPath appends a field name and creates a new path
func (p *Path) FieldPath(field string) Path {
	return Path{
		parent: p,
		key:    fmt.Sprintf(".%s", field),
	}
}

// BaseSchema holds data used by each types of schema.
type BaseSchema struct {
	Description string
	Extensions  map[string]interface{}

	Path Path
}

func (b *BaseSchema) GetDescription() string {
	return b.Description
}

func (b *BaseSchema) GetExtensions() map[string]interface{} {
	return b.Extensions
}

func (b *BaseSchema) GetPath() *Path {
	return &b.Path
}

// Array must have all its element of the same `SubType`.
type Array struct {
	BaseSchema

	SubType Schema
}

var _ Schema = &Array{}

func (a *Array) Accept(v SchemaVisitor) {
	v.VisitArray(a)
}

func (a *Array) GetName() string {
	return fmt.Sprintf("Array of %s", a.SubType.GetName())
}

// Kind is a complex object. It can have multiple different
// subtypes for each field, as defined in the `Fields` field. Mandatory
// fields are listed in `RequiredFields`. The key of the object is
// always of type `string`.
type Kind struct {
	BaseSchema

	// Lists names of required fields.
	RequiredFields []string
	// Maps field names to types.
	Fields map[string]Schema
}

var _ Schema = &Kind{}

func (k *Kind) Accept(v SchemaVisitor) {
	v.VisitKind(k)
}

func (k *Kind) GetName() string {
	properties := []string{}
	for key := range k.Fields {
		properties = append(properties, key)
	}
	return fmt.Sprintf("Kind(%v)", properties)
}

// IsRequired returns true if `field` is a required field for this type.
func (k *Kind) IsRequired(field string) bool {
	for _, f := range k.RequiredFields {
		if f == field {
			return true
		}
	}
	return false
}

// Keys returns a alphabetically sorted list of keys.
func (k *Kind) Keys() []string {
	keys := make([]string, 0)
	for key := range k.Fields {
		keys = append(keys, key)
	}
	sort.Strings(keys)
	return keys
}

// Map is an object who values must all be of the same `SubType`.
// The key of the object is always of type `string`.
type Map struct {
	BaseSchema

	SubType Schema
}

var _ Schema = &Map{}

func (m *Map) Accept(v SchemaVisitor) {
	v.VisitMap(m)
}

func (m *Map) GetName() string {
	return fmt.Sprintf("Map of %s", m.SubType.GetName())
}

// Primitive is a literal. There can be multiple types of primitives,
// and this subtype can be visited through the `subType` field.
type Primitive struct {
	BaseSchema

	// Type of a primitive must be one of: integer, number, string, boolean.
	Type   string
	Format string
}

var _ Schema = &Primitive{}

func (p *Primitive) Accept(v SchemaVisitor) {
	v.VisitPrimitive(p)
}

func (p *Primitive) GetName() string {
	if p.Format == "" {
		return p.Type
	}
	return fmt.Sprintf("%s (%s)", p.Type, p.Format)
}

// Arbitrary is a value of any type (primitive, object or array)
type Arbitrary struct {
	BaseSchema
}

var _ Schema = &Arbitrary{}

func (a *Arbitrary) Accept(v SchemaVisitor) {
	v.VisitArbitrary(a)
}

func (a *Arbitrary) GetName() string {
	return "Arbitrary value (primitive, object or array)"
}

// Reference implementation depends on the type of document.
type Reference interface {
	Schema

	Reference() string
	SubSchema() Schema
}
<commit_msg>remove VisitArbitrary from SchemaVisitor, make different interface<commit_after>/*
Copyright 2017 The Kubernetes Authors.

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

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

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

package proto

import (
	"fmt"
	"sort"
	"strings"
)

// Defines openapi types.
const (
	Integer = "integer"
	Number  = "number"
	String  = "string"
	Boolean = "boolean"

	// These types are private as they should never leak, and are
	// represented by actual structs.
	array  = "array"
	object = "object"
)

// Models interface describe a model provider. They can give you the
// schema for a specific model.
type Models interface {
	LookupModel(string) Schema
	ListModels() []string
}

// SchemaVisitor is an interface that you need to implement if you want
// to "visit" an openapi schema. A dispatch on the Schema type will call
// the appropriate function based on its actual type:
// - Array is a list of one and only one given subtype
// - Map is a map of string to one and only one given subtype
// - Primitive can be string, integer, number and boolean.
// - Kind is an object with specific fields mapping to specific types.
// - Reference is a link to another definition.
type SchemaVisitor interface {
	VisitArray(*Array)
	VisitMap(*Map)
	VisitPrimitive(*Primitive)
	VisitKind(*Kind)
	VisitReference(Reference)
}

// SchemaVisitorArbitrary is an additional visitor interface which handles
// arbitrary types. For backwards compatability, it's a separate interface
// which is checked for at runtime.
type SchemaVisitorArbitrary interface {
	SchemaVisitor
	VisitArbitrary(*Arbitrary)
}

// Schema is the base definition of an openapi type.
type Schema interface {
	// Giving a visitor here will let you visit the actual type.
	Accept(SchemaVisitor)

	// Pretty print the name of the type.
	GetName() string
	// Describes how to access this field.
	GetPath() *Path
	// Describes the field.
	GetDescription() string
	// Returns type extensions.
	GetExtensions() map[string]interface{}
}

// Path helps us keep track of type paths
type Path struct {
	parent *Path
	key    string
}

func NewPath(key string) Path {
	return Path{key: key}
}

func (p *Path) Get() []string {
	if p == nil {
		return []string{}
	}
	if p.key == "" {
		return p.parent.Get()
	}
	return append(p.parent.Get(), p.key)
}

func (p *Path) Len() int {
	return len(p.Get())
}

func (p *Path) String() string {
	return strings.Join(p.Get(), "")
}

// ArrayPath appends an array index and creates a new path
func (p *Path) ArrayPath(i int) Path {
	return Path{
		parent: p,
		key:    fmt.Sprintf("[%d]", i),
	}
}

// FieldPath appends a field name and creates a new path
func (p *Path) FieldPath(field string) Path {
	return Path{
		parent: p,
		key:    fmt.Sprintf(".%s", field),
	}
}

// BaseSchema holds data used by each types of schema.
type BaseSchema struct {
	Description string
	Extensions  map[string]interface{}

	Path Path
}

func (b *BaseSchema) GetDescription() string {
	return b.Description
}

func (b *BaseSchema) GetExtensions() map[string]interface{} {
	return b.Extensions
}

func (b *BaseSchema) GetPath() *Path {
	return &b.Path
}

// Array must have all its element of the same `SubType`.
type Array struct {
	BaseSchema

	SubType Schema
}

var _ Schema = &Array{}

func (a *Array) Accept(v SchemaVisitor) {
	v.VisitArray(a)
}

func (a *Array) GetName() string {
	return fmt.Sprintf("Array of %s", a.SubType.GetName())
}

// Kind is a complex object. It can have multiple different
// subtypes for each field, as defined in the `Fields` field. Mandatory
// fields are listed in `RequiredFields`. The key of the object is
// always of type `string`.
type Kind struct {
	BaseSchema

	// Lists names of required fields.
	RequiredFields []string
	// Maps field names to types.
	Fields map[string]Schema
}

var _ Schema = &Kind{}

func (k *Kind) Accept(v SchemaVisitor) {
	v.VisitKind(k)
}

func (k *Kind) GetName() string {
	properties := []string{}
	for key := range k.Fields {
		properties = append(properties, key)
	}
	return fmt.Sprintf("Kind(%v)", properties)
}

// IsRequired returns true if `field` is a required field for this type.
func (k *Kind) IsRequired(field string) bool {
	for _, f := range k.RequiredFields {
		if f == field {
			return true
		}
	}
	return false
}

// Keys returns a alphabetically sorted list of keys.
func (k *Kind) Keys() []string {
	keys := make([]string, 0)
	for key := range k.Fields {
		keys = append(keys, key)
	}
	sort.Strings(keys)
	return keys
}

// Map is an object who values must all be of the same `SubType`.
// The key of the object is always of type `string`.
type Map struct {
	BaseSchema

	SubType Schema
}

var _ Schema = &Map{}

func (m *Map) Accept(v SchemaVisitor) {
	v.VisitMap(m)
}

func (m *Map) GetName() string {
	return fmt.Sprintf("Map of %s", m.SubType.GetName())
}

// Primitive is a literal. There can be multiple types of primitives,
// and this subtype can be visited through the `subType` field.
type Primitive struct {
	BaseSchema

	// Type of a primitive must be one of: integer, number, string, boolean.
	Type   string
	Format string
}

var _ Schema = &Primitive{}

func (p *Primitive) Accept(v SchemaVisitor) {
	v.VisitPrimitive(p)
}

func (p *Primitive) GetName() string {
	if p.Format == "" {
		return p.Type
	}
	return fmt.Sprintf("%s (%s)", p.Type, p.Format)
}

// Arbitrary is a value of any type (primitive, object or array)
type Arbitrary struct {
	BaseSchema
}

var _ Schema = &Arbitrary{}

func (a *Arbitrary) Accept(v SchemaVisitor) {
	if visitor, ok := v.(SchemaVisitorArbitrary); ok {
		visitor.VisitArbitrary(a)
	}
}

func (a *Arbitrary) GetName() string {
	return "Arbitrary value (primitive, object or array)"
}

// Reference implementation depends on the type of document.
type Reference interface {
	Schema

	Reference() string
	SubSchema() Schema
}
<|endoftext|>


<commit_before>package main

import (
	"log"

	"image"

	"flag"
	"strings"

	"bytes"

	"path/filepath"

	"github.com/CirrusMD/badger/internal"
	"github.com/nfnt/resize"
	"golang.org/x/image/font/basicfont"
	gg "gopkg.in/fogleman/gg.v1"
)

const Version = "0.1.0"

var (
	mversion string
	buildNum string

	beta  bool
	alpha bool
	dark  bool

	assetPath string
)

func init() {
	log.SetFlags(0)

	flag.StringVar(&mversion, "mversion", "", "Marketing version (ex: 1.3.4)")
	flag.StringVar(&buildNum, "b", "", "Build number")

	flag.BoolVar(&beta, "beta", false, "Show beta label image in lower right corner")
	flag.BoolVar(&alpha, "alpha", false, "Show alpha label image in lower right corner")
	flag.BoolVar(&dark, "dark", false, "Show dark beta/alpha image in lower right corner. Default is a light image.")

	flag.StringVar(&assetPath, "path", ".", "Path to your icon files")
}

func main() {
	flag.Parse()

	if strings.Contains(flag.Arg(0), "version") {
		log.Println(Version)
		return
	}

	for _, imgPath := range findImages() {
		log.Printf("Badging %s...", imgPath)
		img, err := gg.LoadImage(imgPath)
		exitIf("could not open file", err)
		parent := gg.NewContextForImage(img)
		drawMarketingVersion(parent)
		drawBuildNumber(parent)
		overlayBadgeImage(parent)

		err = gg.SavePNG(imgPath, parent.Image())
		exitIf("could not save png", err)
	}
}

func findImages() []string {
	path := filepath.Join(assetPath, "*.png")
	path = filepath.Clean(path)
	images, err := filepath.Glob(path)
	exitIf("could not find images", err)
	if len(images) == 0 {
		log.Fatalf(`could not find any PNGs in path "%s"`, path)
	}

	return images
}

func drawMarketingVersion(parent *gg.Context) {
	w, h := versionDimensions(parent)
	vc := gg.NewContext(w, h)
	vc.SetHexColor("#555555")
	vc.Clear()

	vc.SetFontFace(basicfont.Face7x13)
	vc.SetRGB(1, 1, 1)
	vc.DrawStringAnchored(mversion, float64(w/2), float64(h/2), 0.5, 0.5)

	parent.DrawImage(vc.Image(), 0, 0)
}

func drawBuildNumber(parent *gg.Context) {
	w, h := versionDimensions(parent)
	vc := gg.NewContext(w, h)
	vc.SetHexColor("#f48041")
	vc.Clear()

	vc.SetFontFace(basicfont.Face7x13)
	vc.SetRGB(1, 1, 1)
	vc.DrawStringAnchored(buildNum, float64(w/2), float64(h/2), 0.5, 0.5)

	parent.DrawImage(vc.Image(), parent.Width()/2, 0)
}

func versionDimensions(dc *gg.Context) (int, int) {
	width := dc.Image().Bounds().Max.X / 2
	height := int(float64(dc.Image().Bounds().Max.Y)*0.2) - 1
	return width, height
}

func overlayBadgeImage(parent *gg.Context) {
	badge := findBadgeImage()
	if badge == nil {
		return
	}
	badge = resize.Resize(uint(parent.Width()), uint(parent.Height()), badge, resize.NearestNeighbor)
	parent.DrawImage(badge, 0, 0)
}

func findBadgeImage() image.Image {
	imgName := ""
	if alpha && dark {
		imgName = "alpha_badge_dark.png"
	} else if alpha {
		imgName = "alpha_badge_light.png"
	} else if beta && dark {
		imgName = "beta_badge_dark.png"
	} else if beta {
		imgName = "beta_badge_light.png"
	}
	if imgName == "" {
		return nil
	}
	raw, err := internal.Asset("assets/" + imgName)
	exitIf("could not load overlay image", err)

	img, _, err := image.Decode(bytes.NewReader(raw))
	exitIf("unable to decode overlay image", err)

	return img
}

func exitIf(mssg string, err error) {
	if err == nil {
		return
	}
	log.Fatalln(mssg+":", err)
}
<commit_msg>update version<commit_after>package main

import (
	"log"

	"image"

	"flag"
	"strings"

	"bytes"

	"path/filepath"

	"github.com/CirrusMD/badger/internal"
	"github.com/nfnt/resize"
	"golang.org/x/image/font/basicfont"
	gg "gopkg.in/fogleman/gg.v1"
)

const Version = "0.1.1"

var (
	mversion string
	buildNum string

	beta  bool
	alpha bool
	dark  bool

	assetPath string
)

func init() {
	log.SetFlags(0)

	flag.StringVar(&mversion, "mversion", "", "Marketing version (ex: 1.3.4)")
	flag.StringVar(&buildNum, "b", "", "Build number")

	flag.BoolVar(&beta, "beta", false, "Show beta label image in lower right corner")
	flag.BoolVar(&alpha, "alpha", false, "Show alpha label image in lower right corner")
	flag.BoolVar(&dark, "dark", false, "Show dark beta/alpha image in lower right corner. Default is a light image.")

	flag.StringVar(&assetPath, "path", ".", "Path to your icon files")
}

func main() {
	flag.Parse()

	if strings.Contains(flag.Arg(0), "version") {
		log.Println(Version)
		return
	}

	for _, imgPath := range findImages() {
		log.Printf("Badging %s...", imgPath)
		img, err := gg.LoadImage(imgPath)
		exitIf("could not open file", err)
		parent := gg.NewContextForImage(img)
		drawMarketingVersion(parent)
		drawBuildNumber(parent)
		overlayBadgeImage(parent)

		err = gg.SavePNG(imgPath, parent.Image())
		exitIf("could not save png", err)
	}
}

func findImages() []string {
	path := filepath.Join(assetPath, "*.png")
	path = filepath.Clean(path)
	images, err := filepath.Glob(path)
	exitIf("could not find images", err)
	if len(images) == 0 {
		log.Fatalf(`could not find any PNGs in path "%s"`, path)
	}

	return images
}

func drawMarketingVersion(parent *gg.Context) {
	w, h := versionDimensions(parent)
	vc := gg.NewContext(w, h)
	vc.SetHexColor("#555555")
	vc.Clear()

	vc.SetFontFace(basicfont.Face7x13)
	vc.SetRGB(1, 1, 1)
	vc.DrawStringAnchored(mversion, float64(w/2), float64(h/2), 0.5, 0.5)

	parent.DrawImage(vc.Image(), 0, 0)
}

func drawBuildNumber(parent *gg.Context) {
	w, h := versionDimensions(parent)
	vc := gg.NewContext(w, h)
	vc.SetHexColor("#f48041")
	vc.Clear()

	vc.SetFontFace(basicfont.Face7x13)
	vc.SetRGB(1, 1, 1)
	vc.DrawStringAnchored(buildNum, float64(w/2), float64(h/2), 0.5, 0.5)

	parent.DrawImage(vc.Image(), parent.Width()/2, 0)
}

func versionDimensions(dc *gg.Context) (int, int) {
	width := dc.Image().Bounds().Max.X / 2
	height := int(float64(dc.Image().Bounds().Max.Y)*0.2) - 1
	return width, height
}

func overlayBadgeImage(parent *gg.Context) {
	badge := findBadgeImage()
	if badge == nil {
		return
	}
	badge = resize.Resize(uint(parent.Width()), uint(parent.Height()), badge, resize.NearestNeighbor)
	parent.DrawImage(badge, 0, 0)
}

func findBadgeImage() image.Image {
	imgName := ""
	if alpha && dark {
		imgName = "alpha_badge_dark.png"
	} else if alpha {
		imgName = "alpha_badge_light.png"
	} else if beta && dark {
		imgName = "beta_badge_dark.png"
	} else if beta {
		imgName = "beta_badge_light.png"
	}
	if imgName == "" {
		return nil
	}
	raw, err := internal.Asset("assets/" + imgName)
	exitIf("could not load overlay image", err)

	img, _, err := image.Decode(bytes.NewReader(raw))
	exitIf("unable to decode overlay image", err)

	return img
}

func exitIf(mssg string, err error) {
	if err == nil {
		return
	}
	log.Fatalln(mssg+":", err)
}
<|endoftext|>


<commit_before>// battery-notifier:
//
// This is a simple app which notify your laptop battery state, here are the
// steps with corresponding notification:
//
// - 100% and charging will notify you to unplug
// - 80% and charging will notify you to unplug
// - 20% and discharging will notify to plug
// - 10% and discharging will notify to plug and will hibernate 1min after
//
// This app depends on:
// - [libnotify](https://developer.gnome.org/libnotify/) notify-send
// - [zzz](https://github.com/voidlinux/void-runit/blob/master/zzz) to manage hibernate
package main

import (
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"os/signal"
	"strconv"
	"syscall"
	"time"
)

const (
	capacity   = "/sys/class/power_supply/BAT0/capacity"
	status     = "/sys/class/power_supply/BAT0/status"
	hibernated = iota
	plannedHibernate
	notifyedLow
	good
	notifyedHigh
	notifyedTop
)

var (
	state = hibernated
)

func main() {
	// check Battery state every 5 sec
	ticker := time.NewTicker(1 * time.Minute)
	quit := make(chan struct{})
	go func() {
		for {
			select {
			case <-ticker.C:
				check()
			case <-quit:
				ticker.Stop()
				return
			}
		}
	}()

	// listen to syscall
	signal_chan := make(chan os.Signal, 1)
	signal.Notify(signal_chan,
		syscall.SIGHUP,
		syscall.SIGINT,
		syscall.SIGTERM,
		syscall.SIGQUIT)

	exit_chan := make(chan int)
	go func() {
		for {
			s := <-signal_chan
			switch s {
			// kill -SIGHUP XXXX
			case syscall.SIGHUP:
				fmt.Println("hungup")

			// kill -SIGINT XXXX or Ctrl+c
			case syscall.SIGINT:
				fmt.Println("Bye")
				close(quit)
				exit_chan <- 0

			// kill -SIGTERM XXXX
			case syscall.SIGTERM:
				fmt.Println("force stop")
				close(quit)
				exit_chan <- 0

			// kill -SIGQUIT XXXX
			case syscall.SIGQUIT:
				fmt.Println("stop and core dump")
				close(quit)
				exit_chan <- 0

			default:
				fmt.Println("Unknown signal.")
				close(quit)
				exit_chan <- 1
			}
		}
	}()

	code := <-exit_chan
	os.Exit(code)
}

func check() {
	c, s := getInfos()

	switch {
	case c == 100:
		switch s {
		case "Charging":
			if state < notifyedTop {
				notify("Please unplug you battery to preserve it", false)
				state = notifyedTop
			}
		case "Discharging":
			state = good
		}
	case c < 10:
		switch s {
		case "Charging":
			state = good
		case "Discharging":
			if state == plannedHibernate {
				hibernate()
			} else {
				notify(
					"Battery is under 10%, going to hibernate in 1min", true)
				state = plannedHibernate
			}
		}
	case c < 20:
		switch s {
		case "Charging":
			state = good
		case "Discharging":
			notify("Battery is under 20%, please plug it", true)
			state = notifyedLow
		}
	case c > 80:
		switch s {
		case "Charging":
			if state < notifyedHigh {
				notify("Please unplug you battery to preserve it", false)
				state = notifyedHigh
			}
		case "Discharging":
			state = good
		}
	}

	// log.Printf("Battery\tcapacity: %v\tStatus: %s\n", c, s)
}

func notify(body string, critical bool) {
	var icon string
	if critical {
		icon = "/home/scl/Pictures/icons/charge_battery_low.png"
	} else {
		icon = "/home/scl/Pictures/icons/charge_battery_ok.png"
	}
	if err := exec.Command(
		"notify-send", "-i", icon, "Battery", body).Run(); err != nil {

		log.Fatal(err)
	}

}

func hibernate() {
	if err := exec.Command("sudo", "ZZZ").Run(); err != nil {
		log.Fatal(err)
	}
}

func getInfos() (c int, s string) {
	var cap []byte
	var stat []byte
	var err error

	if cap, err = ioutil.ReadFile(capacity); err != nil {
		log.Fatal(err)
	}
	if stat, err = ioutil.ReadFile(status); err != nil {
		log.Fatal(err)
	}
	if c, err = strconv.Atoi(string(cap[:len(cap)-1])); err != nil {
		log.Fatal(err)
	}

	stat = stat[:len(stat)-1]

	return c, string(stat)
}
<commit_msg>[fix] show notification for <20 and <80 only one time<commit_after>// battery-notifier:
//
// This is a simple app which notify your laptop battery state, here are the
// steps with corresponding notification:
//
// - 100% and charging will notify you to unplug
// - 80% and charging will notify you to unplug
// - 20% and discharging will notify to plug
// - 10% and discharging will notify to plug and will hibernate 1min after
//
// This app depends on:
// - [libnotify](https://developer.gnome.org/libnotify/) notify-send
// - [zzz](https://github.com/voidlinux/void-runit/blob/master/zzz) to manage hibernate
package main

import (
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"os/signal"
	"strconv"
	"syscall"
	"time"
)

const (
	capacity   = "/sys/class/power_supply/BAT0/capacity"
	status     = "/sys/class/power_supply/BAT0/status"
	hibernated = iota
	plannedHibernate
	notifyedLow
	good
	notifyedHigh
	notifyedTop
)

var (
	state = hibernated
)

func main() {
	// check Battery state every 5 sec
	ticker := time.NewTicker(1 * time.Minute)
	quit := make(chan struct{})
	go func() {
		for {
			select {
			case <-ticker.C:
				check()
			case <-quit:
				ticker.Stop()
				return
			}
		}
	}()

	// listen to syscall
	signal_chan := make(chan os.Signal, 1)
	signal.Notify(signal_chan,
		syscall.SIGHUP,
		syscall.SIGINT,
		syscall.SIGTERM,
		syscall.SIGQUIT)

	exit_chan := make(chan int)
	go func() {
		for {
			s := <-signal_chan
			switch s {
			// kill -SIGHUP XXXX
			case syscall.SIGHUP:
				fmt.Println("hungup")

			// kill -SIGINT XXXX or Ctrl+c
			case syscall.SIGINT:
				fmt.Println("Bye")
				close(quit)
				exit_chan <- 0

			// kill -SIGTERM XXXX
			case syscall.SIGTERM:
				fmt.Println("force stop")
				close(quit)
				exit_chan <- 0

			// kill -SIGQUIT XXXX
			case syscall.SIGQUIT:
				fmt.Println("stop and core dump")
				close(quit)
				exit_chan <- 0

			default:
				fmt.Println("Unknown signal.")
				close(quit)
				exit_chan <- 1
			}
		}
	}()

	code := <-exit_chan
	os.Exit(code)
}

func check() {
	c, s := getInfos()

	switch {
	case c == 100:
		switch s {
		case "Charging":
			if state < notifyedTop {
				notify("Please unplug you battery to preserve it", false)
				state = notifyedTop
			}
		case "Discharging":
			state = good
		}
	case c < 10:
		switch s {
		case "Charging":
			state = good
		case "Discharging":
			if state == plannedHibernate {
				state = hibernated
				hibernate()
			} else {
				notify(
					"Battery is under 10%, going to hibernate in 1min", true)
				state = plannedHibernate
			}
		}
	case c < 20:
		switch s {
		case "Charging":
			state = good
		case "Discharging":
			if state != notifyedLow {
				notify("Battery is under 20%, please plug it", true)
				state = notifyedLow
			}
		}
	case c > 80:
		switch s {
		case "Charging":
			if state != notifyedHigh {
				notify("Please unplug you battery to preserve it", false)
				state = notifyedHigh
			}
		case "Discharging":
			state = good
		}
	}

	// log.Printf("Battery\tcapacity: %v\tStatus: %s\n", c, s)
}

func notify(body string, critical bool) {
	var icon string
	if critical {
		icon = "/home/scl/Pictures/icons/charge_battery_low.png"
	} else {
		icon = "/home/scl/Pictures/icons/charge_battery_ok.png"
	}
	if err := exec.Command(
		"notify-send", "-i", icon, "Battery", body).Run(); err != nil {

		log.Fatal(err)
	}

}

func hibernate() {
	if err := exec.Command("sudo", "ZZZ").Run(); err != nil {
		log.Fatal(err)
	}
}

func getInfos() (c int, s string) {
	var cap []byte
	var stat []byte
	var err error

	if cap, err = ioutil.ReadFile(capacity); err != nil {
		log.Fatal(err)
	}
	if stat, err = ioutil.ReadFile(status); err != nil {
		log.Fatal(err)
	}
	if c, err = strconv.Atoi(string(cap[:len(cap)-1])); err != nil {
		log.Fatal(err)
	}

	stat = stat[:len(stat)-1]

	return c, string(stat)
}
<|endoftext|>