func GenerateMarkdownDocFromFlagSets(flagSets []*flag_.FlagSet, output io.Writer, serviceName string) {
	escapeColumn := func(text string) string {
		return strings.Replace(text, "|", "\\|", -1)
	}
	fmt.Fprintf(output, "|%v|||||\n|:-:|:-:|:-:|:-:|:-:|\n", serviceName)
	visitFlagSets(flagSets, func(flag *flag_.Flag) {
		fmt.Fprintf(output, "||%v||%v|%v|\n", flag.Name, flag.DefValue, escapeColumn(flag.Usage))
	})
}
GenerateMarkdownDocFromFlagSets generates Markdown file from CLI flag sets.
package cmd
import (
	"context"
	"errors"
	flag_ "flag"
	"fmt"
	"github.com/cossacklabs/acra/logging"
	"io"
	"io/ioutil"
	"net"
	"os"
	"os/signal"
	"path/filepath"
	"reflect"
	"encoding/base64"
	"github.com/cossacklabs/acra/keystore"
	"github.com/cossacklabs/acra/utils"
	log "github.com/sirupsen/logrus"
	"gopkg.in/yaml.v2"
	"math/rand"
	"strconv"
	"strings"
	"time"
)
var (
	config                   = flag_.String("config_file", "", "path to config")
	dumpconfig               = flag_.Bool("dump_config", false, "dump config")
	generateMarkdownArgTable = flag_.Bool("generate_markdown_args_table", false, "Generate with yaml config markdown text file with descriptions of all args")
)
var (
	ErrDumpRequested = errors.New("configurtion dump requested")
)
func init() {
	flag_.CommandLine.Usage = func() {
		PrintFlags(flag_.CommandLine)
	}
}
type SignalCallback func()
type SignalHandler struct {
	ch        chan os.Signal
	listeners []net.Listener
	callbacks []SignalCallback
	signals   []os.Signal
}
func NewSignalHandler(handledSignals []os.Signal) (*SignalHandler, error) {
	return &SignalHandler{ch: make(chan os.Signal), signals: handledSignals}, nil
}
func (handler *SignalHandler) AddListener(listener net.Listener) {
	handler.listeners = append(handler.listeners, listener)
}
func (handler *SignalHandler) GetChannel() chan os.Signal {
	return handler.ch
}
func (handler *SignalHandler) AddCallback(callback SignalCallback) {
	handler.callbacks = append(handler.callbacks, callback)
}
func (handler *SignalHandler) Register() {
	signal.Notify(handler.ch, handler.signals...)
	<-handler.ch
	for _, listener := range handler.listeners {
		listener.Close()
	}
	for _, callback := range handler.callbacks {
		callback()
	}
	os.Exit(0)
}
func (handler *SignalHandler) RegisterWithContext(globalContext context.Context) {
	signal.Notify(handler.ch, handler.signals...)
	for {
		select {
		case <-handler.ch:
			for _, listener := range handler.listeners {
				listener.Close()
			}
			for _, callback := range handler.callbacks {
				callback()
			}
		case <-globalContext.Done():
			return
		}
	}
}
func ValidateClientID(clientID string) {
	if !keystore.ValidateID([]byte(clientID)) {
		log.WithField(logging.FieldKeyEventCode, logging.EventCodeErrorInvalidClientID).Errorf(
			"Invalid client ID,  %d <= len(client ID) <= %d, only digits, letters and '_', '-', ' ' characters",
			keystore.MinClientIDLength, keystore.MaxClientIDLength)
		os.Exit(1)
	}
}
func isZeroValue(flag *flag_.Flag, value string) bool {
	typ := reflect.TypeOf(flag.Value)
	var z reflect.Value
	if typ.Kind() == reflect.Ptr {
		z = reflect.New(typ.Elem())
	} else {
		z = reflect.Zero(typ)
	}
	if value == z.Interface().(flag_.Value).String() {
		return true
	}
	switch value {
	case "false":
		return true
	case "":
		return true
	case "0":
		return true
	}
	return false
}
func PrintFlags(flags *flag_.FlagSet) {
	flags.VisitAll(func(flag *flag_.Flag) {
		var s string
		if len(flag.Name) > 2 {
			s = fmt.Sprintf("  --%s", flag.Name)  
		} else {
			s = fmt.Sprintf("  -%s", flag.Name)  
		}
		if len(s) <= 4 {
			s += "\t"
		} else {
			s += "\n    \t"
		}
		s += flag.Usage
		if !isZeroValue(flag, flag.DefValue) {
			getter, ok := flag.Value.(flag_.Getter)
			if !ok {
				return
			}
			if _, ok := getter.Get().(string); ok {
				s += fmt.Sprintf(" (default %q)", flag.DefValue)
			} else {
				s += fmt.Sprintf(" (default %v)", flag.DefValue)
			}
		}
		fmt.Fprint(os.Stderr, s, "\n")
	})
}
func visitFlagSets(flagSets []*flag_.FlagSet, visit func(flag *flag_.Flag)) {
	seenNames := make(map[string]struct{})
	for _, flags := range flagSets {
		flags.VisitAll(func(flag *flag_.Flag) {
			if _, visited := seenNames[flag.Name]; !visited {
				visit(flag)
				seenNames[flag.Name] = struct{}{}
			}
		})
	}
}
func GenerateYaml(output io.Writer, useDefault bool) {
	GenerateYamlFromFlagSets([]*flag_.FlagSet{flag_.CommandLine}, output, useDefault)
}
func GenerateYamlFromFlagSets(flagSets []*flag_.FlagSet, output io.Writer, useDefault bool) {
	if _, err := fmt.Fprintf(output, "version: %s\n", utils.VERSION); err != nil {
		panic(err)
	}
	visitFlagSets(flagSets, func(flag *flag_.Flag) {
		var s string
		if useDefault {
			s = fmt.Sprintf("# %v\n%v: %v\n", flag.Usage, flag.Name, flag.DefValue)
		} else {
			s = fmt.Sprintf("# %v\n%v: %v\n", flag.Usage, flag.Name, flag.Value)
		}
		fmt.Fprint(output, s, "\n")
	})
}
func GenerateMarkdownDoc(output io.Writer, serviceName string) {
	GenerateMarkdownDocFromFlagSets([]*flag_.FlagSet{flag_.CommandLine}, output, serviceName)
}