This is an automated email from the ASF dual-hosted git repository.

laiyingchun pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-pegasus.git


The following commit(s) were added to refs/heads/master by this push:
     new 2d247a12 chore: Merge repo pegasus-kv/pegic (#960)
2d247a12 is described below

commit 2d247a120af3e48bd8b75e26f9f429d97b41cdeb
Author: Yingchun Lai <[email protected]>
AuthorDate: Wed Apr 27 17:52:29 2022 +0800

    chore: Merge repo pegasus-kv/pegic (#960)
---
 ...-request-go.yml => lint_and_test_admin-cli.yml} |   6 +-
 ...yml => lint_and_test_admin-cli_always_pass.yml} |   8 +-
 ...pull-request-go.yml => lint_and_test_pegic.yml} |  19 +-
 ...ild.yml => lint_and_test_pegic_always_pass.yml} |  44 ++-
 .gitignore                                         |   4 +-
 .licenserc.yaml                                    |   1 +
 .../.goreleaser.yml                                |  44 +--
 pegic/Makefile                                     |  20 +
 pegic/README.md                                    | 253 ++++++++++++
 .../check_and_format.sh                            |  43 +-
 pegic/executor/context.go                          | 137 +++++++
 pegic/executor/del.go                              |  42 ++
 pegic/executor/get.go                              |  59 +++
 pegic/executor/partition_index.go                  |  65 +++
 pegic/executor/scan.go                             | 149 +++++++
 pegic/executor/set.go                              |  42 ++
 pegic/executor/util/asciihex.go                    |  94 +++++
 pegic/executor/util/compression.go                 |  74 ++++
 pegic/executor/util/encoding.go                    | 163 ++++++++
 pegic/executor/util/javabytes.go                   |  57 +++
 pegic/go.mod                                       |  34 ++
 pegic/go.sum                                       | 439 +++++++++++++++++++++
 pegic/interactive/cmd/compression.go               |  77 ++++
 pegic/interactive/cmd/del.go                       |  46 +++
 pegic/interactive/cmd/encoding.go                  | 111 ++++++
 pegic/interactive/cmd/get.go                       |  45 +++
 pegic/interactive/cmd/init.go                      |  76 ++++
 pegic/interactive/cmd/partition_index.go           |  51 +++
 pegic/interactive/cmd/scan.go                      | 117 ++++++
 pegic/interactive/cmd/set.go                       |  47 +++
 pegic/interactive/cmd/use.go                       |  63 +++
 pegic/interactive/run.go                           |  48 +++
 pegic/main.go                                      |  45 +++
 pegic/shell/app.go                                 |  55 +++
 pegic/shell/convert.go                             |  68 ++++
 rdsn                                               |   2 +-
 36 files changed, 2544 insertions(+), 104 deletions(-)

diff --git a/.github/workflows/pull-request-go.yml 
b/.github/workflows/lint_and_test_admin-cli.yml
similarity index 96%
copy from .github/workflows/pull-request-go.yml
copy to .github/workflows/lint_and_test_admin-cli.yml
index b474f812..c6e8dcfe 100644
--- a/.github/workflows/pull-request-go.yml
+++ b/.github/workflows/lint_and_test_admin-cli.yml
@@ -16,7 +16,7 @@
 # under the License.
 ---
 # workflow name
-name: Golang Lint and Unit Test
+name: Golang Lint and Unit Test - admin-cli
 
 # on events
 on:
@@ -37,7 +37,7 @@ on:
 # workflow tasks
 jobs:
   lint:
-    name: Golang Lint
+    name: Lint
     runs-on: ubuntu-latest
     steps:
       - uses: actions/checkout@v2
@@ -50,7 +50,7 @@ jobs:
           working-directory: ./admin-cli
 
   build:
-    name: Golang Test
+    name: Test
     runs-on: ubuntu-latest
     steps:
       - name: Checkout
diff --git a/.github/workflows/pull-request-go-always-pass.yml 
b/.github/workflows/lint_and_test_admin-cli_always_pass.yml
similarity index 93%
copy from .github/workflows/pull-request-go-always-pass.yml
copy to .github/workflows/lint_and_test_admin-cli_always_pass.yml
index bf2a4996..5189678d 100644
--- a/.github/workflows/pull-request-go-always-pass.yml
+++ b/.github/workflows/lint_and_test_admin-cli_always_pass.yml
@@ -16,7 +16,7 @@
 # under the License.
 ---
 # workflow name
-name: Golang Lint and Unit Test
+name: Golang Lint and Unit Test - admin-cli
 
 # on events
 on:
@@ -28,7 +28,7 @@ on:
       - 'v[0-9]+.*' # release branch
       - ci-test # testing branch for github action
       - '*dev'
