func cmdSetOption(cmd *cobra.Command, args []string) error {
	if len(args) < 2 {
		printResponse(cmd, args, response{
			Code: codeBad,
			Log:  "want at least arguments of the form: <key> <value>",
		})
		return nil
	}
	key, val := args[0], args[1]
	_, err := client.SetOptionSync(types.RequestSetOption{Key: key, Value: val})
	if err != nil {
		return err
	}
	printResponse(cmd, args, response{Log: "OK (SetOption doesn't return anything.)"})  
	return nil
}
Set an option on the application
package main
import (
	"bufio"
	"encoding/hex"
	"errors"
	"fmt"
	"io"
	"os"
	"strings"
	"github.com/spf13/cobra"
	"github.com/line/ostracon/libs/log"
	tmos "github.com/line/ostracon/libs/os"
	abcicli "github.com/line/ostracon/abci/client"
	"github.com/line/ostracon/abci/example/code"
	"github.com/line/ostracon/abci/example/counter"
	"github.com/line/ostracon/abci/example/kvstore"
	"github.com/line/ostracon/abci/server"
	servertest "github.com/line/ostracon/abci/tests/server"
	"github.com/line/ostracon/abci/types"
	"github.com/line/ostracon/abci/version"
	"github.com/line/ostracon/proto/ostracon/crypto"
)
var (
	client abcicli.Client
	logger log.Logger
)
var (
	flagAddress  string
	flagAbci     string
	flagVerbose  bool    
	flagLogLevel string  
	flagPath   string
	flagHeight int
	flagProve  bool
	flagSerial bool
	flagPersist string
)
var RootCmd = &cobra.Command{
	Use:   "abci-cli",
	Short: "the ABCI CLI tool wraps an ABCI client",
	Long:  "the ABCI CLI tool wraps an ABCI client and is used for testing ABCI servers",
	PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
		switch cmd.Use {
		case "counter", "kvstore":  
			return nil
		case "version":  
			return nil
		}
		if logger == nil {
			allowLevel, err := log.AllowLevel(flagLogLevel)
			if err != nil {
				return err
			}
			logger = log.NewFilter(log.NewOCLogger(log.NewSyncWriter(os.Stdout)), allowLevel)
		}
		if client == nil {
			var err error
			client, err = abcicli.NewClient(flagAddress, flagAbci, false)
			if err != nil {
				return err
			}
			client.SetLogger(logger.With("module", "abci-client"))
			if err := client.Start(); err != nil {
				return err
			}
		}
		return nil
	},
}
type response struct {
	Data []byte
	Code uint32
	Info string
	Log  string
	Query *queryResponse
}
type queryResponse struct {
	Key      []byte
	Value    []byte
	Height   int64
	ProofOps *crypto.ProofOps
}
func Execute() error {
	addGlobalFlags()
	addCommands()
	return RootCmd.Execute()
}
func addGlobalFlags() {
	RootCmd.PersistentFlags().StringVarP(&flagAddress,
		"address",
		"",
		"tcp://0.0.0.0:26658",
		"address of application socket")
	RootCmd.PersistentFlags().StringVarP(&flagAbci, "abci", "", "socket", "either socket or grpc")
	RootCmd.PersistentFlags().BoolVarP(&flagVerbose,
		"verbose",
		"v",
		false,
		"print the command and results as if it were a console session")
	RootCmd.PersistentFlags().StringVarP(&flagLogLevel, "log_level", "", "debug", "set the logger level")
}
func addQueryFlags() {
	queryCmd.PersistentFlags().StringVarP(&flagPath, "path", "", "/store", "path to prefix query with")
	queryCmd.PersistentFlags().IntVarP(&flagHeight, "height", "", 0, "height to query the blockchain at")
	queryCmd.PersistentFlags().BoolVarP(&flagProve,
		"prove",
		"",
		false,
		"whether or not to return a merkle proof of the query result")
}
func addCounterFlags() {
	counterCmd.PersistentFlags().BoolVarP(&flagSerial, "serial", "", false, "enforce incrementing (serial) transactions")
}
func addKVStoreFlags() {
	kvstoreCmd.PersistentFlags().StringVarP(&flagPersist, "persist", "", "", "directory to use for a database")
}
func addCommands() {
	RootCmd.AddCommand(batchCmd)
	RootCmd.AddCommand(consoleCmd)
	RootCmd.AddCommand(echoCmd)
	RootCmd.AddCommand(infoCmd)
	RootCmd.AddCommand(setOptionCmd)
	RootCmd.AddCommand(deliverTxCmd)
	RootCmd.AddCommand(checkTxCmd)
	RootCmd.AddCommand(commitCmd)
	RootCmd.AddCommand(versionCmd)
	RootCmd.AddCommand(testCmd)
	addQueryFlags()
	RootCmd.AddCommand(queryCmd)
	addCounterFlags()
	RootCmd.AddCommand(counterCmd)
	addKVStoreFlags()
	RootCmd.AddCommand(kvstoreCmd)
}
var batchCmd = &cobra.Command{
	Use:   "batch",
	Short: "run a batch of abci commands against an application",
	Long: `run a batch of abci commands against an application
This command is run by piping in a file containing a series of commands
you'd like to run:
    abci-cli batch < example.file
where example.file looks something like:
    set_option serial on
    check_tx 0x00
    check_tx 0xff
    deliver_tx 0x00
    check_tx 0x00
    deliver_tx 0x01
    deliver_tx 0x04
    info
`,
	Args: cobra.ExactArgs(0),
	RunE: cmdBatch,
}
var consoleCmd = &cobra.Command{
	Use:   "console",
	Short: "start an interactive ABCI console for multiple commands",
	Long: `start an interactive ABCI console for multiple commands
This command opens an interactive console for running any of the other commands
without opening a new connection each time
`,
	Args:      cobra.ExactArgs(0),
	ValidArgs: []string{"echo", "info", "set_option", "deliver_tx", "check_tx", "commit", "query"},
	RunE:      cmdConsole,
}
var echoCmd = &cobra.Command{
	Use:   "echo",
	Short: "have the application echo a message",
	Long:  "have the application echo a message",
	Args:  cobra.ExactArgs(1),
	RunE:  cmdEcho,
}
var infoCmd = &cobra.Command{
	Use:   "info",
	Short: "get some info about the application",
	Long:  "get some info about the application",
	Args:  cobra.ExactArgs(0),
	RunE:  cmdInfo,
}
var setOptionCmd = &cobra.Command{
	Use:   "set_option",
	Short: "set an option on the application",
	Long:  "set an option on the application",
	Args:  cobra.ExactArgs(2),
	RunE:  cmdSetOption,
}
var deliverTxCmd = &cobra.Command{
	Use:   "deliver_tx",
	Short: "deliver a new transaction to the application",
	Long:  "deliver a new transaction to the application",
	Args:  cobra.ExactArgs(1),
	RunE:  cmdDeliverTx,
}
var checkTxCmd = &cobra.Command{
	Use:   "check_tx",
	Short: "validate a transaction",
	Long:  "validate a transaction",
	Args:  cobra.ExactArgs(1),
	RunE:  cmdCheckTx,
}
var commitCmd = &cobra.Command{
	Use:   "commit",
	Short: "commit the application state and return the Merkle root hash",
	Long:  "commit the application state and return the Merkle root hash",
	Args:  cobra.ExactArgs(0),
	RunE:  cmdCommit,
}
var versionCmd = &cobra.Command{
	Use:   "version",
	Short: "print ABCI console version",
	Long:  "print ABCI console version",
	Args:  cobra.ExactArgs(0),
	RunE: func(cmd *cobra.Command, args []string) error {
		fmt.Println(version.Version)
		return nil
	},
}
var queryCmd = &cobra.Command{
	Use:   "query",
	Short: "query the application state",
	Long:  "query the application state",
	Args:  cobra.ExactArgs(1),
	RunE:  cmdQuery,
}
var counterCmd = &cobra.Command{
	Use:   "counter",
	Short: "ABCI demo example",
	Long:  "ABCI demo example",
	Args:  cobra.ExactArgs(0),
	RunE:  cmdCounter,
}
var kvstoreCmd = &cobra.Command{
	Use:   "kvstore",
	Short: "ABCI demo example",
	Long:  "ABCI demo example",
	Args:  cobra.ExactArgs(0),
	RunE:  cmdKVStore,
}
var testCmd = &cobra.Command{
	Use:   "test",
	Short: "run integration tests",
	Long:  "run integration tests",
	Args:  cobra.ExactArgs(0),
	RunE:  cmdTest,
}
func persistentArgs(line []byte) []string {
	args := os.Args
	args = args[:len(args)-1]  
	if len(line) > 0 {  
		args = append(args, strings.Split(string(line), " ")...)
	}
	return args
}
func compose(fs []func() error) error {
	if len(fs) == 0 {
		return nil
	}
	err := fs[0]()
	if err == nil {
		return compose(fs[1:])
	}
	return err
}
func cmdTest(cmd *cobra.Command, args []string) error {
	return compose(
		[]func() error{
			func() error { return servertest.InitChain(client) },
			func() error { return servertest.SetOption(client, "serial", "on") },
			func() error { return servertest.Commit(client, nil) },
			func() error { return servertest.DeliverTx(client, []byte("abc"), code.CodeTypeBadNonce, nil) },
			func() error { return servertest.Commit(client, nil) },
			func() error { return servertest.DeliverTx(client, []byte{0x00}, code.CodeTypeOK, nil) },
			func() error { return servertest.Commit(client, []byte{0, 0, 0, 0, 0, 0, 0, 1}) },
			func() error { return servertest.DeliverTx(client, []byte{0x00}, code.CodeTypeBadNonce, nil) },
			func() error { return servertest.DeliverTx(client, []byte{0x01}, code.CodeTypeOK, nil) },
			func() error { return servertest.DeliverTx(client, []byte{0x00, 0x02}, code.CodeTypeOK, nil) },
			func() error { return servertest.DeliverTx(client, []byte{0x00, 0x03}, code.CodeTypeOK, nil) },
			func() error { return servertest.DeliverTx(client, []byte{0x00, 0x00, 0x04}, code.CodeTypeOK, nil) },
			func() error {
				return servertest.DeliverTx(client, []byte{0x00, 0x00, 0x06}, code.CodeTypeBadNonce, nil)
			},
			func() error { return servertest.Commit(client, []byte{0, 0, 0, 0, 0, 0, 0, 5}) },
		})
}
func cmdBatch(cmd *cobra.Command, args []string) error {
	bufReader := bufio.NewReader(os.Stdin)
LOOP:
	for {
		line, more, err := bufReader.ReadLine()
		switch {
		case more:
			return errors.New("input line is too long")
		case err == io.EOF:
			break LOOP
		case len(line) == 0:
			continue
		case err != nil:
			return err
		}
		cmdArgs := persistentArgs(line)
		if err := muxOnCommands(cmd, cmdArgs); err != nil {
			return err
		}
		fmt.Println()
	}
	return nil
}
func cmdConsole(cmd *cobra.Command, args []string) error {
	for {
		fmt.Printf("> ")
		bufReader := bufio.NewReader(os.Stdin)
		line, more, err := bufReader.ReadLine()
		if more {
			return errors.New("input is too long")
		} else if err != nil {
			return err
		}
		pArgs := persistentArgs(line)
		if err := muxOnCommands(cmd, pArgs); err != nil {
			return err
		}
	}
}
func muxOnCommands(cmd *cobra.Command, pArgs []string) error {
	if len(pArgs) < 2 {
		return errors.New("expecting persistent args of the form: abci-cli [command] <...>")
	}
	args := []string{}
	for i := 0; i < len(pArgs); i++ {
		arg := pArgs[i]
		if strings.HasPrefix(arg, "-") {
			if strings.Contains(arg, "=") {
				continue
			}
			_, err := cmd.Flags().GetBool(strings.TrimLeft(arg, "-"))
			if err == nil {
				continue
			}
			i++
			continue
		}
		args = append(args, arg)
	}
	var subCommand string
	var actualArgs []string
	if len(args) > 1 {
		subCommand = args[1]
	}
	if len(args) > 2 {
		actualArgs = args[2:]
	}
	cmd.Use = subCommand  
	switch strings.ToLower(subCommand) {
	case "check_tx":
		return cmdCheckTx(cmd, actualArgs)
	case "commit":
		return cmdCommit(cmd, actualArgs)
	case "deliver_tx":
		return cmdDeliverTx(cmd, actualArgs)
	case "echo":
		return cmdEcho(cmd, actualArgs)
	case "info":
		return cmdInfo(cmd, actualArgs)
	case "query":
		return cmdQuery(cmd, actualArgs)
	case "set_option":
		return cmdSetOption(cmd, actualArgs)
	default:
		return cmdUnimplemented(cmd, pArgs)
	}
}
func cmdUnimplemented(cmd *cobra.Command, args []string) error {
	msg := "unimplemented command"
	if len(args) > 0 {
		msg += fmt.Sprintf(" args: [%s]", strings.Join(args, " "))
	}
	printResponse(cmd, args, response{
		Code: codeBad,
		Log:  msg,
	})
	fmt.Println("Available commands:")
	fmt.Printf("%s: %s\n", echoCmd.Use, echoCmd.Short)
	fmt.Printf("%s: %s\n", infoCmd.Use, infoCmd.Short)
	fmt.Printf("%s: %s\n", checkTxCmd.Use, checkTxCmd.Short)
	fmt.Printf("%s: %s\n", deliverTxCmd.Use, deliverTxCmd.Short)
	fmt.Printf("%s: %s\n", queryCmd.Use, queryCmd.Short)
	fmt.Printf("%s: %s\n", commitCmd.Use, commitCmd.Short)
	fmt.Printf("%s: %s\n", setOptionCmd.Use, setOptionCmd.Short)
	fmt.Println("Use \"[command] --help\" for more information about a command.")
	return nil
}
func cmdEcho(cmd *cobra.Command, args []string) error {
	msg := ""
	if len(args) > 0 {
		msg = args[0]
	}
	res, err := client.EchoSync(msg)
	if err != nil {
		return err
	}
	printResponse(cmd, args, response{
		Data: []byte(res.Message),
	})
	return nil
}
func cmdInfo(cmd *cobra.Command, args []string) error {
	var version string
	if len(args) == 1 {
		version = args[0]
	}
	res, err := client.InfoSync(types.RequestInfo{Version: version})
	if err != nil {
		return err
	}
	printResponse(cmd, args, response{
		Data: []byte(res.Data),
	})
	return nil
}
const codeBad uint32 = 10