-    paths:
+    paths-ignore:
       - admin-cli/**
 
   # for manually triggering workflow
@@ -37,13 +37,13 @@ on:
 # workflow tasks
 jobs:
   lint:
-    name: Golang Lint
+    name: Lint
     runs-on: ubuntu-latest
     steps:
       - run: 'echo "No build required" '
 
   build:
-    name: Golang Test
+    name: Test
     runs-on: ubuntu-latest
     steps:
       - run: 'echo "No build required" '
diff --git a/.github/workflows/pull-request-go.yml 
b/.github/workflows/lint_and_test_pegic.yml
similarity index 83%
rename from .github/workflows/pull-request-go.yml
rename to .github/workflows/lint_and_test_pegic.yml
index b474f812..d193252d 100644
--- a/.github/workflows/pull-request-go.yml
+++ b/.github/workflows/lint_and_test_pegic.yml
@@ -16,20 +16,20 @@
 # under the License.
 ---
 # workflow name
-name: Golang Lint and Unit Test
+name: Golang Lint and Unit Test - pegic
 
 # on events
 on:
   # run on each pull request
   pull_request:
-    types: [ synchronize, opened, reopened ]
+    types: [ synchronize, reopened, opened ]
     branches:
       - master
       - 'v[0-9]+.*' # release branch
       - ci-test # testing branch for github action
       - '*dev'
     paths:
-      - admin-cli/**
+      - pegic/**
 
   # for manually triggering workflow
   workflow_dispatch:
@@ -37,7 +37,7 @@ on:
 # workflow tasks
 jobs:
   lint:
-    name: Golang Lint
+    name: Lint
     runs-on: ubuntu-latest
     steps:
       - uses: actions/checkout@v2
@@ -47,10 +47,10 @@ jobs:
         uses: golangci/golangci-lint-action@v3
         with:
           version: v1.29
-          working-directory: ./admin-cli
+          working-directory: ./pegic
 
   build:
-    name: Golang Test
+    name: Test
     runs-on: ubuntu-latest
     steps:
       - name: Checkout
@@ -61,9 +61,6 @@ jobs:
         uses: actions/setup-go@v2
         with:
           go-version: 1.14
-      - name: Compile
-        working-directory: ./admin-cli
+      - name: Compile 
+        working-directory: ./pegic
         run: make
-      - name: Test
-        working-directory: ./admin-cli
-        run: make test
diff --git a/.github/workflows/cross-build.yml 
b/.github/workflows/lint_and_test_pegic_always_pass.yml
similarity index 62%
rename from .github/workflows/cross-build.yml
rename to .github/workflows/lint_and_test_pegic_always_pass.yml
index 407e68e2..f4ab4929 100644
--- a/.github/workflows/cross-build.yml
+++ b/.github/workflows/lint_and_test_pegic_always_pass.yml
@@ -16,32 +16,34 @@
 # under the License.
 ---
 # workflow name
-name: Generate release-artifacts
+name: Golang Lint and Unit Test - pegic
 
 # on events
 on:
-  release:
-    types: 
-        - created
+  # run on each pull request
+  pull_request:
+    types: [ synchronize, opened, reopened ]
+    branches:
+      - master
+      - 'v[0-9]+.*' # release branch
+      - ci-test # testing branch for github action
+      - '*dev'
+    paths-ignore:
+      - pegic/**
+
+  # for manually triggering workflow
+  workflow_dispatch:
 
 # workflow tasks
 jobs:
-  goreleaser:
+  lint:
+    name: Lint
+    runs-on: ubuntu-latest
+    steps:
+      - run: 'echo "No build required" '
+
+  build:
+    name: Test
     runs-on: ubuntu-latest
     steps:
-      - name: Checkout
-        uses: actions/checkout@v2
-        with:
-          fetch-depth: 0
-      - name: Set up Go
-        uses: actions/setup-go@v2
-        with:
-          go-version: 1.14
-      - name: Run GoReleaser
-        uses: goreleaser/goreleaser-action@v2
-        with:
-          workdir: ./admin-cli
-          version: latest
-          args: release --rm-dist
-        env:
-          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+      - run: 'echo "No build required" '
diff --git a/.gitignore b/.gitignore
index 749cab97..6ef6753e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -106,9 +106,8 @@ LOG
 
 .vscode/
 .history/
-.admin-cli-history
+.*-history
 
-.shell-history
 PACKAGE
 scripts/py_utils/*.pyc
 cmake-build-debug
@@ -121,4 +120,5 @@ pegasus-server*
 *.log
 
 admin-cli/bin/
+pegic/bin/
 golangci-*
diff --git a/.licenserc.yaml b/.licenserc.yaml
index 94ef4d3a..036af421 100644
--- a/.licenserc.yaml
+++ b/.licenserc.yaml
@@ -37,5 +37,6 @@ header:
     - 'src/shell/sds/sds.h'
     - 'src/shell/sds/sdsalloc.h'
     - 'admin-cli/go.sum'
+    - 'pegic/go.sum'
 
   comment: on-failure
diff --git a/.github/workflows/pull-request-go-always-pass.yml 
b/pegic/.goreleaser.yml
similarity index 55%
copy from .github/workflows/pull-request-go-always-pass.yml
copy to pegic/.goreleaser.yml
index bf2a4996..fc721c7d 100644
--- a/.github/workflows/pull-request-go-always-pass.yml
+++ b/pegic/.goreleaser.yml
@@ -15,35 +15,15 @@
 # specific language governing permissions and limitations
 # under the License.
 ---
-# workflow name
-name: Golang Lint and Unit Test
-
-# on events
-on:
-  # run on each pull request
-  pull_request:
-    types: [ synchronize, opened, reopened ]
-    branches:
-      - master
-      - 'v[0-9]+.*' # release branch
-      - ci-test # testing branch for github action
-      - '*dev'
-    paths:
-      - admin-cli/**
-
-  # for manually triggering workflow
-  workflow_dispatch:
-
-# workflow tasks
-jobs:
-  lint:
-    name: Golang Lint
-    runs-on: ubuntu-latest
-    steps:
-      - run: 'echo "No build required" '
-
-  build:
-    name: Golang Test
-    runs-on: ubuntu-latest
-    steps:
-      - run: 'echo "No build required" '
+builds:
+  - goos:
+      - linux
+      - darwin
+      - windows
+    goarch:
+      - amd64
+      - arm64
+    goarm:
+      - 7
+    main: ./main.go
+    binary: pegic
diff --git a/pegic/Makefile b/pegic/Makefile
new file mode 100644
index 00000000..00454d5e
--- /dev/null
+++ b/pegic/Makefile
@@ -0,0 +1,20 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You 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.
+#
+
+build:
+       go mod verify && go mod tidy
+       go build -o bin/pegic main.go
diff --git a/pegic/README.md b/pegic/README.md
new file mode 100644
index 00000000..4f2b6ee0
--- /dev/null
+++ b/pegic/README.md
@@ -0,0 +1,253 @@
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you 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.
+-->
+# pegic, another PEGasus Interactive Cli
+
+Pegic is a user-facing command-line tool to read/write your data on Pegasus.
+
+## Quick Start
+
+To connect to an existing Pegasus cluster, you need to specify the Pegasus 
address:
+
+```sh
+./pegic --meta 127.0.0.1:34601,127.0.0.2:34601
+```
+
+`127.0.0.1:34601,127.0.0.2:34601` is a list of MetaServer addresses. It's a 
comma (',') separated string.
+
+Before starting read/write command, you need to firstly select a table to 
operate.
+
+```
+pegic » use xiaomi_ad_data
+```
+
+This command opens a table called "xiaomi_ad_data". Every operation followed 
is applied to this table.
+
+## Commands
+
+* [Set/Get/Del](#setgetdel)
+* [Encoding](#encoding)
+* [Scan](#scan)
+
+This is an overview of the commands that pegic provides.
+
+```txt
+Commands:
+  clear            clear the screen
+  compression      read the current compression algorithm
+  del              delete a record
+  encoding         read the current encoding
+  exit             exit the shell
+  get              read a record from Pegasus
+  help             use 'help [command]' for command help
+  partition-index  ADVANCED: calculate the partition index where the hashkey 
is routed to
+  scan             scan records under the hashkey
+  set              write a record into Pegasus
+  use              select a table
+```
+
+### Set/Get/Del
+
+```
+pegic » set "hashkey::1" "sortkey" "value::1"
+
+ok
+
+Encoding:
+  - HashKey: UTF8
+  - SortKey: UTF8
+  - Value: UTF8
+```
+
+Set/Get/Del correspond to "Write","Read" and "Delete" to a table. Each 
manipulates on only single record.
+
+```
+pegic » get "hashkey::1" "sortkey"
+
+hashkey::1 : sortkey : value::1
+
+Encoding:
+  - HashKey: UTF8
+  - SortKey: UTF8
+  - Value: UTF8
+```
+
+The first argument is the "hashkey", which is used for partitioning. The 
second argument is the "sortkey", that's key-ordering under the hashkey.
+
+`set` command has the third argument, the "value", which is the record body, 
the main data.
+
+### Encoding
+
+Pegasus stores the entire record in raw bytes, the database is unaware of the 
actual encoding of the data. By default, when you use pegic, the "hashkey", 
"sortkey" and "value" will be encoded in UTF-8 from string to bytes.
+
+```
+pegic » set "中国" "北京" "abcdefg"
+
+ok
+
+Encoding:
+  - HashKey: UTF8
+  - SortKey: UTF8
+  - Value: UTF8
+
+pegic » get "中国" "北京"
+
+中国 : 北京 : abcdefg
+
+Encoding:
+  - HashKey: UTF8
+  - SortKey: UTF8
+  - Value: UTF8  
+```
+
+However, the fields could also be set with other encodings like 
`ByteBuffer.allocate(4).putInt(1695609641).array()`, or be encoded via 
binary-serialization protocols like thrift/protobuf.
+
+Here's an example where hashkey is encoded as an integer:
+
+```
+pegic » encoding hashkey int32
+
+Encoding:
+  - HashKey: INT32
+  - SortKey: UTF8
+  - Value: UTF8
+
+pegic » get 19491001 "sortkey"
+
+19491001 : sortkey : value
+
+Encoding:
+  - HashKey: INT32
+  - SortKey: UTF8
+  - Value: UTF8
+```
+
+If the encoding is not correctly matched to the data, the result will be 
unexpected.
+
+```
+pegic » encoding hashkey utf8
+
+Encoding:
+  - HashKey: UTF8
+  - SortKey: UTF8
+  - Value: UTF8
+
+pegic » get 19491001 "sortkey"
+
+Encoding:
+  - HashKey: UTF8
+  - SortKey: UTF8
+  - Value: UTF8
+
+error: record not found
+HASH_KEY=19491001
+SORT_KEY=sortkey
+```
+
+### Supported encodings
+
+- `utf8`: The default encoding.
+
+-      `int32`: 32-bit integer.
+
+-      `int64`: 64-bit integer.
+
+-      `bytes`: The golang byte array. Each byte is from range [0, 255]. For 
example: "104,101,108,108,111,32,119,111,114,108,100".
+
+-      `javabytes`: The java byte array. Each byte is from range [-128, 127]. 
For example: `49,48,52,48,56,10,0,3,-1,-1,0`.
+
+-      `asciihex`: For example 
`\x00\x00\x00e\x0C\x00\x01\x08\x00\x01\x00\x00\x00e\x08`.
+
+Please submit an issue if there's encoding not supported but generally useful.
+
+### Compression
+
+In some use-cases, we need to compress our value in order to improve read/write
+performance and latency stability.
+
+For those data, you need to specify the compression algorithm in pegic:
+
+```
+pegic » compression set zstd
+ok
+
+pegic » get novelcoldstart novelcoldstart
+novelcoldstart : novelcoldstart : abcdef
+
+TTL(Time-To-Live) is not set
+
+Encoding:
+  - HashKey: UTF8
+  - SortKey: UTF8
+  - Value: UTF8
+Compression:
+  zstd
+```
+
+### Scan
+
+```
+pegic » scan "中国"
+中国 : 上海 : {"people_num": 35000000}
+中国 : 北京 : {"people_num": 40000000}
+中国 : 广州 : {"people_num": 28000000}
+中国 : 成都 : {"people_num": 20000000}
+
+Total records count: 4
+
+Encoding:
+  - HashKey: UTF8
+  - SortKey: UTF8
+  - Value: UTF8
+```
+
+`scan` iterates over all the records under the given hashkey. If you only want 
a subset of
+the records within a given range, or to filter out the records that matched 
some pattern,
+you can specify the flags according to your needs.
+
+Scan with range:
+
+```
+pegic » scan --from 20200714000000 --to 20200715000000 uid18456112
+uid18456112 : 20200714151429 : {"login": "Beijing"}
+uid18456112 : 20200714152021 : {"login": "Beijing"}
+uid18456112 : 20200714153342 : {"login": "Beijing"}
+
+Total records count: 3
+
+Encoding:
+  - HashKey: UTF8
+  - SortKey: INT64
+  - Value: UTF8
+```
+
+Scan with filtering pattern:
+
+```
+pegic » scan --prefix rocksdb pegasus
+pegasus : rocksdb_index_size_mb : 4300
+pegasus : rocksdb_memtable_size_mb : 2000
+pegasus : rocksdb_sst_size_mb : 358000
+
+Total records count: 3
+
+Encoding:
+  - HashKey: UTF8
+  - SortKey: UTF8
+  - Value: INT64
+```
diff --git a/.github/workflows/pull-request-go-always-pass.yml 
b/pegic/check_and_format.sh
old mode 100644
new mode 100755
similarity index 55%
rename from .github/workflows/pull-request-go-always-pass.yml
rename to pegic/check_and_format.sh
index bf2a4996..f6d6f095
--- a/.github/workflows/pull-request-go-always-pass.yml
+++ b/pegic/check_and_format.sh
@@ -1,3 +1,6 @@
+#!/usr/bin/env bash
+
+#
 # Licensed to the Apache Software Foundation (ASF) under one
 # or more contributor license agreements.  See the NOTICE file
 # distributed with this work for additional information
@@ -14,36 +17,16 @@
 # KIND, either express or implied.  See the License for the
 # specific language governing permissions and limitations
 # under the License.
----
-# workflow name
-name: Golang Lint and Unit Test
-
-# on events
-on:
-  # run on each pull request
-  pull_request:
-    types: [ synchronize, opened, reopened ]
-    branches:
-      - master
-      - 'v[0-9]+.*' # release branch
-      - ci-test # testing branch for github action
-      - '*dev'
-    paths:
-      - admin-cli/**
+#
 
-  # for manually triggering workflow
-  workflow_dispatch:
+PROJECT_DIR=$(dirname "${SCRIPT_DIR}")
+cd "${PROJECT_DIR}" || exit 1
 
-# workflow tasks
-jobs:
-  lint:
-    name: Golang Lint
-    runs-on: ubuntu-latest
-    steps:
-      - run: 'echo "No build required" '
+if [ ! -f "${PROJECT_DIR}"/golangci-lint-1.35.2-linux-amd64/golangci-lint ]; 
then
+    wget 
https://github.com/golangci/golangci-lint/releases/download/v1.35.2/golangci-lint-1.35.2-linux-amd64.tar.gz
+    tar -xzvf golangci-lint-1.35.2-linux-amd64.tar.gz
+fi
 
-  build:
-    name: Golang Test
-    runs-on: ubuntu-latest
-    steps:
-      - run: 'echo "No build required" '
+gofmt -l -w .
+go mod tidy
+golangci-lint-1.35.2-linux-amd64/golangci-lint run -v -E gofmt -E golint
diff --git a/pegic/executor/context.go b/pegic/executor/context.go
new file mode 100644
index 00000000..d5bf104d
--- /dev/null
+++ b/pegic/executor/context.go
@@ -0,0 +1,137 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 executor
+
+import (
+       "fmt"
+       "io"
+
+       "github.com/XiaoMi/pegasus-go-client/pegasus"
+       "github.com/XiaoMi/pegasus-go-client/session"
+       "github.com/apache/incubator-pegasus/pegic/executor/util"
+)
+
+type Context struct {
+       // Every command should use Context as the fmt.Fprint's writer.
+       io.Writer
+
+       pegasus.Client
+
+       Meta *session.MetaManager
+
+       // default to nil
+       UseTable     pegasus.TableConnector
+       UseTableName string
+       // default to 0
+       UseTablePartitionCount int
+
+       // default to nil
+       Compressor util.BytesCompression
+
+       HashKeyEnc, SortKeyEnc, ValueEnc util.Encoder
+}
+
+func NewContext(writer io.Writer, metaAddrs []string) *Context {
+       c := &Context{
+               Writer: writer,
+               Client: pegasus.NewClient(pegasus.Config{
+                       MetaServers: metaAddrs,
+               }),
+               Meta: session.NewMetaManager(metaAddrs, session.NewNodeSession),
+
+               // by default, string uses utf-8 as encoding to bytes
+               HashKeyEnc: util.NewEncoder("utf8"),
+               SortKeyEnc: util.NewEncoder("utf8"),
+               ValueEnc:   util.NewEncoder("utf8"),
+       }
+       return c
+}
+
+// String returns a human-readable string of context.
+func (c *Context) String() string {
+       output := "\nEncoding:\n"
+       output += "  - HashKey: " + c.HashKeyEnc.String() + "\n"
+       output += "  - SortKey: " + c.SortKeyEnc.String() + "\n"
+       output += "  - Value: " + c.ValueEnc.String() + "\n"
+       if c.Compressor != nil {
+               output += "Compression:\n"
+               output += "  " + c.Compressor.String() + "\n"
+       }
+       return output
+}
+
+// readPegasusArgs assumes the args to be [hashkey, sortkey, value].
+// It returns the bytes encoded from the args if no failure.
+func readPegasusArgs(ctx *Context, args []string) ([][]byte, error) {
+       // the first argument must be hashkey
+       hashkey, err := ctx.HashKeyEnc.EncodeAll(args[0])
+       if err != nil {
+               return nil, err
+       }
+       if len(args) == 1 {
+               return [][]byte{hashkey}, nil
+       }
+
+       sortkey, err := ctx.SortKeyEnc.EncodeAll(args[1])
+       if err != nil {
+               return nil, err
+       }
+       if len(args) == 2 {
+               return [][]byte{hashkey, sortkey}, nil
+       }
+
+       value, err := ctx.ValueEnc.EncodeAll(args[2])
+       if err != nil {
+               return nil, err
+       }
+       if len(args) == 3 {
+               return [][]byte{hashkey, sortkey, value}, nil
+       }
+
+       panic("more than 3 arguments are given")
+}
+
+// printPegasusRecord prints bytes from pegasus in pretty and parsable form.
+func printPegasusRecord(ctx *Context, hashKey, sortKey, value []byte) error {
+       if ctx.Compressor != nil {
+               var err error
+               value, err = ctx.Compressor.Decompress(value)
+               if err != nil {
+                       return fmt.Errorf("%s failed to decompress value: %s", 
ctx.Compressor, err)
+               }
+       }
+
+       hashKeyStr, err := ctx.HashKeyEnc.DecodeAll(hashKey)
+       if err != nil {
+               return fmt.Errorf("HashKey can not be decoded in %s: %s", 
ctx.HashKeyEnc, err)
+       }
+       sortkeyStr, err := ctx.SortKeyEnc.DecodeAll(sortKey)
+       if err != nil {
+               return fmt.Errorf("SortKey can not be decoded in %s: %s", 
ctx.SortKeyEnc, err)
+       }
+       valueStr, err := ctx.ValueEnc.DecodeAll(value)
+       if err != nil {
+               bytesEnc := util.NewEncoder("javabytes")
+               valueStr, _ := bytesEnc.DecodeAll(value)
+               return fmt.Errorf("Value can not be decoded in %s: %s [SortKey: 
\"%s\"]\nValue: [JAVABYTES]\n%s", ctx.ValueEnc, err, sortKey, valueStr)
+       }
+       fmt.Fprintf(ctx, "%s : %s : %s\n", hashKeyStr, sortkeyStr, valueStr)
+       return nil
+}
diff --git a/pegic/executor/del.go b/pegic/executor/del.go
new file mode 100644
index 00000000..18246784
--- /dev/null
+++ b/pegic/executor/del.go
@@ -0,0 +1,42 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 executor
+
+import (
+       "context"
+       "fmt"
+       "time"
+)
+
+func Del(rootCtx *Context, hashKeyStr, sortkeyStr string) error {
+       pegasusArgs, err := readPegasusArgs(rootCtx, []string{hashKeyStr, 
sortkeyStr})
+       if err != nil {
+               return err
+       }
+
+       ctx, cancel := context.WithTimeout(context.Background(), time.Second*10)
+       defer cancel()
+       err = rootCtx.UseTable.Del(ctx, pegasusArgs[0], pegasusArgs[1])
+       if err != nil {
+               return err
+       }
+       fmt.Fprintln(rootCtx, "\nok")
+       return nil
+}
diff --git a/pegic/executor/get.go b/pegic/executor/get.go
new file mode 100644
index 00000000..b2fadd08
--- /dev/null
+++ b/pegic/executor/get.go
@@ -0,0 +1,59 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 executor
+
+import (
+       "context"
+       "fmt"
+       "time"
+)
+
+func Get(rootCtx *Context, hashKeyStr, sortkeyStr string) error {
+       pegasusArgs, err := readPegasusArgs(rootCtx, []string{hashKeyStr, 
sortkeyStr})
+       if err != nil {
+               return err
+       }
+
+       ctx, cancel := context.WithTimeout(context.Background(), time.Second*10)
+       defer cancel()
+       rawValue, err := rootCtx.UseTable.Get(ctx, pegasusArgs[0], 
pegasusArgs[1])
+       if err != nil {
+               return err
+       }
+       if rawValue == nil {
+               return fmt.Errorf("record not found\nHASH_KEY=%s\nSORT_KEY=%s", 
hashKeyStr, sortkeyStr)
+       }
+
+       if err = printPegasusRecord(rootCtx, pegasusArgs[0], pegasusArgs[1], 
rawValue); err != nil {
+               return err
+       }
+
+       ttl, err := rootCtx.UseTable.TTL(ctx, pegasusArgs[0], pegasusArgs[1])
+       if err != nil {
+               return err
+       }
+       if ttl == -1 {
+               fmt.Fprintf(rootCtx, "\nTTL(Time-To-Live) is not set\n")
+       } else {
+               fmt.Fprintf(rootCtx, "\nTTL(Time-To-Live) : %d seconds\n", ttl)
+       }
+
+       return nil
+}
diff --git a/pegic/executor/partition_index.go 
b/pegic/executor/partition_index.go
new file mode 100644
index 00000000..31ac3b53
--- /dev/null
+++ b/pegic/executor/partition_index.go
@@ -0,0 +1,65 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 executor
+
+import (
+       "context"
+       "fmt"
+       "hash/crc64"
+       "time"
+
+       "github.com/XiaoMi/pegasus-go-client/idl/base"
+)
+
+var crc64Table = crc64.MakeTable(0x9a6c9329ac4bc9b5)
+
+func crc64Hash(data []byte) uint64 {
+       return crc64.Checksum(data, crc64Table)
+}
+
+func getPartitionIndex(hashKey []byte, partitionCount int) int32 {
+       return int32(crc64Hash(hashKey) % uint64(partitionCount))
+}
+
+func PartitionIndex(rootCtx *Context, hashKeyStr string) error {
+       pegasusArgs, err := readPegasusArgs(rootCtx, []string{hashKeyStr})
+       if err != nil {
+               return err
+       }
+
+       if rootCtx.UseTablePartitionCount == 0 {
+               ctx, cancel := context.WithTimeout(context.Background(), 
10*time.Second)
+               defer cancel()
+
+               resp, err := rootCtx.Meta.QueryConfig(ctx, rootCtx.UseTableName)
+               if err != nil {
+                       return err
+               }
+               if resp.GetErr().Errno != base.ERR_OK.String() {
+                       return fmt.Errorf("QueryConfig failed: %s", 
resp.GetErr().String())
+               }
+               rootCtx.UseTablePartitionCount = int(resp.PartitionCount)
+       }
+
+       partIdx := getPartitionIndex(pegasusArgs[0], 
rootCtx.UseTablePartitionCount)
+       fmt.Fprintf(rootCtx, "\nPartition index : %d\n", partIdx)
+
+       return nil
+}
diff --git a/pegic/executor/scan.go b/pegic/executor/scan.go
new file mode 100644
index 00000000..e169b922
--- /dev/null
+++ b/pegic/executor/scan.go
@@ -0,0 +1,149 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 executor
+
+import (
+       "context"
+       "fmt"
+       "time"
+
+       "github.com/XiaoMi/pegasus-go-client/pegasus"
+)
+
+// ScanCommand wraps scan command input.
+type ScanCommand struct {
+       HashKey string
+
+       // optional
+       From, To                 *string
+       Prefix, Suffix, Contains *string
+
+       // only calculate the count of sortkeys under this hashkey.
+       // default to false.
+       CountOnly bool
+}
+
+// IterateAll iterates over the table according to the command.
+func (s *ScanCommand) IterateAll(rootCtx *Context) error {
+       hashkey, err := rootCtx.HashKeyEnc.EncodeAll(s.HashKey)
+       if err != nil {
+               return fmt.Errorf("invalid hashkey: %s", err)
+       }
+
+       var startSortKey, stopSortKey, filterPattern []byte
+       var filterType pegasus.FilterType
+
+       if s.From != nil {
+               startSortKey, err = rootCtx.SortKeyEnc.EncodeAll(*s.From)
+               if err != nil {
+                       return fmt.Errorf("invalid startSortKey: %s", err)
+               }
+       }
+       if s.To != nil {
+               stopSortKey, err = rootCtx.SortKeyEnc.EncodeAll(*s.To)
+               if err != nil {
+                       return fmt.Errorf("invalid stopSortKey: %s", err)
+               }
+       }
+
+       var filterStr *string
+       if s.Prefix != nil {
+               filterStr = s.Prefix
+               filterType = pegasus.FilterTypeMatchPrefix
+       }
+       if s.Suffix != nil {
+               filterStr = s.Suffix
+               filterType = pegasus.FilterTypeMatchPostfix
+       }
+       if s.Contains != nil {
+               filterStr = s.Contains
+               filterType = pegasus.FilterTypeMatchAnywhere
+       }
+       if filterStr != nil {
+               filterPattern, err = rootCtx.SortKeyEnc.EncodeAll(*filterStr)
+               if err != nil {
+                       return fmt.Errorf("invalid filter: %s", err)
+               }
+       }
+
+       sopts := &pegasus.ScannerOptions{
+               BatchSize: 5,
+               SortKeyFilter: pegasus.Filter{
+                       Type:    filterType,
+                       Pattern: filterPattern,
+               },
+               // TODO(wutao): provide options
+               StartInclusive: true,
+               StopInclusive:  true,
+               NoValue:        s.CountOnly,
+       }
+       ctx, cancel := context.WithTimeout(context.Background(), time.Second*10)
+       defer cancel()
+       scanner, err := rootCtx.UseTable.GetScanner(ctx, hashkey, startSortKey, 
stopSortKey, sopts)
+       if err != nil {
+               return err
+       }
+       return s.iterateAllWithScanner(rootCtx, scanner)
+}
+
+// Validate if ScanCommand is valid.
+func (s *ScanCommand) Validate() error {
+       cnt := 0
+       if s.Prefix != nil {
+               cnt++
+       }
+       if s.Suffix != nil {
+               cnt++
+       }
+       if s.Contains != nil {
+               cnt++
+       }
+       if cnt > 1 {
+               return fmt.Errorf("should specify only one of 
prefix|suffix|contains")
+       }
+       return nil
+}
+
+// iterateAllWithScanner prints all entries owned by scanner.
+func (s *ScanCommand) iterateAllWithScanner(rootCtx *Context, scanner 
pegasus.Scanner) error {
+       ctx, cancel := context.WithTimeout(context.Background(), time.Second*10)
+       defer cancel()
+
+       recordsCnt := uint64(0)
+       for {
+               completed, hashKey, sortKey, value, err := scanner.Next(ctx)
+               if err != nil {
+                       return err
+               }
+               if completed {
+                       break
+               }
+               recordsCnt++
+               if s.CountOnly {
+                       continue
+               }
+               err = printPegasusRecord(rootCtx, hashKey, sortKey, value)
+               if err != nil {
+                       return err
+               }
+       }
+       fmt.Fprintf(rootCtx, "\nTotal records count: %d\n", recordsCnt)
+       return nil
+}
diff --git a/pegic/executor/set.go b/pegic/executor/set.go
new file mode 100644
index 00000000..2b6dd716
--- /dev/null
+++ b/pegic/executor/set.go
@@ -0,0 +1,42 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 executor
+
+import (
+       "context"
+       "fmt"
+       "time"
+)
+
+func Set(rootCtx *Context, hashKeyStr, sortkeyStr, valueStr string) error {
+       pegasusArgs, err := readPegasusArgs(rootCtx, []string{hashKeyStr, 
sortkeyStr, valueStr})
+       if err != nil {
+               return err
+       }
+
+       ctx, cancel := context.WithTimeout(context.Background(), time.Second*10)
+       defer cancel()
+       err = rootCtx.UseTable.Set(ctx, pegasusArgs[0], pegasusArgs[1], 
pegasusArgs[2])
+       if err != nil {
+               return err
+       }
+       fmt.Fprintln(rootCtx, "\nok")
+       return nil
+}
diff --git a/pegic/executor/util/asciihex.go b/pegic/executor/util/asciihex.go
new file mode 100644
index 00000000..3cf88182
--- /dev/null
+++ b/pegic/executor/util/asciihex.go
@@ -0,0 +1,94 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 util
+
+import (
+       "encoding/hex"
+       "fmt"
+)
+
+type asciiHexEncoder struct {
+}
+
+func (*asciiHexEncoder) EncodeAll(s string) ([]byte, error) {
+       var bs []byte
+
+       for i := 0; i < len(s); i++ {
+               if s[i] == '\\' {
+                       if i+1 >= len(s) {
+                               return nil, fmt.Errorf("invalid asciihex 
string: %s", s)
+                       }
+
+                       i++
+                       switch s[i] {
+                       case 'n':
+                               bs = append(bs, '\n')
+                       case 'r':
+                               bs = append(bs, '\r')
+                       case 't':
+                               bs = append(bs, '\t')
+                       case '"':
+                               bs = append(bs, '"')
+                       case '\'':
+                               bs = append(bs, '\'')
+                       case '\\':
+                               bs = append(bs, '\\')
+                       case 'x', 'X':
+                               if i+2 >= len(s) {
+                                       return nil, fmt.Errorf("invalid 
asciihex string: %s", s)
+                               }
+                               digit1 := s[i+1]
+                               digit2 := s[i+2]
+                               i += 2
+
+                               var hexStr string
+                               hexStr += string(digit1) + string(digit2)
+                               bytes, err := hex.DecodeString(hexStr)
+                               if err != nil {
+                                       return nil, err
+                               }
+                               if len(bytes) != 1 {
+                                       panic("two hex digits should be 1 byte")
+                               }
+
+                               bs = append(bs, bytes[0])
+                       }
+               } else if s[i] >= 32 && s[i] <= 126 {
+                       // valid ascii character
+                       bs = append(bs, s[i])
+               } else {
+                       return nil, fmt.Errorf("invalid asciihex string: %s", s)
+               }
+       }
+       return bs, nil
+}
+
+func (*asciiHexEncoder) DecodeAll(bytes []byte) (string, error) {
+       var s string
+       for _, c := range bytes {
+               hexByte := hex.EncodeToString([]byte{c})
+               s += "\\x" + hexByte
+       }
+       return s, nil
+}
+
+func (*asciiHexEncoder) String() string {
+       return "ASCIIHEX"
+}
diff --git a/pegic/executor/util/compression.go 
b/pegic/executor/util/compression.go
new file mode 100644
index 00000000..c3b66fc3
--- /dev/null
+++ b/pegic/executor/util/compression.go
@@ -0,0 +1,74 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 util
+
+import (
+       "strings"
+
+       "github.com/klauspost/compress/zstd"
+)
+
+// BytesCompression is an interface of algorithm for compressing bytes.
+type BytesCompression interface {
+       Compress([]byte) ([]byte, error)
+
+       Decompress([]byte) ([]byte, error)
+
+       // String returns name of the algorithm.
+       String() string
+}
+
+// NewCompression returns nil if the given name is invalid.
+func NewCompression(name string) BytesCompression {
+       name = strings.ToLower(name)
+       switch name {
+       case "zstd":
+               return newZstdCompression()
+       default:
+               return nil
+       }
+}
+
+type zstdCompression struct {
+       encoder *zstd.Encoder
+       decoder *zstd.Decoder
+}
+
+func (z *zstdCompression) Compress(data []byte) ([]byte, error) {
+       return z.encoder.EncodeAll(data, make([]byte, 0, len(data))), nil
+}
+
+func (z *zstdCompression) Decompress(data []byte) ([]byte, error) {
+       return z.decoder.DecodeAll(data, nil)
+}
+
+func (z *zstdCompression) String() string {
+       return "zstd"
+}
+
+func newZstdCompression() BytesCompression {
+       decoder, _ := zstd.NewReader(nil)
+       encoder, _ := zstd.NewWriter(nil)
+
+       return &zstdCompression{
+               encoder: encoder,
+               decoder: decoder,
+       }
+}
diff --git a/pegic/executor/util/encoding.go b/pegic/executor/util/encoding.go
new file mode 100644
index 00000000..cf97e35f
--- /dev/null
+++ b/pegic/executor/util/encoding.go
@@ -0,0 +1,163 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 util
+
+import (
+       "encoding/binary"
+       "errors"
+       "fmt"
+       "strconv"
+       "strings"
+       "unicode/utf8"
+)
+
+type Encoder interface {
+       // encode string into a bytes
+       EncodeAll(string) ([]byte, error)
+
+       // decode from bytes to string
+       DecodeAll([]byte) (string, error)
+
+       // String returns name of the encoding.
+       String() string
+}
+
+type utf8Encoder struct {
+}
+
+func (*utf8Encoder) EncodeAll(s string) ([]byte, error) {
+       if !utf8.ValidString(s) {
+               return nil, errors.New("invalid utf8 string")
+       }
+       return []byte(s), nil // go uses utf8 by default.
+}
+
+func (*utf8Encoder) DecodeAll(s []byte) (string, error) {
+       if !utf8.Valid(s) {
+               return "", errors.New("invalid utf8 bytes")
+       }
+       return string(s), nil
+}
+
+func (*utf8Encoder) String() string {
+       return "UTF8"
+}
+
+type int32Encoder struct {
+}
+
+func (*int32Encoder) EncodeAll(s string) ([]byte, error) {
+       i, err := strconv.ParseInt(s, 10, 32 /*bits*/)
+       if err != nil {
+               return nil, errors.New("invalid INT32")
+       }
+       value := make([]byte, 4 /*bytes*/)
+       binary.BigEndian.PutUint32(value, uint32(i))
+       return value, nil
+}
+
+func (*int32Encoder) DecodeAll(s []byte) (string, error) {
+       if len(s) != 4 {
+               return "", fmt.Errorf("bytes is not a valid INT32")
+       }
+       i := binary.BigEndian.Uint32(s)
+       return fmt.Sprint(int32(i)), nil
+}
+
+func (*int32Encoder) String() string {
+       return "INT32"
+}
+
+type int64Encoder struct {
+}
+
+func (*int64Encoder) EncodeAll(s string) ([]byte, error) {
+       i, err := strconv.ParseInt(s, 10, 64 /*bits*/)
+       if err != nil {
+               return nil, errors.New("invalid INT64")
+       }
+       value := make([]byte, 8 /*bytes*/)
+       binary.BigEndian.PutUint64(value, uint64(i))
+       return value, nil
+}
+
+func (*int64Encoder) DecodeAll(s []byte) (string, error) {
+       if len(s) != 8 {
+               return "", fmt.Errorf("bytes is not a valid INT64")
+       }
+       i := binary.BigEndian.Uint64(s)
+       return fmt.Sprint(int64(i)), nil
+}
+
+func (*int64Encoder) String() string {
+       return "INT64"
+}
+
+type goBytesEncoder struct {
+}
+
+func (*goBytesEncoder) EncodeAll(s string) ([]byte, error) {
+       bytesInStrList := strings.Split(s, " ")
+
+       value := make([]byte, len(bytesInStrList))
+       for i, byteStr := range bytesInStrList {
+               b, err := strconv.Atoi(byteStr)
+               if err != nil || b > 255 || b < 0 { // byte ranges from [0, 255]
+                       return nil, fmt.Errorf("invalid go byte \"%s\"", 
byteStr)
+               }
+               value[i] = byte(b)
+       }
+
+       return value, nil
+}
+
+func (*goBytesEncoder) DecodeAll(bytes []byte) (string, error) {
+       s := make([]string, len(bytes))
+       for i, c := range bytes {
+               s[i] = fmt.Sprint(uint8(c))
+       }
+       return strings.Join(s, ","), nil
+}
+
+func (*goBytesEncoder) String() string {
+       return "BYTES"
+}
+
+// NewEncoder returns nil if the given name is invalid.
+func NewEncoder(name string) Encoder {
+       name = strings.ToLower(name)
+       switch name {
+       case "utf8", "utf-8":
+               return &utf8Encoder{}
+       case "int32":
+               return &int32Encoder{}
+       case "int64":
+               return &int64Encoder{}
+       case "bytes":
+               return &goBytesEncoder{}
+       case "javabytes":
+               return &javaBytesEncoder{}
+       case "asciihex":
+               return &asciiHexEncoder{}
+       // TODO(wutao): support hex array, such as 0x37, 0xFF, ...
+       default:
+               return nil
+       }
+}
diff --git a/pegic/executor/util/javabytes.go b/pegic/executor/util/javabytes.go
new file mode 100644
index 00000000..ae16d278
--- /dev/null
+++ b/pegic/executor/util/javabytes.go
@@ -0,0 +1,57 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 util
+
+import (
+       "fmt"
+       "strconv"
+       "strings"
+)
+
+// javabytes is like '0,0,101,12,0,1,8,-1,-1,-1', delimited by ',' and each 
byte ranges from [-128, 127]
+type javaBytesEncoder struct {
+}
+
+func (*javaBytesEncoder) EncodeAll(s string) ([]byte, error) {
+       bytesInStrList := strings.Split(s, ",")
+
+       value := make([]byte, len(bytesInStrList))
+       for i, byteStr := range bytesInStrList {
+               b, err := strconv.Atoi(byteStr)
+               if err != nil || b > 127 || b < -128 { // byte ranges from 
[-128, 127]
+                       return nil, fmt.Errorf("invalid java byte \"%s\"", 
byteStr)
+               }
+               value[i] = byte(b)
+       }
+
+       return value, nil
+}
+
+func (*javaBytesEncoder) DecodeAll(bytes []byte) (string, error) {
+       s := make([]string, len(bytes))
+       for i, c := range bytes {
+               s[i] = fmt.Sprint(int8(c))
+       }
+       return strings.Join(s, ","), nil
+}
+
+func (*javaBytesEncoder) String() string {
+       return "JAVABYTES"
+}
diff --git a/pegic/go.mod b/pegic/go.mod
new file mode 100644
index 00000000..eac79d3f
--- /dev/null
+++ b/pegic/go.mod
@@ -0,0 +1,34 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you 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.
+
+module github.com/apache/incubator-pegasus/pegic
+
+go 1.14
+
+require (
+       github.com/XiaoMi/pegasus-go-client v0.0.0-20211126055700-5ae2deb75c37
+       github.com/desertbit/grumble v1.1.1
+       github.com/hashicorp/go-multierror v1.1.1 // indirect
+       github.com/klauspost/compress v1.12.1
+       github.com/sirupsen/logrus v1.8.1
+       github.com/spf13/cobra v1.1.3
+       golang.org/x/net v0.0.0-20210415231046-e915ea6b2b7d // indirect
+       golang.org/x/sys v0.0.0-20210415045647-66c3f260301c // indirect
+       gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
+       gopkg.in/natefinch/lumberjack.v2 v2.0.0
+       gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
+)
diff --git a/pegic/go.sum b/pegic/go.sum
new file mode 100644
index 00000000..e6cbcc3b
--- /dev/null
+++ b/pegic/go.sum
@@ -0,0 +1,439 @@
+cloud.google.com/go v0.26.0/go.mod 
h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
+cloud.google.com/go v0.34.0/go.mod 
h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
+cloud.google.com/go v0.38.0/go.mod 
h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
+cloud.google.com/go v0.44.1/go.mod 
h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=
+cloud.google.com/go v0.44.2/go.mod 
h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
+cloud.google.com/go v0.45.1/go.mod 
h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc=
+cloud.google.com/go v0.46.3/go.mod 
h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=
+cloud.google.com/go/bigquery v1.0.1/go.mod 
h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
+cloud.google.com/go/datastore v1.0.0/go.mod 
h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
+cloud.google.com/go/firestore v1.1.0/go.mod 
h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk=
+cloud.google.com/go/pubsub v1.0.1/go.mod 
h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
+cloud.google.com/go/storage v1.0.0/go.mod 
h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=
+dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod 
h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
+github.com/BurntSushi/toml v0.3.1 
h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
+github.com/BurntSushi/toml v0.3.1/go.mod 
h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
+github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod 
h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
+github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod 
h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ=
+github.com/Netflix/go-expect v0.0.0-20180615182759-c93bf25de8e8/go.mod 
h1:oX5x61PbNXchhh0oikYAH+4Pcfw5LKv21+Jnpr6r6Pc=
+github.com/Netflix/go-expect v0.0.0-20190729225929-0e00d9168667/go.mod 
h1:oX5x61PbNXchhh0oikYAH+4Pcfw5LKv21+Jnpr6r6Pc=
+github.com/OneOfOne/xxhash v1.2.2/go.mod 
h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
+github.com/PuerkitoBio/purell v1.0.0/go.mod 
h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
+github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod 
h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
+github.com/XiaoMi/pegasus-go-client v0.0.0-20211126055700-5ae2deb75c37 
h1:h1be834SkoleMU2rDxpQuWp4FQhXCPbV1t8yr/fXzXo=
+github.com/XiaoMi/pegasus-go-client v0.0.0-20211126055700-5ae2deb75c37/go.mod 
h1:VrfgKISflRhFm32m3e0SXLccvNJTyG8PRywWbUuGEfY=
+github.com/agiledragon/gomonkey v2.0.2+incompatible 
h1:eXKi9/piiC3cjJD1658mEE2o3NjkJ5vDLgYjCQu0Xlw=
+github.com/agiledragon/gomonkey v2.0.2+incompatible/go.mod 
h1:2NGfXu1a80LLr2cmWXGBDaHEjb1idR6+FVlX5T3D9hw=
+github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod 
h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
+github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod 
h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
+github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod 
h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
+github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod 
h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
+github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod 
h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
+github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod 
h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
+github.com/beorn7/perks v1.0.0/go.mod 
h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
+github.com/bgentry/speakeasy v0.1.0/go.mod 
h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
+github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod 
h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84=
+github.com/cenkalti/backoff/v4 v4.1.0 
h1:c8LkOFQTzuO0WBM/ae5HdGQuZPfPxp7lqBRwQRm4fSc=
+github.com/cenkalti/backoff/v4 v4.1.0/go.mod 
h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw=
+github.com/cespare/xxhash v1.1.0/go.mod 
h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
+github.com/chzyer/logex v1.1.10 h1:Swpa1K6QvQznwJRcfTfQJmTE72DqScAa40E+fbHEXEE=
+github.com/chzyer/logex v1.1.10/go.mod 
h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
+github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1 
h1:q763qf9huN11kDQavWsoZXJNW3xEE4JJyHa5Q25/sd8=
+github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod 
h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
+github.com/client9/misspell v0.3.4/go.mod 
h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
+github.com/coreos/bbolt v1.3.2/go.mod 
h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
+github.com/coreos/etcd v3.3.13+incompatible/go.mod 
h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
+github.com/coreos/go-semver v0.3.0/go.mod 
h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
+github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod 
h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
+github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod 
h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
+github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod 
h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
+github.com/creack/pty v1.1.7/go.mod 
h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
+github.com/davecgh/go-spew v0.0.0-20151105211317-5215b55f46b2/go.mod 
h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/davecgh/go-spew v1.1.0/go.mod 
h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/davecgh/go-spew v1.1.1 
h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
+github.com/davecgh/go-spew v1.1.1/go.mod 
h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/desertbit/closer/v3 v3.1.2 
h1:a6+2DmwIcNygW04XXWYq+Qp2X9uIk9QbZCP9//qEkb0=
+github.com/desertbit/closer/v3 v3.1.2/go.mod 
h1:AAC4KRd8DC40nwvV967J/kDFhujMEiuwIKQfN0IDxXw=
+github.com/desertbit/columnize v2.1.0+incompatible 
h1:h55rYmdrWoTj7w9aAnCkxzM3C2Eb8zuFa2W41t0o5j0=
+github.com/desertbit/columnize v2.1.0+incompatible/go.mod 
h1:5kPrzQwKbQ8E5D28nvTVPqIBJyj+8jvJzwt6HXZvXgI=
+github.com/desertbit/go-shlex v0.1.1 
h1:c65HnbgX1QyC6kPL1dMzUpZ4puNUE6ai/eVucWNLNsk=
+github.com/desertbit/go-shlex v0.1.1/go.mod 
h1:Qbb+mJNud5AypgHZ81EL8syOGaWlwvAOTqS7XmWI4pQ=
+github.com/desertbit/grumble v1.1.1 
h1:1wxy6ka1aqbtA3kZIHaPfB/DD91HSM2m4Kx2QIIGfpE=
+github.com/desertbit/grumble v1.1.1/go.mod 
h1:r7j3ShNy5EmOsegRD2DzTutIaGiLiA3M5yBTXXeLwcs=
+github.com/desertbit/readline v1.5.1 
h1:/wOIZkWYl1s+IvJm/5bOknfUgs6MhS9svRNZpFM53Os=
+github.com/desertbit/readline v1.5.1/go.mod 
h1:pHQgTsCFs9Cpfh5mlSUFi9Xa5kkL4d8L1Jo4UVWzPw0=
+github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod 
h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
+github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod 
h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
+github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod 
h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM=
+github.com/elazarl/goproxy v0.0.0-20170405201442-c4fc26588b6e/go.mod 
h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc=
+github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod 
h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs=
+github.com/evanphx/json-patch v4.2.0+incompatible/go.mod 
h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
+github.com/fatih/color v1.7.0/go.mod 
h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
+github.com/fatih/color v1.10.0 h1:s36xzo75JdqLaaWoiEHk767eHiwo0598uUxyfiPkDsg=
+github.com/fatih/color v1.10.0/go.mod 
h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM=
+github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568 
h1:BHsljHzVlRcyQhjrss6TZTdY2VfCqZPbv5k3iBFa2ZQ=
+github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod 
h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=
+github.com/fortytw2/leaktest v1.3.0 
h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw=
+github.com/fortytw2/leaktest v1.3.0/go.mod 
h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g=
+github.com/fsnotify/fsnotify v1.4.7/go.mod 
h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
+github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod 
h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
+github.com/ghodss/yaml v1.0.0/go.mod 
h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
+github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod 
h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
+github.com/go-kit/kit v0.8.0/go.mod 
h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
+github.com/go-logfmt/logfmt v0.3.0/go.mod 
h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
+github.com/go-logfmt/logfmt v0.4.0/go.mod 
h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
+github.com/go-logr/logr v0.1.0/go.mod 
h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas=
+github.com/go-openapi/jsonpointer v0.0.0-20160704185906-46af16f9f7b1/go.mod 
h1:+35s3my2LFTysnkMfxsJBAMHj/DoqoB9knIWoYG/Vk0=
+github.com/go-openapi/jsonreference v0.0.0-20160704190145-13c6e3589ad9/go.mod 
h1:W3Z9FmVs9qj+KR4zFKmDPGiLdk1D9Rlm7cyMvf57TTg=
+github.com/go-openapi/spec v0.0.0-20160808142527-6aced65f8501/go.mod 
h1:J8+jY1nAiCcj+friV/PDoE1/3eeccG9LYBs0tYvLOWc=
+github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87/go.mod 
h1:DXUve3Dpr1UfpPtxFw+EFuQ41HhCWZfha5jSVRG7C7I=
+github.com/go-stack/stack v1.8.0/go.mod 
h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
+github.com/gogo/protobuf v1.1.1/go.mod 
h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
+github.com/gogo/protobuf v1.2.1/go.mod 
h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
+github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d/go.mod 
h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
+github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod 
h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
+github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod 
h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
+github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod 
h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
+github.com/golang/mock v1.1.1/go.mod 
h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
+github.com/golang/mock v1.2.0/go.mod 
h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
+github.com/golang/mock v1.3.1/go.mod 
h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
+github.com/golang/protobuf v0.0.0-20161109072736-4bd1920723d7/go.mod 
h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.2.0/go.mod 
h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.3.1/go.mod 
h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.3.2/go.mod 
h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/snappy v0.0.3 h1:fHPg5GQYlCeLIPB9BZqMVR5nR9A+IM5zcgeTdjMYmLA=
+github.com/golang/snappy v0.0.3/go.mod 
h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
+github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod 
h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
+github.com/google/btree v1.0.0/go.mod 
h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
+github.com/google/go-cmp v0.2.0/go.mod 
h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
+github.com/google/go-cmp v0.3.0/go.mod 
h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
+github.com/google/gofuzz v0.0.0-20161122191042-44d81051d367/go.mod 
h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI=
+github.com/google/gofuzz v1.0.0/go.mod 
h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
+github.com/google/martian v2.1.0+incompatible/go.mod 
h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
+github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod 
h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
+github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod 
h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
+github.com/google/renameio v0.1.0/go.mod 
h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
+github.com/google/uuid v1.1.1/go.mod 
h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
+github.com/googleapis/gax-go/v2 v2.0.4/go.mod 
h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
+github.com/googleapis/gax-go/v2 v2.0.5/go.mod 
h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
+github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d/go.mod 
h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY=
+github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod 
h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
+github.com/gorilla/websocket v1.4.2/go.mod 
h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
+github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod 
h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
+github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod 
h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
+github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod 
h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
+github.com/hashicorp/consul/api v1.1.0/go.mod 
h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q=
+github.com/hashicorp/consul/sdk v0.1.1/go.mod 
h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8=
+github.com/hashicorp/errwrap v1.0.0/go.mod 
h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
+github.com/hashicorp/errwrap v1.1.0 
h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I=
+github.com/hashicorp/errwrap v1.1.0/go.mod 
h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
+github.com/hashicorp/go-cleanhttp v0.5.1/go.mod 
h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
+github.com/hashicorp/go-immutable-radix v1.0.0/go.mod 
h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
+github.com/hashicorp/go-msgpack v0.5.3/go.mod 
h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=
+github.com/hashicorp/go-multierror v1.0.0/go.mod 
h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
+github.com/hashicorp/go-multierror v1.1.0/go.mod 
h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA=
+github.com/hashicorp/go-multierror v1.1.1 
h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo=
+github.com/hashicorp/go-multierror v1.1.1/go.mod 
h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
+github.com/hashicorp/go-rootcerts v1.0.0/go.mod 
h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU=
+github.com/hashicorp/go-sockaddr v1.0.0/go.mod 
h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU=
+github.com/hashicorp/go-syslog v1.0.0/go.mod 
h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=
+github.com/hashicorp/go-uuid v1.0.0/go.mod 
h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
+github.com/hashicorp/go-uuid v1.0.1/go.mod 
h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
+github.com/hashicorp/go.net v0.0.1/go.mod 
h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90=
+github.com/hashicorp/golang-lru v0.5.0/go.mod 
h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
+github.com/hashicorp/golang-lru v0.5.1/go.mod 
h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
+github.com/hashicorp/hcl v1.0.0/go.mod 
h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
+github.com/hashicorp/logutils v1.0.0/go.mod 
h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64=
+github.com/hashicorp/mdns v1.0.0/go.mod 
h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ=
+github.com/hashicorp/memberlist v0.1.3/go.mod 
h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I=
+github.com/hashicorp/serf v0.8.2/go.mod 
h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc=
+github.com/hinshun/vt10x v0.0.0-20180616224451-1954e6464174/go.mod 
h1:DqJ97dSdRW1W22yXSB90986pcOyQ7r45iio1KN2ez1A=
+github.com/hinshun/vt10x v0.0.0-20180809195222-d55458df857c/go.mod 
h1:DqJ97dSdRW1W22yXSB90986pcOyQ7r45iio1KN2ez1A=
+github.com/hpcloud/tail v1.0.0/go.mod 
h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
+github.com/inconshreveable/mousetrap v1.0.0 
h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
+github.com/inconshreveable/mousetrap v1.0.0/go.mod 
h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
+github.com/jonboulle/clockwork v0.1.0/go.mod 
h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
+github.com/json-iterator/go v0.0.0-20180612202835-f2b4162afba3/go.mod 
h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
+github.com/json-iterator/go v1.1.6/go.mod 
h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
+github.com/json-iterator/go v1.1.8/go.mod 
h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
+github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod 
h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
+github.com/jtolds/gls v4.20.0+incompatible/go.mod 
h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
+github.com/julienschmidt/httprouter v1.2.0/go.mod 
h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
+github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod 
h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8=
+github.com/kisielk/errcheck v1.1.0/go.mod 
h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
+github.com/kisielk/errcheck v1.2.0/go.mod 
h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
+github.com/kisielk/gotool v1.0.0/go.mod 
h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
+github.com/klauspost/compress v1.12.1 
h1:/+xsCsk06wE38cyiqOR/o7U2fSftcH72xD+BQXmja/g=
+github.com/klauspost/compress v1.12.1/go.mod 
h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg=
+github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod 
h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
+github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod 
h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
+github.com/kr/pretty v0.1.0/go.mod 
h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
+github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI=
+github.com/kr/pretty v0.2.1/go.mod 
h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
+github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
+github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw=
+github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
+github.com/kr/text v0.1.0/go.mod 
h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
+github.com/magiconair/properties v1.8.1/go.mod 
h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
+github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod 
h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
+github.com/mattn/go-colorable v0.0.9/go.mod 
h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
+github.com/mattn/go-colorable v0.1.8 
h1:c1ghPdyEDarC70ftn0y+A/Ee++9zz8ljHG1b13eJ0s8=
+github.com/mattn/go-colorable v0.1.8/go.mod 
h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
+github.com/mattn/go-isatty v0.0.3/go.mod 
h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
+github.com/mattn/go-isatty v0.0.12 
h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
+github.com/mattn/go-isatty v0.0.12/go.mod 
h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
+github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod 
h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
+github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod 
h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE=
+github.com/miekg/dns v1.0.14/go.mod 
h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
+github.com/mitchellh/cli v1.0.0/go.mod 
h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
+github.com/mitchellh/go-homedir v1.0.0/go.mod 
h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
+github.com/mitchellh/go-homedir v1.1.0/go.mod 
h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
+github.com/mitchellh/go-testing-interface v1.0.0/go.mod 
h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
+github.com/mitchellh/gox v0.4.0/go.mod 
h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg=
+github.com/mitchellh/iochan v1.0.0/go.mod 
h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY=
+github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod 
h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
+github.com/mitchellh/mapstructure v1.1.2/go.mod 
h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
+github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod 
h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
+github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod 
h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
+github.com/modern-go/reflect2 v0.0.0-20180320133207-05fbef0ca5da/go.mod 
h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
+github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod 
h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
+github.com/modern-go/reflect2 v1.0.1/go.mod 
h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
+github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod 
h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
+github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod 
h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
+github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod 
h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw=
+github.com/nbutton23/zxcvbn-go v0.0.0-20180912185939-ae427f1e4c1d/go.mod 
h1:o96djdrsSGy3AWPyBgZMAGfxZNfgntdJG+11KU4QvbU=
+github.com/oklog/ulid v1.3.1/go.mod 
h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
+github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod 
h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
+github.com/onsi/ginkgo v1.6.0/go.mod 
h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
+github.com/onsi/ginkgo v1.10.1/go.mod 
h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
+github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod 
h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
+github.com/onsi/gomega v1.7.0/go.mod 
h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
+github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod 
h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
+github.com/pegasus-kv/thrift v0.13.0 
h1:4ESwaNoHImfbHa9RUGJiJZ4hrxorihZHk5aarYwY8d4=
+github.com/pegasus-kv/thrift v0.13.0/go.mod 
h1:Gl9NT/WHG6ABm6NsrbfE8LiJN0sAyneCrvB4qN4NPqQ=
+github.com/pelletier/go-toml v1.2.0/go.mod 
h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
+github.com/pkg/errors v0.8.0/go.mod 
h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+github.com/pkg/errors v0.8.1/go.mod 
h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+github.com/pmezard/go-difflib v0.0.0-20151028094244-d8ed2627bdf0/go.mod 
h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/pmezard/go-difflib v1.0.0 
h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
+github.com/pmezard/go-difflib v1.0.0/go.mod 
h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/posener/complete v1.1.1/go.mod 
h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
+github.com/prometheus/client_golang v0.9.1/go.mod 
h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
+github.com/prometheus/client_golang v0.9.3/go.mod 
h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso=
+github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod 
h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
+github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod 
h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
+github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod 
h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
+github.com/prometheus/common v0.4.0/go.mod 
h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
+github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod 
h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
+github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod 
h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
+github.com/prometheus/tsdb v0.7.1/go.mod 
h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
+github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod 
h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
+github.com/rogpeppe/go-internal v1.3.0/go.mod 
h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
+github.com/russross/blackfriday/v2 v2.0.1/go.mod 
h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
+github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod 
h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
+github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod 
h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
+github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod 
h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
+github.com/sirupsen/logrus v1.2.0/go.mod 
h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
+github.com/sirupsen/logrus v1.4.2/go.mod 
h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
+github.com/sirupsen/logrus v1.8.1 
h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE=
+github.com/sirupsen/logrus v1.8.1/go.mod 
h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
+github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod 
h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
+github.com/smartystreets/goconvey v1.6.4/go.mod 
h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
+github.com/soheilhy/cmux v0.1.4/go.mod 
h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
+github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod 
h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
+github.com/spf13/afero v1.1.2/go.mod 
h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
+github.com/spf13/cast v1.3.0/go.mod 
h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
+github.com/spf13/cobra v1.1.3 h1:xghbfqPkxzxP3C/f3n5DdpAbdKLj4ZE4BWQI362l53M=
+github.com/spf13/cobra v1.1.3/go.mod 
h1:pGADOWyqRD/YMrPZigI/zbliZ2wVD/23d+is3pSWzOo=
+github.com/spf13/jwalterweatherman v1.0.0/go.mod 
h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
+github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod 
h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
+github.com/spf13/pflag v1.0.3/go.mod 
h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
+github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
+github.com/spf13/pflag v1.0.5/go.mod 
h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
+github.com/spf13/viper v1.7.0/go.mod 
h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg=
+github.com/stretchr/objx v0.1.0/go.mod 
h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/objx v0.1.1/go.mod 
h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/testify v0.0.0-20151208002404-e3a8ff8ce365/go.mod 
h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
+github.com/stretchr/testify v1.2.1/go.mod 
h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
+github.com/stretchr/testify v1.2.2/go.mod 
h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
+github.com/stretchr/testify v1.3.0/go.mod 
h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
+github.com/stretchr/testify v1.4.0/go.mod 
h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
+github.com/stretchr/testify v1.6.1 
h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
+github.com/stretchr/testify v1.6.1/go.mod 
h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+github.com/subosito/gotenv v1.2.0/go.mod 
h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
+github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod 
h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
+github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod 
h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
+go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
+go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
+go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
+go.uber.org/atomic v1.4.0/go.mod 
h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
+go.uber.org/multierr v1.1.0/go.mod 
h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
+go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
+golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod 
h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
+golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod 
h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
+golang.org/x/crypto v0.0.0-20190123085648-057139ce5d2b/go.mod 
h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
+golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod 
h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
+golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod 
h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod 
h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod 
h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod 
h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
+golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod 
h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
+golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod 
h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
+golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod 
h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek=
+golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod 
h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=
+golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod 
h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
+golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod 
h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
+golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod 
h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
+golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod 
h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
+golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod 
h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
+golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod 
h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
+golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod 
h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
+golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod 
h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
+golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod 
h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
+golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod 
h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
+golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod 
h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
+golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod 
h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
+golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
+golang.org/x/net v0.0.0-20170114055629-f2499483f923/go.mod 
h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod 
h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod 
h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod 
h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod 
h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod 
h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod 
h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod 
h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod 
h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod 
h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod 
h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod 
h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod 
h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod 
h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod 
h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
+golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod 
h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20191004110552-13f9640d40b9/go.mod 
h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20191105084925-a882066a44e0/go.mod 
h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20210415231046-e915ea6b2b7d 
h1:BgJvlyh+UqCUaPlscHJ+PN8GcpfrFdr7NHjd1JL0+Gs=
+golang.org/x/net v0.0.0-20210415231046-e915ea6b2b7d/go.mod 
h1:9tjilg8BloeKEkVJvy7fQ90B1CfIiPueXVOjqfkSzI8=
+golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod 
h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
+golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod 
h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
+golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod 
h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
+golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod 
h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod 
h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod 
h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod 
h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod 
h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sys v0.0.0-20170830134202-bb24a47a89ea/go.mod 
h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20180606202747-9527bec2660b/go.mod 
h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod 
h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod 
h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod 
h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod 
h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod 
h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod 
h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod 
h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod 
h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod 
h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod 
h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod 
h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod 
h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod 
h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod 
h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod 
h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod 
h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191010194322-b09406accb47/go.mod 
h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod 
h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod 
h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod 
h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20201009025420-dfb3f7c4e634/go.mod 
h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod 
h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20201214210602-f9fddec55a1e/go.mod 
h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod 
h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210415045647-66c3f260301c 
h1:6L+uOeS3OQt/f4eFHXZcTxeZrGCuz+CLElgEBjbcTA4=
+golang.org/x/sys v0.0.0-20210415045647-66c3f260301c/go.mod 
h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod 
h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
+golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod 
h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod 
h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
+golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod 
h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod 
h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod 
h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod 
h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20181011042414-1f849cf54d09/go.mod 
h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod 
h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod 
h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod 
h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
+golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod 
h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod 
h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod 
h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod 
h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod 
h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
+golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod 
h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
+golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod 
h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
+golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod 
h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
+golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod 
h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
+golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod 
h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod 
h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod 
h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod 
h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod 
h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+google.golang.org/api v0.4.0/go.mod 
h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
+google.golang.org/api v0.7.0/go.mod 
h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
+google.golang.org/api v0.8.0/go.mod 
h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
+google.golang.org/api v0.9.0/go.mod 
h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
+google.golang.org/api v0.13.0/go.mod 
h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
+google.golang.org/appengine v1.1.0/go.mod 
h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
+google.golang.org/appengine v1.4.0/go.mod 
h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
+google.golang.org/appengine v1.5.0/go.mod 
h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
+google.golang.org/appengine v1.6.1/go.mod 
h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
+google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod 
h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
+google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod 
h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
+google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod 
h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
+google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod 
h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
+google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod 
h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
+google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod 
h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
+google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod 
h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
+google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod 
h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
+google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod 
h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
+google.golang.org/grpc v1.19.0/go.mod 
h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
+google.golang.org/grpc v1.20.1/go.mod 
h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
+google.golang.org/grpc v1.21.1/go.mod 
h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
+gopkg.in/AlecAivazis/survey.v1 v1.8.5/go.mod 
h1:iBNOmqKz/NUbZx3bA+4hAGLRC7fSK7tgtVDT4tB22XA=
+gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod 
h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod 
h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod 
h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c 
h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
+gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod 
h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
+gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
+gopkg.in/fsnotify.v1 v1.4.7/go.mod 
h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
+gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
+gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
+gopkg.in/natefinch/lumberjack.v2 v2.0.0 
h1:1Lc07Kr7qY4U2YPouBjpCLxpiyxIVoxqXgkXLknAOE8=
+gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod 
h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k=
+gopkg.in/resty.v1 v1.12.0/go.mod 
h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
+gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod 
h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
+gopkg.in/tomb.v2 v2.0.0-20161208151619-d5d1b5820637 
h1:yiW+nvdHb9LVqSHQBXfZCieqV4fzYhNBql77zY0ykqs=
+gopkg.in/tomb.v2 v2.0.0-20161208151619-d5d1b5820637/go.mod 
h1:BHsqpu/nsuzkT5BpiH1EMZPLyqSMM8JbIavyFACoFNk=
+gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod 
h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
+gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
+gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
+gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod 
h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b 
h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
+gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod 
h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod 
h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod 
h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod 
h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+honnef.co/go/tools v0.0.1-2019.2.3/go.mod 
h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
+k8s.io/apimachinery v0.0.0-20191123233150-4c4803ed55e3 
h1:FErmbNIJruD5GT2oVEjtPn5Ar5+rcWJsC8/PPUkR0s4=
+k8s.io/apimachinery v0.0.0-20191123233150-4c4803ed55e3/go.mod 
h1:b9qmWdKlLuU9EBh+06BtLcSf/Mu89rWL33naRxs1uZg=
+k8s.io/gengo v0.0.0-20190128074634-0689ccc1d7d6/go.mod 
h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0=
+k8s.io/klog v0.0.0-20181102134211-b9b56d5dfc92/go.mod 
h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk=
+k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I=
+k8s.io/kube-openapi v0.0.0-20191107075043-30be4d16710a/go.mod 
h1:1TqjTSzOxsLGIKfj0lK8EeCP7K1iUG65v09OM0/WG5E=
+rsc.io/binaryregexp v0.2.0/go.mod 
h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
+sigs.k8s.io/structured-merge-diff v0.0.0-20190525122527-15d366b2352e/go.mod 
h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI=
+sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=
diff --git a/pegic/interactive/cmd/compression.go 
b/pegic/interactive/cmd/compression.go
new file mode 100644
index 00000000..4ab35e7b
--- /dev/null
+++ b/pegic/interactive/cmd/compression.go
@@ -0,0 +1,77 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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"
+       "strings"
+
+       "github.com/apache/incubator-pegasus/pegic/executor/util"
+       "github.com/apache/incubator-pegasus/pegic/interactive"
+       "github.com/desertbit/grumble"
+)
+
+func init() {
+       rootCmd := &grumble.Command{
+               Name: "compression",
+               Help: "read the current compression algorithm",
+               Run: func(c *grumble.Context) error {
+                       if globalContext.Compressor == nil {
+                               c.App.Println("No compression is used")
+                       } else {
+                               c.App.Printf("Compression: %s\n", 
globalContext.Compressor.String())
+                       }
+                       return nil
+               },
+       }
+
+       rootCmd.AddCommand(&grumble.Command{
+               Name:    "set",
+               Aliases: []string{"SET"},
+               Help:    "reset the compression algorithm, default no",
+               Run: func(c *grumble.Context) error {
+                       algo := strings.TrimSpace(c.Args.String("ALGORITHM"))
+                       if algo == "" || algo == "no" {
+                               c.App.Println("Reset to no compression mode")
+                               globalContext.Compressor = nil
+                               return nil
+                       }
+                       globalContext.Compressor = util.NewCompression(algo)
+                       if globalContext.Compressor == nil {
+                               return fmt.Errorf("Invalid compression 
algorithm \"%s\"", algo)
+                       }
+                       c.App.Println("ok")
+                       return nil
+               },
+               Args: func(a *grumble.Args) {
+                       a.String("ALGORITHM", "Compression algorithm. By 
default no compression is used. Options: zstd", grumble.Default(""))
+               },
+               Completer: compressionCompleter,
+       })
+
+       interactive.App.AddCommand(rootCmd)
+}
+
+func compressionCompleter(prefix string, args []string) []string {
+       return filterStringWithPrefix([]string{
+               "zstd",
+               "no",
+       }, prefix)
+}
diff --git a/pegic/interactive/cmd/del.go b/pegic/interactive/cmd/del.go
new file mode 100644
index 00000000..bb140541
--- /dev/null
+++ b/pegic/interactive/cmd/del.go
@@ -0,0 +1,46 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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"
+
+       "github.com/apache/incubator-pegasus/pegic/executor"
+       "github.com/apache/incubator-pegasus/pegic/interactive"
+       "github.com/desertbit/grumble"
+)
+
+func init() {
+       interactive.App.AddCommand(&grumble.Command{
+               Name:  "del",
+               Help:  "delete a record",
+               Usage: "del <HASHKEY> <SORTKEY>",
+               Run: requireUseTable(printEndingContext(func(c 
*grumble.Context) error {
+                       if len(c.Args) != 2 {
+                               return fmt.Errorf("invalid number (%d) of 
arguments for `del`", len(c.Args))
+                       }
+                       return executor.Del(globalContext, 
c.Args.String("HASHKEY"), c.Args.String("SORTKEY"))
+               })),
+               Args: func(a *grumble.Args) {
+                       a.String("HASHKEY", "HashKey")
+                       a.String("SORTKEY", "SortKey")
+               },
+       })
+}
diff --git a/pegic/interactive/cmd/encoding.go 
b/pegic/interactive/cmd/encoding.go
new file mode 100644
index 00000000..98bad43b
--- /dev/null
+++ b/pegic/interactive/cmd/encoding.go
@@ -0,0 +1,111 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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"
+       "strings"
+
+       "github.com/apache/incubator-pegasus/pegic/executor/util"
+       "github.com/apache/incubator-pegasus/pegic/interactive"
+       "github.com/desertbit/grumble"
+)
+
+var supportedEncodings = []string{
+       "utf8",
+       "int32",
+       "int64",
+       "bytes",
+       "javabytes",
+       "asciihex",
+}
+
+func init() {
+       rootCmd := &grumble.Command{
+               Name: "encoding",
+               Help: "read the current encoding",
+               Run: func(c *grumble.Context) error {
+                       c.App.Println(globalContext)
+                       return nil
+               },
+       }
+
+       rootCmd.AddCommand(&grumble.Command{
+               Name: "hashkey",
+               Help: fmt.Sprintf("Set encoding for hashkey. Supported 
encodings: %s", supportedEncodingsToString()),
+               Run: func(c *grumble.Context) error {
+                       return resetEncoding(c, &globalContext.HashKeyEnc)
+               },
+               Args:      registerArgs,
+               Completer: encodingCompleter,
+       })
+
+       rootCmd.AddCommand(&grumble.Command{
+               Name: "sortkey",
+               Help: fmt.Sprintf("Set encoding for sortkey. Supported 
encodings: %s", supportedEncodingsToString()),
+               Run: func(c *grumble.Context) error {
+                       return resetEncoding(c, &globalContext.SortKeyEnc)
+               },
+               Args:      registerArgs,
+               Completer: encodingCompleter,
+       })
+
+       rootCmd.AddCommand(&grumble.Command{
+               Name: "value",
+               Help: fmt.Sprintf("Set encoding for value. Supported encodings: 
%s", supportedEncodingsToString()),
+               Run: func(c *grumble.Context) error {
+                       return resetEncoding(c, &globalContext.ValueEnc)
+               },
+               Args:      registerArgs,
+               Completer: encodingCompleter,
+       })
+
+       interactive.App.AddCommand(rootCmd)
+}
+
+// resetEncoding is the generic executor for the encoding-reset commands
+func resetEncoding(c *grumble.Context, encPtr *util.Encoder) error {
+       if len(c.Args) != 1 {
+               return fmt.Errorf("invalid number (%d) of arguments for 
`encoding %s`", len(c.Args), c.Command.Name)
+       }
+
+       encoding := c.Args.String("ENCODING")
+       enc := util.NewEncoder(encoding)
+       if enc == nil {
+               return fmt.Errorf("uncognized encoding: %s", encoding)
+       }
+       *encPtr = enc
+       c.App.Println(globalContext)
+       return nil
+}
+
+func encodingCompleter(prefix string, args []string) []string {
+       return filterStringWithPrefix(supportedEncodings, prefix)
+}
+
+func supportedEncodingsToString() string {
+       return strings.Join(supportedEncodings, ",")
+}
+
+func registerArgs(a *grumble.Args) {
+       a.String("ENCODING",
+               fmt.Sprintf("The encoding from user string to raw bytes. 
Supported encodings: %s", supportedEncodingsToString()),
+               grumble.Default("utf8"))
+}
diff --git a/pegic/interactive/cmd/get.go b/pegic/interactive/cmd/get.go
new file mode 100644
index 00000000..8cda53f3
--- /dev/null
+++ b/pegic/interactive/cmd/get.go
@@ -0,0 +1,45 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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"
+
+       "github.com/apache/incubator-pegasus/pegic/executor"
+       "github.com/apache/incubator-pegasus/pegic/interactive"
+       "github.com/desertbit/grumble"
+)
+
+func init() {
+       interactive.App.AddCommand(&grumble.Command{
+               Name:  "get",
+               Help:  "read a record from Pegasus",
+               Usage: "get <HASHKEY> <SORTKEY>",
+               Run: requireUseTable(printEndingContext(func(c 
*grumble.Context) error {
+                       if len(c.Args) != 2 {
+                               return fmt.Errorf("invalid number (%d) of 
arguments for `get`", len(c.Args))
+                       }
+                       return executor.Get(globalContext, 
c.Args.String("HASHKEY"), c.Args.String("SORTKEY"))
+               })),
+               Args: func(a *grumble.Args) {
+                       a.String("HASHKEY", "HashKey")
+                       a.String("SORTKEY", "SortKey")
+               }})
+}
diff --git a/pegic/interactive/cmd/init.go b/pegic/interactive/cmd/init.go
new file mode 100644
index 00000000..0614801a
--- /dev/null
+++ b/pegic/interactive/cmd/init.go
@@ -0,0 +1,76 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 (
+       "errors"
+       "os"
+       "strings"
+
+       "github.com/XiaoMi/pegasus-go-client/session"
+       "github.com/apache/incubator-pegasus/pegic/executor"
+       "github.com/desertbit/grumble"
+)
+
+var globalContext *executor.Context
+
+func Init(metaAddrs []string) error {
+       // validate meta addresses
+       _, err := session.ResolveMetaAddr(metaAddrs)
+       if err != nil {
+               return err
+       }
+
+       globalContext = executor.NewContext(os.Stdout, metaAddrs)
+       return nil
+}
+
+func requireUseTable(run func(*grumble.Context) error) func(c 
*grumble.Context) error {
+       grumbleRun := func(c *grumble.Context) error {
+               if globalContext.UseTable == nil {
+                       c.App.PrintError(errors.New("please USE a table first"))
+                       c.App.Println("Usage: USE <TABLE_NAME>")
+                       return nil
+               }
+               return run(c)
+       }
+       return grumbleRun
+}
+
+// filterStringWithPrefix returns strings with the same prefix.
+// This function is commonly used for the auto-completion of commands.
+func filterStringWithPrefix(strs []string, prefix string) []string {
+       var result []string
+       for _, s := range strs {
+               if strings.HasPrefix(s, prefix) {
+                       result = append(result, s)
+               }
+       }
+       return result
+}
+
+func printEndingContext(run func(*grumble.Context) error) func(c 
*grumble.Context) error {
+       grumbleRun := func(c *grumble.Context) error {
+               err := run(c)
+               c.App.Println(globalContext)
+               return err
+       }
+       return grumbleRun
+}
diff --git a/pegic/interactive/cmd/partition_index.go 
b/pegic/interactive/cmd/partition_index.go
new file mode 100644
index 00000000..48d64b8e
--- /dev/null
+++ b/pegic/interactive/cmd/partition_index.go
@@ -0,0 +1,51 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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"
+
+       "github.com/apache/incubator-pegasus/pegic/executor"
+       "github.com/apache/incubator-pegasus/pegic/interactive"
+       "github.com/desertbit/grumble"
+)
+
+func init() {
+       rootCmd := &grumble.Command{
+               Name:  "partition-index",
+               Help:  "ADVANCED: calculate the partition index where the 
hashkey is routed to",
+               Usage: "partition-index <HASHKEY>",
+               Run: requireUseTable(func(c *grumble.Context) error {
+                       if len(c.Args) != 1 {
+                               return fmt.Errorf("invalid number (%d) of 
arguments for `partition-index`", len(c.Args))
+                       }
+                       err := executor.PartitionIndex(globalContext, 
c.Args.String("HASHKEY"))
+                       if err != nil {
+                               return err
+                       }
+                       c.App.Println(globalContext)
+                       return nil
+               }),
+               Args: func(a *grumble.Args) {
+                       a.String("HASHKEY", "HashKey")
+               },
+       }
+       interactive.App.AddCommand(rootCmd)
+}
diff --git a/pegic/interactive/cmd/scan.go b/pegic/interactive/cmd/scan.go
new file mode 100644
index 00000000..466dc9b2
--- /dev/null
+++ b/pegic/interactive/cmd/scan.go
@@ -0,0 +1,117 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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"
+
+       "github.com/apache/incubator-pegasus/pegic/executor"
+       "github.com/apache/incubator-pegasus/pegic/interactive"
+       "github.com/desertbit/grumble"
+)
+
+func init() {
+       usage := `<hashKey>
+[ --from <startSortKey> ]
+[ --to <stopSortKey> ]
+[
+  --prefix <filter>
+  --suffix <filter>
+  --contains <filter>
+]`
+
+       scanCmd := &grumble.Command{
+               Name:  "scan",
+               Help:  "scan records under the hashkey",
+               Usage: "\nscan " + usage,
+               Run: requireUseTable(printEndingContext(func(c 
*grumble.Context) error {
+                       cmd, err := newScanCommand(c)
+                       if err != nil {
+                               return err
+                       }
+                       return cmd.IterateAll(globalContext)
+               })),
+               Flags: scanFlags,
+               Args: func(a *grumble.Args) {
+                       a.String("HASHKEY", "HashKey")
+               },
+       }
+
+       scanCmd.AddCommand(&grumble.Command{
+               Name:  "count",
+               Help:  "scan records under the hashkey",
+               Usage: "\nscan " + usage,
+               Run: requireUseTable(printEndingContext(func(c 
*grumble.Context) error {
+                       cmd, err := newScanCommand(c)
+                       if err != nil {
+                               return err
+                       }
+                       cmd.CountOnly = true
+                       return cmd.IterateAll(globalContext)
+               })),
+               Flags: scanFlags,
+               Args: func(a *grumble.Args) {
+                       a.String("HASHKEY", "HashKey")
+               },
+       })
+
+       interactive.App.AddCommand(scanCmd)
+}
+
+func newScanCommand(c *grumble.Context) (*executor.ScanCommand, error) {
+       if len(c.Args) < 1 {
+               return nil, fmt.Errorf("missing <hashkey> for `scan`")
+       }
+
+       from := c.Flags.String("from")
+       to := c.Flags.String("to")
+       suffix := c.Flags.String("suffix")
+       prefix := c.Flags.String("prefix")
+       contains := c.Flags.String("contains")
+
+       cmd := &executor.ScanCommand{HashKey: c.Args.String("HASHKEY")}
+       if from != "" {
+               cmd.From = &from
+       }
+       if to != "" {
+               cmd.To = &to
+       }
+       if suffix != "" {
+               cmd.Suffix = &suffix
+       }
+       if prefix != "" {
+               cmd.Prefix = &prefix
+       }
+       if contains != "" {
+               cmd.Contains = &contains
+       }
+       if err := cmd.Validate(); err != nil {
+               return nil, err
+       }
+       return cmd, nil
+}
+
+func scanFlags(f *grumble.Flags) {
+       f.StringL("from", "", "<startSortKey>")
+       f.StringL("to", "", "<stopSortKey>")
+       f.StringL("prefix", "", "<filter>")
+       f.StringL("suffix", "", "<filter>")
+       f.StringL("contains", "", "<filter>")
+}
diff --git a/pegic/interactive/cmd/set.go b/pegic/interactive/cmd/set.go
new file mode 100644
index 00000000..1313796f
--- /dev/null
+++ b/pegic/interactive/cmd/set.go
@@ -0,0 +1,47 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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"
+
+       "github.com/apache/incubator-pegasus/pegic/executor"
+       "github.com/apache/incubator-pegasus/pegic/interactive"
+       "github.com/desertbit/grumble"
+)
+
+func init() {
+       interactive.App.AddCommand(&grumble.Command{
+               Name:  "set",
+               Help:  "write a record into Pegasus",
+               Usage: "set <HASHKEY> <SORTKEY> <VALUE>",
+               Run: requireUseTable(printEndingContext(func(c 
*grumble.Context) error {
+                       if len(c.Args) != 3 {
+                               return fmt.Errorf("invalid number (%d) of 
arguments for `set`", len(c.Args))
+                       }
+                       return executor.Set(globalContext, 
c.Args.String("HASHKEY"), c.Args.String("SORTKEY"), c.Args.String("VALUE"))
+               })),
+               Args: func(a *grumble.Args) {
+                       a.String("HASHKEY", "HashKey")
+                       a.String("SORTKEY", "SortKey")
+                       a.String("VALUE", "Value of the record")
+               },
+       })
+}
diff --git a/pegic/interactive/cmd/use.go b/pegic/interactive/cmd/use.go
new file mode 100644
index 00000000..bf4b4772
--- /dev/null
+++ b/pegic/interactive/cmd/use.go
@@ -0,0 +1,63 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 (
+       "context"
+       "fmt"
+       "strings"
+       "time"
+
+       "github.com/apache/incubator-pegasus/pegic/interactive"
+       "github.com/desertbit/grumble"
+)
+
+func init() {
+       interactive.App.AddCommand(&grumble.Command{
+               Name:  "use",
+               Help:  "select a table",
+               Usage: "use <TABLE_NAME>",
+               Run: func(c *grumble.Context) error {
+                       if len(c.Args) != 1 {
+                               return fmt.Errorf("invalid number (%d) of 
arguments for `use`", len(c.Args))
+                       }
+
+                       ctx, cancel := 
context.WithTimeout(context.Background(), time.Second*10)
+                       defer cancel()
+                       var tableName = c.Args.String("TABLE")
+                       var err error
+                       globalContext.UseTable, err = 
globalContext.OpenTable(ctx, tableName)
+                       if err != nil && strings.Contains(err.Error(), 
"ERR_OBJECT_NOT_FOUND") {
+                               // give a simple prompt to this special error
+                               return fmt.Errorf("table \"%s\" does not 
exist", tableName)
+                       }
+                       if err != nil {
+                               return err
+                       }
+                       globalContext.UseTableName = tableName
+
+                       c.App.Println("ok")
+                       return nil
+               },
+               Args: func(a *grumble.Args) {
+                       a.String("TABLE", "The table name to access.")
+               },
+       })
+}
diff --git a/pegic/interactive/run.go b/pegic/interactive/run.go
new file mode 100644
index 00000000..7c3c5155
--- /dev/null
+++ b/pegic/interactive/run.go
@@ -0,0 +1,48 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 interactive
+
+import (
+       "fmt"
+       "os"
+
+       "github.com/desertbit/grumble"
+)
+
+// App is the global interactive application.
+var App *grumble.App
+
+func init() {
+       App = grumble.New(&grumble.Config{
+               Name:        "pegic",
+               HistoryFile: ".pegic-history",
+               Flags: func(f *grumble.Flags) {
+                       f.String("m", "meta", 
"127.0.0.1:34601,127.0.0.1:34602", "the list of MetaServer addresses")
+               },
+       })
+}
+
+func Run() {
+       err := App.Run()
+       if err != nil {
+               fmt.Fprintln(os.Stderr, err)
+               os.Exit(1)
+       }
+}
diff --git a/pegic/main.go b/pegic/main.go
new file mode 100644
index 00000000..a6f15804
--- /dev/null
+++ b/pegic/main.go
@@ -0,0 +1,45 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 main
+
+import (
+       "fmt"
+       "os"
+
+       "github.com/XiaoMi/pegasus-go-client/pegalog"
+       "github.com/apache/incubator-pegasus/pegic/shell"
+       "github.com/sirupsen/logrus"
+       "gopkg.in/natefinch/lumberjack.v2"
+)
+
+func main() {
+       // pegasus-go-client's logs use the same logger as ours.
+       pegalog.SetLogger(logrus.StandardLogger())
+       // configure log destination
+       logrus.SetOutput(&lumberjack.Logger{
+               Filename:  "./pegic.log",
+               LocalTime: true,
+       })
+
+       if err := shell.Root.Execute(); err != nil {
+               fmt.Fprintln(os.Stderr, err)
+               os.Exit(1)
+       }
+}
diff --git a/pegic/shell/app.go b/pegic/shell/app.go
new file mode 100644
index 00000000..db30e9dd
--- /dev/null
+++ b/pegic/shell/app.go
@@ -0,0 +1,55 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 shell
+
+import (
+       "os"
+       "strings"
+
+       "github.com/apache/incubator-pegasus/pegic/interactive"
+       "github.com/apache/incubator-pegasus/pegic/interactive/cmd"
+       "github.com/spf13/cobra"
+)
+
+// Root command for pegic.
+var Root *cobra.Command
+
+func init() {
+       var metaList *string
+
+       Root = &cobra.Command{
+               Use:   "pegic [--meta|-m <meta-list>]",
+               Short: "pegic: Pegasus Interactive Command-Line tool",
+               PreRun: func(c *cobra.Command, args []string) {
+                       metaAddrs := strings.Split(*metaList, ",")
+                       err := cmd.Init(metaAddrs)
+                       if err != nil {
+                               c.PrintErrln(err)
+                               os.Exit(1)
+                       }
+               },
+               Run: func(cmd *cobra.Command, args []string) {
+                       // the default entrance is interactive
+                       interactive.Run()
+               },
+       }
+
+       metaList = Root.Flags().StringP("meta", "m", 
"127.0.0.1:34601,127.0.0.1:34602", "the list of MetaServer addresses")
+}
diff --git a/pegic/shell/convert.go b/pegic/shell/convert.go
new file mode 100644
index 00000000..4226b561
--- /dev/null
+++ b/pegic/shell/convert.go
@@ -0,0 +1,68 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 shell
+
+import (
+       "github.com/apache/incubator-pegasus/pegic/executor/util"
+       "github.com/spf13/cobra"
+)
+
+func init() {
+       // flags
+       var from *string
+       var to *string
+
+       cmd := &cobra.Command{
+               Use:   "convert",
+               Short: "convert bytes from one encoding to the other",
+               Args:  cobra.ExactArgs(1),
+               Run: func(c *cobra.Command, args []string) {
+                       fromEnc := util.NewEncoder(*from)
+                       if fromEnc == nil {
+                               c.PrintErrf("invalid encoding: \"%s\"", *from)
+                               return
+                       }
+                       toEnc := util.NewEncoder(*to)
+                       if toEnc == nil {
+                               c.PrintErrf("invalid encoding: \"%s\"", *to)
+                               return
+                       }
+
+                       data, err := fromEnc.EncodeAll(args[0])
+                       if err != nil {
+                               c.PrintErr(err)
+                               return
+                       }
+                       result, err := toEnc.DecodeAll(data)
+                       if err != nil {
+                               c.PrintErr(err)
+                               return
+                       }
+                       c.Println(result)
+               },
+       }
+
+       from = cmd.Flags().String("from", "", "the original encoding of the 
given bytes")
+       to = cmd.Flags().String("to", "", "the original encoding of the given 
bytes")
+       _ = cmd.MarkFlagRequired("from")
+       _ = cmd.MarkFlagRequired("to")
+
+       Root.AddCommand(cmd)
+}
diff --git a/rdsn b/rdsn
index da843900..47fd85c2 160000
--- a/rdsn
+++ b/rdsn
@@ -1 +1 @@
-Subproject commit da843900f4d89e658038048775d9adf9604bd5ec
+Subproject commit 47fd85c29bd446495388e1ab3a46bd741c99c443


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to