From d3aeea569adcbdb09ca5edfbafce3d7a39dfff19 Mon Sep 17 00:00:00 2001
From: Malte Bauch <malte.bauch@tbnet.works>
Date: Fri, 6 May 2022 12:19:00 +0000
Subject: [PATCH] Improve usability and better output formatting for gosndc

See merge request danet/gosdn!284

Co-authored-by: Malte Bauch <malte.bauch@extern.h-da.de>
---
 .golangci.yml                                 |   1 +
 api/go/gosdn/pnd/pnd.pb.go                    | 653 +++++++++---------
 api/go/gosdn/pnd/pnd.pb.gw.go                 |   4 +-
 api/openapiv2/gosdn_northbound.swagger.json   |  23 +-
 api/proto/buf.lock                            |   6 +
 api/proto/gosdn/pnd/pnd.proto                 |  27 +-
 cli/adapter/OndAdapter.go                     |   1 -
 cli/adapter/PndAdapter.go                     |  84 +--
 cli/adapter/PndAdapter_test.go                |  12 +-
 cli/cmd/changeCommit.go                       |  12 +-
 cli/cmd/changeConfirm.go                      |  13 +-
 cli/cmd/{init.go => changeGet.go}             |  55 +-
 cli/cmd/changeList.go                         |  36 +-
 cli/cmd/deviceCreate.go                       |  12 +-
 cli/cmd/deviceDelete.go                       |  20 +-
 cli/cmd/deviceGet.go                          |  27 +-
 cli/cmd/deviceList.go                         |  26 +-
 cli/cmd/deviceRemove.go                       |   9 +-
 cli/cmd/deviceSet.go                          |  25 +-
 cli/cmd/deviceShow.go                         |  15 +-
 cli/cmd/login.go                              |  34 +-
 cli/cmd/pndCreate.go                          |  21 +-
 cli/cmd/pndGet.go                             |  12 +-
 cli/cmd/pndList.go                            |  17 +-
 cli/cmd/pndRemove.go                          |  13 +-
 cli/cmd/pndUse.go                             |  17 +-
 cli/cmd/prompt.go                             | 281 ++++++--
 cli/cmd/root.go                               |   3 +-
 cli/cmd/utils.go                              |  48 +-
 controller/api/change.go                      |  25 +-
 controller/api/initialise_test.go             |  19 +-
 controller/api/pnd.go                         |   3 -
 controller/interfaces/change/change.go        |   2 +
 controller/interfaces/networkdomain/pnd.go    |   2 +-
 controller/mocks/Change.go                    |  49 +-
 controller/mocks/Device.go                    |  33 +-
 controller/mocks/NetworkDomain.go             |  32 +-
 controller/mocks/Plugin.go                    |  16 +-
 controller/mocks/SouthboundInterface.go       |  13 +-
 controller/mocks/Storable.go                  |  13 +-
 controller/mocks/Transport.go                 |  13 +-
 controller/northbound/server/pnd.go           |  26 +-
 controller/nucleus/change.go                  |  12 +
 controller/nucleus/principalNetworkDomain.go  |  58 +-
 .../nucleus/principalNetworkDomain_test.go    |  35 +-
 .../integration/nucleusIntegration_test.go    |   3 +-
 go.mod                                        |  13 +-
 go.sum                                        |  42 +-
 48 files changed, 1210 insertions(+), 706 deletions(-)
 delete mode 100644 cli/adapter/OndAdapter.go
 rename cli/cmd/{init.go => changeGet.go} (57%)

diff --git a/.golangci.yml b/.golangci.yml
index 894ea22bf..cccc94d98 100644
--- a/.golangci.yml
+++ b/.golangci.yml
@@ -5,6 +5,7 @@ run:
     issues-exit-code: 1
     # directories to be ignored by linters
     skip-dirs:
+        - artifacts
         - controller/forks
         - controller/test
         - controller/mocks
diff --git a/api/go/gosdn/pnd/pnd.pb.go b/api/go/gosdn/pnd/pnd.pb.go
index 3738f74a0..9c8932f78 100644
--- a/api/go/gosdn/pnd/pnd.pb.go
+++ b/api/go/gosdn/pnd/pnd.pb.go
@@ -292,7 +292,7 @@ type GetOndListRequest struct {
 	unknownFields protoimpl.UnknownFields
 
 	Timestamp int64  `protobuf:"varint,1,opt,name=timestamp,proto3" json:"timestamp,omitempty"` // Timestamp in nanoseconds since Epoch.
-	Pid       string `protobuf:"bytes,4,opt,name=pid,proto3" json:"pid,omitempty"`
+	Pid       string `protobuf:"bytes,2,opt,name=pid,proto3" json:"pid,omitempty"`
 }
 
 func (x *GetOndListRequest) Reset() {
@@ -347,8 +347,8 @@ type GetOndRequest struct {
 	unknownFields protoimpl.UnknownFields
 
 	Timestamp int64    `protobuf:"varint,1,opt,name=timestamp,proto3" json:"timestamp,omitempty"` // Timestamp in nanoseconds since Epoch.
-	Did       []string `protobuf:"bytes,3,rep,name=did,proto3" json:"did,omitempty"`
-	Pid       string   `protobuf:"bytes,4,opt,name=pid,proto3" json:"pid,omitempty"`
+	Did       []string `protobuf:"bytes,2,rep,name=did,proto3" json:"did,omitempty"`
+	Pid       string   `protobuf:"bytes,3,opt,name=pid,proto3" json:"pid,omitempty"`
 }
 
 func (x *GetOndRequest) Reset() {
@@ -410,7 +410,7 @@ type GetSbiListRequest struct {
 	unknownFields protoimpl.UnknownFields
 
 	Timestamp int64  `protobuf:"varint,1,opt,name=timestamp,proto3" json:"timestamp,omitempty"` // Timestamp in nanoseconds since Epoch.
-	Pid       string `protobuf:"bytes,4,opt,name=pid,proto3" json:"pid,omitempty"`
+	Pid       string `protobuf:"bytes,2,opt,name=pid,proto3" json:"pid,omitempty"`
 }
 
 func (x *GetSbiListRequest) Reset() {
@@ -465,8 +465,8 @@ type GetSbiRequest struct {
 	unknownFields protoimpl.UnknownFields
 
 	Timestamp int64    `protobuf:"varint,1,opt,name=timestamp,proto3" json:"timestamp,omitempty"` // Timestamp in nanoseconds since Epoch.
-	Sid       []string `protobuf:"bytes,3,rep,name=sid,proto3" json:"sid,omitempty"`
-	Pid       string   `protobuf:"bytes,4,opt,name=pid,proto3" json:"pid,omitempty"`
+	Sid       []string `protobuf:"bytes,2,rep,name=sid,proto3" json:"sid,omitempty"`
+	Pid       string   `protobuf:"bytes,3,opt,name=pid,proto3" json:"pid,omitempty"`
 }
 
 func (x *GetSbiRequest) Reset() {
@@ -528,7 +528,7 @@ type GetChangeListRequest struct {
 	unknownFields protoimpl.UnknownFields
 
 	Timestamp int64  `protobuf:"varint,1,opt,name=timestamp,proto3" json:"timestamp,omitempty"` // Timestamp in nanoseconds since Epoch.
-	Pid       string `protobuf:"bytes,4,opt,name=pid,proto3" json:"pid,omitempty"`
+	Pid       string `protobuf:"bytes,2,opt,name=pid,proto3" json:"pid,omitempty"`
 }
 
 func (x *GetChangeListRequest) Reset() {
@@ -582,9 +582,9 @@ type GetChangeRequest struct {
 	sizeCache     protoimpl.SizeCache
 	unknownFields protoimpl.UnknownFields
 
-	Timestamp int64  `protobuf:"varint,1,opt,name=timestamp,proto3" json:"timestamp,omitempty"` // Timestamp in nanoseconds since Epoch.
-	Cuid      string `protobuf:"bytes,3,opt,name=cuid,proto3" json:"cuid,omitempty"`
-	Pid       string `protobuf:"bytes,4,opt,name=pid,proto3" json:"pid,omitempty"`
+	Timestamp int64    `protobuf:"varint,1,opt,name=timestamp,proto3" json:"timestamp,omitempty"` // Timestamp in nanoseconds since Epoch.
+	Cuid      []string `protobuf:"bytes,2,rep,name=cuid,proto3" json:"cuid,omitempty"`
+	Pid       string   `protobuf:"bytes,3,opt,name=pid,proto3" json:"pid,omitempty"`
 }
 
 func (x *GetChangeRequest) Reset() {
@@ -626,11 +626,11 @@ func (x *GetChangeRequest) GetTimestamp() int64 {
 	return 0
 }
 
-func (x *GetChangeRequest) GetCuid() string {
+func (x *GetChangeRequest) GetCuid() []string {
 	if x != nil {
 		return x.Cuid
 	}
-	return ""
+	return nil
 }
 
 func (x *GetChangeRequest) GetPid() string {
@@ -1305,9 +1305,10 @@ type Change struct {
 	sizeCache     protoimpl.SizeCache
 	unknownFields protoimpl.UnknownFields
 
-	Id    string      `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
-	Age   int64       `protobuf:"varint,2,opt,name=age,proto3" json:"age,omitempty"`
-	State ChangeState `protobuf:"varint,3,opt,name=state,proto3,enum=gosdn.pnd.ChangeState" json:"state,omitempty"`
+	Id    string             `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
+	Age   int64              `protobuf:"varint,2,opt,name=age,proto3" json:"age,omitempty"`
+	State ChangeState        `protobuf:"varint,3,opt,name=state,proto3,enum=gosdn.pnd.ChangeState" json:"state,omitempty"`
+	Diff  *gnmi.Notification `protobuf:"bytes,4,opt,name=diff,proto3" json:"diff,omitempty"`
 }
 
 func (x *Change) Reset() {
@@ -1363,6 +1364,13 @@ func (x *Change) GetState() ChangeState {
 	return ChangeState_CHANGE_STATE_UNSPECIFIED
 }
 
+func (x *Change) GetDiff() *gnmi.Notification {
+	if x != nil {
+		return x.Diff
+	}
+	return nil
+}
+
 type SetOndListRequest struct {
 	state         protoimpl.MessageState
 	sizeCache     protoimpl.SizeCache
@@ -1866,7 +1874,8 @@ type SetResponse struct {
 	unknownFields protoimpl.UnknownFields
 
 	Timestamp int64  `protobuf:"varint,1,opt,name=timestamp,proto3" json:"timestamp,omitempty"` // Timestamp in nanoseconds since Epoch.
-	Status    Status `protobuf:"varint,2,opt,name=status,proto3,enum=gosdn.pnd.Status" json:"status,omitempty"`
+	Id        string `protobuf:"bytes,2,opt,name=id,proto3" json:"id,omitempty"`
+	Status    Status `protobuf:"varint,3,opt,name=status,proto3,enum=gosdn.pnd.Status" json:"status,omitempty"`
 }
 
 func (x *SetResponse) Reset() {
@@ -1908,6 +1917,13 @@ func (x *SetResponse) GetTimestamp() int64 {
 	return 0
 }
 
+func (x *SetResponse) GetId() string {
+	if x != nil {
+		return x.Id
+	}
+	return ""
+}
+
 func (x *SetResponse) GetStatus() Status {
 	if x != nil {
 		return x.Status
@@ -2228,8 +2244,8 @@ type DeleteOndRequest struct {
 	unknownFields protoimpl.UnknownFields
 
 	Timestamp int64  `protobuf:"varint,1,opt,name=timestamp,proto3" json:"timestamp,omitempty"` // Timestamp in nanoseconds since Epoch.
-	Pid       string `protobuf:"bytes,4,opt,name=pid,proto3" json:"pid,omitempty"`
-	Did       string `protobuf:"bytes,5,opt,name=did,proto3" json:"did,omitempty"`
+	Pid       string `protobuf:"bytes,2,opt,name=pid,proto3" json:"pid,omitempty"`
+	Did       string `protobuf:"bytes,3,opt,name=did,proto3" json:"did,omitempty"`
 }
 
 func (x *DeleteOndRequest) Reset() {
@@ -2363,31 +2379,31 @@ var file_gosdn_pnd_pnd_proto_rawDesc = []byte{
 	0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x74,
 	0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09,
 	0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x10, 0x0a, 0x03, 0x70, 0x69, 0x64,
-	0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x70, 0x69, 0x64, 0x22, 0x51, 0x0a, 0x0d, 0x47,
+	0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x70, 0x69, 0x64, 0x22, 0x51, 0x0a, 0x0d, 0x47,
 	0x65, 0x74, 0x4f, 0x6e, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1c, 0x0a, 0x09,
 	0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52,
 	0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x10, 0x0a, 0x03, 0x64, 0x69,
-	0x64, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x03, 0x64, 0x69, 0x64, 0x12, 0x10, 0x0a, 0x03,
-	0x70, 0x69, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x70, 0x69, 0x64, 0x22, 0x43,
+	0x64, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x03, 0x64, 0x69, 0x64, 0x12, 0x10, 0x0a, 0x03,
+	0x70, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x70, 0x69, 0x64, 0x22, 0x43,
 	0x0a, 0x11, 0x47, 0x65, 0x74, 0x53, 0x62, 0x69, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75,
 	0x65, 0x73, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70,
 	0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d,
-	0x70, 0x12, 0x10, 0x0a, 0x03, 0x70, 0x69, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03,
+	0x70, 0x12, 0x10, 0x0a, 0x03, 0x70, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03,
 	0x70, 0x69, 0x64, 0x22, 0x51, 0x0a, 0x0d, 0x47, 0x65, 0x74, 0x53, 0x62, 0x69, 0x52, 0x65, 0x71,
 	0x75, 0x65, 0x73, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d,
 	0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61,
-	0x6d, 0x70, 0x12, 0x10, 0x0a, 0x03, 0x73, 0x69, 0x64, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52,
-	0x03, 0x73, 0x69, 0x64, 0x12, 0x10, 0x0a, 0x03, 0x70, 0x69, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28,
+	0x6d, 0x70, 0x12, 0x10, 0x0a, 0x03, 0x73, 0x69, 0x64, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52,
+	0x03, 0x73, 0x69, 0x64, 0x12, 0x10, 0x0a, 0x03, 0x70, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28,
 	0x09, 0x52, 0x03, 0x70, 0x69, 0x64, 0x22, 0x46, 0x0a, 0x14, 0x47, 0x65, 0x74, 0x43, 0x68, 0x61,
 	0x6e, 0x67, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1c,
 	0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28,
 	0x03, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x10, 0x0a, 0x03,
-	0x70, 0x69, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x70, 0x69, 0x64, 0x22, 0x56,
+	0x70, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x70, 0x69, 0x64, 0x22, 0x56,
 	0x0a, 0x10, 0x47, 0x65, 0x74, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65,
 	0x73, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18,
 	0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70,
-	0x12, 0x12, 0x0a, 0x04, 0x63, 0x75, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04,
-	0x63, 0x75, 0x69, 0x64, 0x12, 0x10, 0x0a, 0x03, 0x70, 0x69, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28,
+	0x12, 0x12, 0x0a, 0x04, 0x63, 0x75, 0x69, 0x64, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x04,
+	0x63, 0x75, 0x69, 0x64, 0x12, 0x10, 0x0a, 0x03, 0x70, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28,
 	0x09, 0x52, 0x03, 0x70, 0x69, 0x64, 0x22, 0x66, 0x0a, 0x0e, 0x47, 0x65, 0x74, 0x50, 0x61, 0x74,
 	0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65,
 	0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x74, 0x69, 0x6d,
@@ -2480,85 +2496,79 @@ var file_gosdn_pnd_pnd_proto_rawDesc = []byte{
 	0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x73, 0x6f, 0x75, 0x74,
 	0x68, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x2e, 0x53, 0x6f, 0x75, 0x74, 0x68, 0x62, 0x6f, 0x75, 0x6e,
 	0x64, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x52, 0x03, 0x73, 0x62, 0x69, 0x22,
-	0x58, 0x0a, 0x06, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18,
-	0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x10, 0x0a, 0x03, 0x61, 0x67, 0x65,
-	0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x03, 0x61, 0x67, 0x65, 0x12, 0x2c, 0x0a, 0x05, 0x73,
-	0x74, 0x61, 0x74, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x16, 0x2e, 0x67, 0x6f, 0x73,
-	0x64, 0x6e, 0x2e, 0x70, 0x6e, 0x64, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x53, 0x74, 0x61,
-	0x74, 0x65, 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x22, 0x68, 0x0a, 0x11, 0x53, 0x65, 0x74,
-	0x4f, 0x6e, 0x64, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1c,
+	0x80, 0x01, 0x0a, 0x06, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64,
+	0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x10, 0x0a, 0x03, 0x61, 0x67,
+	0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x03, 0x61, 0x67, 0x65, 0x12, 0x2c, 0x0a, 0x05,
+	0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x16, 0x2e, 0x67, 0x6f,
+	0x73, 0x64, 0x6e, 0x2e, 0x70, 0x6e, 0x64, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x53, 0x74,
+	0x61, 0x74, 0x65, 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x12, 0x26, 0x0a, 0x04, 0x64, 0x69,
+	0x66, 0x66, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x67, 0x6e, 0x6d, 0x69, 0x2e,
+	0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x04, 0x64, 0x69,
+	0x66, 0x66, 0x22, 0x68, 0x0a, 0x11, 0x53, 0x65, 0x74, 0x4f, 0x6e, 0x64, 0x4c, 0x69, 0x73, 0x74,
+	0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73,
+	0x74, 0x61, 0x6d, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65,
+	0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x23, 0x0a, 0x03, 0x6f, 0x6e, 0x64, 0x18, 0x02, 0x20, 0x03,
+	0x28, 0x0b, 0x32, 0x11, 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x70, 0x6e, 0x64, 0x2e, 0x53,
+	0x65, 0x74, 0x4f, 0x6e, 0x64, 0x52, 0x03, 0x6f, 0x6e, 0x64, 0x12, 0x10, 0x0a, 0x03, 0x70, 0x69,
+	0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x70, 0x69, 0x64, 0x22, 0x68, 0x0a, 0x11,
+	0x53, 0x65, 0x74, 0x53, 0x62, 0x69, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
+	0x74, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x01,
+	0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12,
+	0x23, 0x0a, 0x03, 0x73, 0x62, 0x69, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x67,
+	0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x70, 0x6e, 0x64, 0x2e, 0x53, 0x65, 0x74, 0x53, 0x62, 0x69, 0x52,
+	0x03, 0x73, 0x62, 0x69, 0x12, 0x10, 0x0a, 0x03, 0x70, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28,
+	0x09, 0x52, 0x03, 0x70, 0x69, 0x64, 0x22, 0x74, 0x0a, 0x14, 0x53, 0x65, 0x74, 0x43, 0x68, 0x61,
+	0x6e, 0x67, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1c,
 	0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28,
-	0x03, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x23, 0x0a, 0x03,
-	0x6f, 0x6e, 0x64, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x67, 0x6f, 0x73, 0x64,
-	0x6e, 0x2e, 0x70, 0x6e, 0x64, 0x2e, 0x53, 0x65, 0x74, 0x4f, 0x6e, 0x64, 0x52, 0x03, 0x6f, 0x6e,
-	0x64, 0x12, 0x10, 0x0a, 0x03, 0x70, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03,
-	0x70, 0x69, 0x64, 0x22, 0x68, 0x0a, 0x11, 0x53, 0x65, 0x74, 0x53, 0x62, 0x69, 0x4c, 0x69, 0x73,
-	0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65,
-	0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x74, 0x69, 0x6d,
-	0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x23, 0x0a, 0x03, 0x73, 0x62, 0x69, 0x18, 0x02, 0x20,
-	0x03, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x70, 0x6e, 0x64, 0x2e,
-	0x53, 0x65, 0x74, 0x53, 0x62, 0x69, 0x52, 0x03, 0x73, 0x62, 0x69, 0x12, 0x10, 0x0a, 0x03, 0x70,
-	0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x70, 0x69, 0x64, 0x22, 0x74, 0x0a,
-	0x14, 0x53, 0x65, 0x74, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65,
-	0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61,
-	0x6d, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74,
-	0x61, 0x6d, 0x70, 0x12, 0x2c, 0x0a, 0x06, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x18, 0x02, 0x20,
-	0x03, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x70, 0x6e, 0x64, 0x2e,
-	0x53, 0x65, 0x74, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x52, 0x06, 0x63, 0x68, 0x61, 0x6e, 0x67,
-	0x65, 0x12, 0x10, 0x0a, 0x03, 0x70, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03,
-	0x70, 0x69, 0x64, 0x22, 0x85, 0x01, 0x0a, 0x12, 0x53, 0x65, 0x74, 0x50, 0x61, 0x74, 0x68, 0x4c,
-	0x69, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69,
-	0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x74,
-	0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x3f, 0x0a, 0x0e, 0x63, 0x68, 0x61, 0x6e,
-	0x67, 0x65, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b,
-	0x32, 0x18, 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x70, 0x6e, 0x64, 0x2e, 0x43, 0x68, 0x61,
-	0x6e, 0x67, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, 0x0d, 0x63, 0x68, 0x61, 0x6e,
-	0x67, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x70, 0x69, 0x64,
-	0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x70, 0x69, 0x64, 0x22, 0x7b, 0x0a, 0x0d, 0x43,
-	0x68, 0x61, 0x6e, 0x67, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x10, 0x0a, 0x03,
-	0x64, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x64, 0x69, 0x64, 0x12, 0x12,
-	0x0a, 0x04, 0x70, 0x61, 0x74, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x70, 0x61,
-	0x74, 0x68, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28,
-	0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x2e, 0x0a, 0x06, 0x61, 0x70, 0x69, 0x5f,
-	0x6f, 0x70, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x17, 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e,
-	0x2e, 0x70, 0x6e, 0x64, 0x2e, 0x41, 0x70, 0x69, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f,
-	0x6e, 0x52, 0x05, 0x61, 0x70, 0x69, 0x4f, 0x70, 0x22, 0xc9, 0x01, 0x0a, 0x06, 0x53, 0x65, 0x74,
-	0x4f, 0x6e, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01,
-	0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x37, 0x0a,
-	0x03, 0x73, 0x62, 0x69, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x67, 0x6f, 0x73,
-	0x64, 0x6e, 0x2e, 0x73, 0x6f, 0x75, 0x74, 0x68, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x2e, 0x53, 0x6f,
-	0x75, 0x74, 0x68, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63,
-	0x65, 0x52, 0x03, 0x73, 0x62, 0x69, 0x12, 0x1f, 0x0a, 0x0b, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65,
-	0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x64, 0x65, 0x76,
-	0x69, 0x63, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x4b, 0x0a, 0x10, 0x74, 0x72, 0x61, 0x6e, 0x73,
-	0x70, 0x6f, 0x72, 0x74, 0x5f, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28,
-	0x0b, 0x32, 0x20, 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70,
-	0x6f, 0x72, 0x74, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x4f, 0x70, 0x74,
-	0x69, 0x6f, 0x6e, 0x52, 0x0f, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x4f, 0x70,
-	0x74, 0x69, 0x6f, 0x6e, 0x22, 0x37, 0x0a, 0x06, 0x53, 0x65, 0x74, 0x53, 0x62, 0x69, 0x12, 0x2d,
-	0x0a, 0x08, 0x73, 0x62, 0x69, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e,
-	0x32, 0x12, 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x70, 0x6e, 0x64, 0x2e, 0x53, 0x62, 0x69,
-	0x54, 0x79, 0x70, 0x65, 0x52, 0x07, 0x73, 0x62, 0x69, 0x54, 0x79, 0x70, 0x65, 0x22, 0x45, 0x0a,
-	0x09, 0x53, 0x65, 0x74, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x63, 0x75,
-	0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x63, 0x75, 0x69, 0x64, 0x12, 0x24,
-	0x0a, 0x02, 0x6f, 0x70, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x14, 0x2e, 0x67, 0x6f, 0x73,
-	0x64, 0x6e, 0x2e, 0x70, 0x6e, 0x64, 0x2e, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e,
-	0x52, 0x02, 0x6f, 0x70, 0x22, 0x56, 0x0a, 0x0b, 0x53, 0x65, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f,
-	0x6e, 0x73, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70,
-	0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d,
-	0x70, 0x12, 0x29, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28,
-	0x0e, 0x32, 0x11, 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x70, 0x6e, 0x64, 0x2e, 0x53, 0x74,
-	0x61, 0x74, 0x75, 0x73, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0x93, 0x01, 0x0a,
-	0x12, 0x53, 0x65, 0x74, 0x4f, 0x6e, 0x64, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f,
-	0x6e, 0x73, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70,
+	0x03, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x2c, 0x0a, 0x06,
+	0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x67,
+	0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x70, 0x6e, 0x64, 0x2e, 0x53, 0x65, 0x74, 0x43, 0x68, 0x61, 0x6e,
+	0x67, 0x65, 0x52, 0x06, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x70, 0x69,
+	0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x70, 0x69, 0x64, 0x22, 0x85, 0x01, 0x0a,
+	0x12, 0x53, 0x65, 0x74, 0x50, 0x61, 0x74, 0x68, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75,
+	0x65, 0x73, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70,
 	0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d,
-	0x70, 0x12, 0x29, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28,
-	0x0e, 0x32, 0x11, 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x70, 0x6e, 0x64, 0x2e, 0x53, 0x74,
-	0x61, 0x74, 0x75, 0x73, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x34, 0x0a, 0x09,
-	0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32,
-	0x16, 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x70, 0x6e, 0x64, 0x2e, 0x53, 0x65, 0x74, 0x52,
-	0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x52, 0x09, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
-	0x65, 0x73, 0x22, 0x96, 0x01, 0x0a, 0x15, 0x53, 0x65, 0x74, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65,
+	0x70, 0x12, 0x3f, 0x0a, 0x0e, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x5f, 0x72, 0x65, 0x71, 0x75,
+	0x65, 0x73, 0x74, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x67, 0x6f, 0x73, 0x64,
+	0x6e, 0x2e, 0x70, 0x6e, 0x64, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x52, 0x65, 0x71, 0x75,
+	0x65, 0x73, 0x74, 0x52, 0x0d, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65,
+	0x73, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x70, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52,
+	0x03, 0x70, 0x69, 0x64, 0x22, 0x7b, 0x0a, 0x0d, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x52, 0x65,
+	0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x64, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01,
+	0x28, 0x09, 0x52, 0x03, 0x64, 0x69, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x61, 0x74, 0x68, 0x18,
+	0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x70, 0x61, 0x74, 0x68, 0x12, 0x14, 0x0a, 0x05, 0x76,
+	0x61, 0x6c, 0x75, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75,
+	0x65, 0x12, 0x2e, 0x0a, 0x06, 0x61, 0x70, 0x69, 0x5f, 0x6f, 0x70, 0x18, 0x04, 0x20, 0x01, 0x28,
+	0x0e, 0x32, 0x17, 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x70, 0x6e, 0x64, 0x2e, 0x41, 0x70,
+	0x69, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x05, 0x61, 0x70, 0x69, 0x4f,
+	0x70, 0x22, 0xc9, 0x01, 0x0a, 0x06, 0x53, 0x65, 0x74, 0x4f, 0x6e, 0x64, 0x12, 0x18, 0x0a, 0x07,
+	0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61,
+	0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x37, 0x0a, 0x03, 0x73, 0x62, 0x69, 0x18, 0x02, 0x20,
+	0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x73, 0x6f, 0x75, 0x74,
+	0x68, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x2e, 0x53, 0x6f, 0x75, 0x74, 0x68, 0x62, 0x6f, 0x75, 0x6e,
+	0x64, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x52, 0x03, 0x73, 0x62, 0x69, 0x12,
+	0x1f, 0x0a, 0x0b, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03,
+	0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x4e, 0x61, 0x6d, 0x65,
+	0x12, 0x4b, 0x0a, 0x10, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x5f, 0x6f, 0x70,
+	0x74, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x67, 0x6f, 0x73,
+	0x64, 0x6e, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x54, 0x72, 0x61,
+	0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0f, 0x74, 0x72,
+	0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x37, 0x0a,
+	0x06, 0x53, 0x65, 0x74, 0x53, 0x62, 0x69, 0x12, 0x2d, 0x0a, 0x08, 0x73, 0x62, 0x69, 0x5f, 0x74,
+	0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x12, 0x2e, 0x67, 0x6f, 0x73, 0x64,
+	0x6e, 0x2e, 0x70, 0x6e, 0x64, 0x2e, 0x53, 0x62, 0x69, 0x54, 0x79, 0x70, 0x65, 0x52, 0x07, 0x73,
+	0x62, 0x69, 0x54, 0x79, 0x70, 0x65, 0x22, 0x45, 0x0a, 0x09, 0x53, 0x65, 0x74, 0x43, 0x68, 0x61,
+	0x6e, 0x67, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x63, 0x75, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28,
+	0x09, 0x52, 0x04, 0x63, 0x75, 0x69, 0x64, 0x12, 0x24, 0x0a, 0x02, 0x6f, 0x70, 0x18, 0x02, 0x20,
+	0x01, 0x28, 0x0e, 0x32, 0x14, 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x70, 0x6e, 0x64, 0x2e,
+	0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x02, 0x6f, 0x70, 0x22, 0x66, 0x0a,
+	0x0b, 0x53, 0x65, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1c, 0x0a, 0x09,
+	0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52,
+	0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64,
+	0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x29, 0x0a, 0x06, 0x73, 0x74,
+	0x61, 0x74, 0x75, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x11, 0x2e, 0x67, 0x6f, 0x73,
+	0x64, 0x6e, 0x2e, 0x70, 0x6e, 0x64, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x06, 0x73,
+	0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0x93, 0x01, 0x0a, 0x12, 0x53, 0x65, 0x74, 0x4f, 0x6e, 0x64,
 	0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1c, 0x0a, 0x09,
 	0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52,
 	0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x29, 0x0a, 0x06, 0x73, 0x74,
@@ -2567,14 +2577,33 @@ var file_gosdn_pnd_pnd_proto_rawDesc = []byte{
 	0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x34, 0x0a, 0x09, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
 	0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e,
 	0x2e, 0x70, 0x6e, 0x64, 0x2e, 0x53, 0x65, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
-	0x52, 0x09, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x73, 0x22, 0x5c, 0x0a, 0x11, 0x53,
-	0x65, 0x74, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
-	0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x01, 0x20,
-	0x01, 0x28, 0x03, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x29,
-	0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x11,
-	0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x70, 0x6e, 0x64, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75,
-	0x73, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0x93, 0x01, 0x0a, 0x12, 0x53, 0x65,
-	0x74, 0x53, 0x62, 0x69, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
+	0x52, 0x09, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x73, 0x22, 0x96, 0x01, 0x0a, 0x15,
+	0x53, 0x65, 0x74, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73,
+	0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61,
+	0x6d, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74,
+	0x61, 0x6d, 0x70, 0x12, 0x29, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x02, 0x20,
+	0x01, 0x28, 0x0e, 0x32, 0x11, 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x70, 0x6e, 0x64, 0x2e,
+	0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x34,
+	0x0a, 0x09, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28,
+	0x0b, 0x32, 0x16, 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x70, 0x6e, 0x64, 0x2e, 0x53, 0x65,
+	0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x52, 0x09, 0x72, 0x65, 0x73, 0x70, 0x6f,
+	0x6e, 0x73, 0x65, 0x73, 0x22, 0x5c, 0x0a, 0x11, 0x53, 0x65, 0x74, 0x43, 0x68, 0x61, 0x6e, 0x67,
+	0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d,
+	0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x74, 0x69,
+	0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x29, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75,
+	0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x11, 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e,
+	0x70, 0x6e, 0x64, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74,
+	0x75, 0x73, 0x22, 0x93, 0x01, 0x0a, 0x12, 0x53, 0x65, 0x74, 0x53, 0x62, 0x69, 0x4c, 0x69, 0x73,
+	0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d,
+	0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x74, 0x69,
+	0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x29, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75,
+	0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x11, 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e,
+	0x70, 0x6e, 0x64, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74,
+	0x75, 0x73, 0x12, 0x34, 0x0a, 0x09, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x73, 0x18,
+	0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x70, 0x6e,
+	0x64, 0x2e, 0x53, 0x65, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x52, 0x09, 0x72,
+	0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x73, 0x22, 0x94, 0x01, 0x0a, 0x13, 0x53, 0x65, 0x74,
+	0x50, 0x61, 0x74, 0x68, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
 	0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x01, 0x20,
 	0x01, 0x28, 0x03, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x29,
 	0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x11,
@@ -2583,162 +2612,153 @@ var file_gosdn_pnd_pnd_proto_rawDesc = []byte{
 	0x70, 0x6f, 0x6e, 0x73, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x67,
 	0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x70, 0x6e, 0x64, 0x2e, 0x53, 0x65, 0x74, 0x52, 0x65, 0x73, 0x70,
 	0x6f, 0x6e, 0x73, 0x65, 0x52, 0x09, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x73, 0x22,
-	0x94, 0x01, 0x0a, 0x13, 0x53, 0x65, 0x74, 0x50, 0x61, 0x74, 0x68, 0x4c, 0x69, 0x73, 0x74, 0x52,
-	0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73,
-	0x74, 0x61, 0x6d, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65,
-	0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x29, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18,
-	0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x11, 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x70, 0x6e,
-	0x64, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73,
-	0x12, 0x34, 0x0a, 0x09, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x73, 0x18, 0x03, 0x20,
-	0x03, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x70, 0x6e, 0x64, 0x2e,
-	0x53, 0x65, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x52, 0x09, 0x72, 0x65, 0x73,
-	0x70, 0x6f, 0x6e, 0x73, 0x65, 0x73, 0x22, 0x54, 0x0a, 0x10, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65,
-	0x4f, 0x6e, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69,
+	0x54, 0x0a, 0x10, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4f, 0x6e, 0x64, 0x52, 0x65, 0x71, 0x75,
+	0x65, 0x73, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70,
+	0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d,
+	0x70, 0x12, 0x10, 0x0a, 0x03, 0x70, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03,
+	0x70, 0x69, 0x64, 0x12, 0x10, 0x0a, 0x03, 0x64, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09,
+	0x52, 0x03, 0x64, 0x69, 0x64, 0x22, 0x5c, 0x0a, 0x11, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4f,
+	0x6e, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69,
 	0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x74,
-	0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x10, 0x0a, 0x03, 0x70, 0x69, 0x64, 0x18,
-	0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x70, 0x69, 0x64, 0x12, 0x10, 0x0a, 0x03, 0x64, 0x69,
-	0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x64, 0x69, 0x64, 0x22, 0x5c, 0x0a, 0x11,
-	0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4f, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
-	0x65, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x01,
-	0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12,
-	0x29, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32,
-	0x11, 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x70, 0x6e, 0x64, 0x2e, 0x53, 0x74, 0x61, 0x74,
-	0x75, 0x73, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x2a, 0x9c, 0x01, 0x0a, 0x0b, 0x43,
-	0x68, 0x61, 0x6e, 0x67, 0x65, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x1c, 0x0a, 0x18, 0x43, 0x48,
-	0x41, 0x4e, 0x47, 0x45, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x45, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45,
-	0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x18, 0x0a, 0x14, 0x43, 0x48, 0x41, 0x4e,
-	0x47, 0x45, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x45, 0x5f, 0x50, 0x45, 0x4e, 0x44, 0x49, 0x4e, 0x47,
-	0x10, 0x01, 0x12, 0x1a, 0x0a, 0x16, 0x43, 0x48, 0x41, 0x4e, 0x47, 0x45, 0x5f, 0x53, 0x54, 0x41,
-	0x54, 0x45, 0x5f, 0x43, 0x4f, 0x4d, 0x4d, 0x49, 0x54, 0x54, 0x45, 0x44, 0x10, 0x02, 0x12, 0x1a,
-	0x0a, 0x16, 0x43, 0x48, 0x41, 0x4e, 0x47, 0x45, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x45, 0x5f, 0x43,
-	0x4f, 0x4e, 0x46, 0x49, 0x52, 0x4d, 0x45, 0x44, 0x10, 0x03, 0x12, 0x1d, 0x0a, 0x19, 0x43, 0x48,
-	0x41, 0x4e, 0x47, 0x45, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x45, 0x5f, 0x49, 0x4e, 0x43, 0x4f, 0x4e,
-	0x53, 0x49, 0x53, 0x54, 0x45, 0x4e, 0x54, 0x10, 0x04, 0x2a, 0x7c, 0x0a, 0x0c, 0x41, 0x70, 0x69,
-	0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1d, 0x0a, 0x19, 0x41, 0x50, 0x49,
-	0x5f, 0x4f, 0x50, 0x45, 0x52, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45,
-	0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x18, 0x0a, 0x14, 0x41, 0x50, 0x49, 0x5f,
-	0x4f, 0x50, 0x45, 0x52, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x55, 0x50, 0x44, 0x41, 0x54, 0x45,
-	0x10, 0x01, 0x12, 0x19, 0x0a, 0x15, 0x41, 0x50, 0x49, 0x5f, 0x4f, 0x50, 0x45, 0x52, 0x41, 0x54,
-	0x49, 0x4f, 0x4e, 0x5f, 0x52, 0x45, 0x50, 0x4c, 0x41, 0x43, 0x45, 0x10, 0x02, 0x12, 0x18, 0x0a,
-	0x14, 0x41, 0x50, 0x49, 0x5f, 0x4f, 0x50, 0x45, 0x52, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x44,
-	0x45, 0x4c, 0x45, 0x54, 0x45, 0x10, 0x03, 0x2a, 0x6d, 0x0a, 0x07, 0x53, 0x62, 0x69, 0x54, 0x79,
-	0x70, 0x65, 0x12, 0x18, 0x0a, 0x14, 0x53, 0x42, 0x49, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x55,
-	0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x17, 0x0a, 0x13,
-	0x53, 0x42, 0x49, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x4f, 0x50, 0x45, 0x4e, 0x43, 0x4f, 0x4e,
-	0x46, 0x49, 0x47, 0x10, 0x01, 0x12, 0x1a, 0x0a, 0x16, 0x53, 0x42, 0x49, 0x5f, 0x54, 0x59, 0x50,
-	0x45, 0x5f, 0x43, 0x4f, 0x4e, 0x54, 0x41, 0x49, 0x4e, 0x45, 0x52, 0x49, 0x53, 0x45, 0x44, 0x10,
-	0x02, 0x12, 0x13, 0x0a, 0x0f, 0x53, 0x42, 0x49, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x50, 0x4c,
-	0x55, 0x47, 0x49, 0x4e, 0x10, 0x03, 0x2a, 0x69, 0x0a, 0x09, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74,
-	0x69, 0x6f, 0x6e, 0x12, 0x19, 0x0a, 0x15, 0x4f, 0x50, 0x45, 0x52, 0x41, 0x54, 0x49, 0x4f, 0x4e,
-	0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x14,
-	0x0a, 0x10, 0x4f, 0x50, 0x45, 0x52, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x43, 0x52, 0x45, 0x41,
-	0x54, 0x45, 0x10, 0x01, 0x12, 0x14, 0x0a, 0x10, 0x4f, 0x50, 0x45, 0x52, 0x41, 0x54, 0x49, 0x4f,
-	0x4e, 0x5f, 0x43, 0x4f, 0x4d, 0x4d, 0x49, 0x54, 0x10, 0x02, 0x12, 0x15, 0x0a, 0x11, 0x4f, 0x50,
-	0x45, 0x52, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x43, 0x4f, 0x4e, 0x46, 0x49, 0x52, 0x4d, 0x10,
-	0x03, 0x2a, 0x41, 0x0a, 0x06, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x16, 0x0a, 0x12, 0x53,
-	0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45,
-	0x44, 0x10, 0x00, 0x12, 0x0d, 0x0a, 0x09, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x4f, 0x4b,
-	0x10, 0x01, 0x12, 0x10, 0x0a, 0x0c, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x45, 0x52, 0x52,
-	0x4f, 0x52, 0x10, 0x02, 0x32, 0xfc, 0x09, 0x0a, 0x0a, 0x50, 0x6e, 0x64, 0x53, 0x65, 0x72, 0x76,
-	0x69, 0x63, 0x65, 0x12, 0x63, 0x0a, 0x0a, 0x47, 0x65, 0x74, 0x4f, 0x6e, 0x64, 0x4c, 0x69, 0x73,
-	0x74, 0x12, 0x1c, 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x70, 0x6e, 0x64, 0x2e, 0x47, 0x65,
-	0x74, 0x4f, 0x6e, 0x64, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a,
-	0x1d, 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x70, 0x6e, 0x64, 0x2e, 0x47, 0x65, 0x74, 0x4f,
-	0x6e, 0x64, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x18,
-	0x82, 0xd3, 0xe4, 0x93, 0x02, 0x12, 0x12, 0x10, 0x2f, 0x70, 0x6e, 0x64, 0x73, 0x2f, 0x7b, 0x70,
-	0x69, 0x64, 0x7d, 0x2f, 0x6f, 0x6e, 0x64, 0x73, 0x12, 0x5c, 0x0a, 0x06, 0x47, 0x65, 0x74, 0x4f,
-	0x6e, 0x64, 0x12, 0x18, 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x70, 0x6e, 0x64, 0x2e, 0x47,
-	0x65, 0x74, 0x4f, 0x6e, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x67,
-	0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x70, 0x6e, 0x64, 0x2e, 0x47, 0x65, 0x74, 0x4f, 0x6e, 0x64, 0x52,
-	0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1d, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x17, 0x12,
-	0x15, 0x2f, 0x70, 0x6e, 0x64, 0x73, 0x2f, 0x7b, 0x70, 0x69, 0x64, 0x7d, 0x2f, 0x6f, 0x6e, 0x64,
-	0x2f, 0x7b, 0x64, 0x69, 0x64, 0x7d, 0x12, 0x66, 0x0a, 0x0a, 0x53, 0x65, 0x74, 0x4f, 0x6e, 0x64,
-	0x4c, 0x69, 0x73, 0x74, 0x12, 0x1c, 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x70, 0x6e, 0x64,
-	0x2e, 0x53, 0x65, 0x74, 0x4f, 0x6e, 0x64, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65,
-	0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x70, 0x6e, 0x64, 0x2e, 0x53,
-	0x65, 0x74, 0x4f, 0x6e, 0x64, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
-	0x65, 0x22, 0x1b, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x15, 0x3a, 0x01, 0x2a, 0x22, 0x10, 0x2f, 0x70,
-	0x6e, 0x64, 0x73, 0x2f, 0x7b, 0x70, 0x69, 0x64, 0x7d, 0x2f, 0x6f, 0x6e, 0x64, 0x73, 0x12, 0x63,
-	0x0a, 0x0a, 0x47, 0x65, 0x74, 0x53, 0x62, 0x69, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x1c, 0x2e, 0x67,
-	0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x70, 0x6e, 0x64, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x62, 0x69, 0x4c,
-	0x69, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x67, 0x6f, 0x73,
-	0x64, 0x6e, 0x2e, 0x70, 0x6e, 0x64, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x62, 0x69, 0x4c, 0x69, 0x73,
-	0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x18, 0x82, 0xd3, 0xe4, 0x93, 0x02,
-	0x12, 0x12, 0x10, 0x2f, 0x70, 0x6e, 0x64, 0x73, 0x2f, 0x7b, 0x70, 0x69, 0x64, 0x7d, 0x2f, 0x73,
-	0x62, 0x69, 0x73, 0x12, 0x5d, 0x0a, 0x06, 0x47, 0x65, 0x74, 0x53, 0x62, 0x69, 0x12, 0x18, 0x2e,
-	0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x70, 0x6e, 0x64, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x62, 0x69,
-	0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e,
-	0x70, 0x6e, 0x64, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x62, 0x69, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
-	0x73, 0x65, 0x22, 0x1e, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x18, 0x12, 0x16, 0x2f, 0x70, 0x6e, 0x64,
-	0x73, 0x2f, 0x7b, 0x70, 0x69, 0x64, 0x7d, 0x2f, 0x73, 0x62, 0x69, 0x73, 0x2f, 0x7b, 0x73, 0x69,
-	0x64, 0x7d, 0x12, 0x66, 0x0a, 0x0a, 0x53, 0x65, 0x74, 0x53, 0x62, 0x69, 0x4c, 0x69, 0x73, 0x74,
-	0x12, 0x1c, 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x70, 0x6e, 0x64, 0x2e, 0x53, 0x65, 0x74,
-	0x53, 0x62, 0x69, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d,
-	0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x70, 0x6e, 0x64, 0x2e, 0x53, 0x65, 0x74, 0x53, 0x62,
-	0x69, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1b, 0x82,
-	0xd3, 0xe4, 0x93, 0x02, 0x15, 0x3a, 0x01, 0x2a, 0x22, 0x10, 0x2f, 0x70, 0x6e, 0x64, 0x73, 0x2f,
-	0x7b, 0x70, 0x69, 0x64, 0x7d, 0x2f, 0x73, 0x62, 0x69, 0x73, 0x12, 0x6f, 0x0a, 0x0d, 0x47, 0x65,
-	0x74, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x1f, 0x2e, 0x67, 0x6f,
-	0x73, 0x64, 0x6e, 0x2e, 0x70, 0x6e, 0x64, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x68, 0x61, 0x6e, 0x67,
-	0x65, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x67,
-	0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x70, 0x6e, 0x64, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x68, 0x61, 0x6e,
-	0x67, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1b,
-	0x82, 0xd3, 0xe4, 0x93, 0x02, 0x15, 0x12, 0x13, 0x2f, 0x70, 0x6e, 0x64, 0x73, 0x2f, 0x7b, 0x70,
-	0x69, 0x64, 0x7d, 0x2f, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x73, 0x12, 0x6a, 0x0a, 0x09, 0x47,
-	0x65, 0x74, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x12, 0x1b, 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e,
-	0x2e, 0x70, 0x6e, 0x64, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x52, 0x65,
-	0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x70, 0x6e,
-	0x64, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f,
-	0x6e, 0x73, 0x65, 0x22, 0x22, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1c, 0x12, 0x1a, 0x2f, 0x70, 0x6e,
-	0x64, 0x73, 0x2f, 0x7b, 0x70, 0x69, 0x64, 0x7d, 0x2f, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x73,
-	0x2f, 0x7b, 0x63, 0x75, 0x69, 0x64, 0x7d, 0x12, 0x72, 0x0a, 0x0d, 0x53, 0x65, 0x74, 0x43, 0x68,
-	0x61, 0x6e, 0x67, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x1f, 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e,
-	0x2e, 0x70, 0x6e, 0x64, 0x2e, 0x53, 0x65, 0x74, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x4c, 0x69,
-	0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x67, 0x6f, 0x73, 0x64,
-	0x6e, 0x2e, 0x70, 0x6e, 0x64, 0x2e, 0x53, 0x65, 0x74, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x4c,
-	0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1e, 0x82, 0xd3, 0xe4,
-	0x93, 0x02, 0x18, 0x3a, 0x01, 0x2a, 0x22, 0x13, 0x2f, 0x70, 0x6e, 0x64, 0x73, 0x2f, 0x7b, 0x70,
-	0x69, 0x64, 0x7d, 0x2f, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x73, 0x12, 0x6d, 0x0a, 0x07, 0x47,
-	0x65, 0x74, 0x50, 0x61, 0x74, 0x68, 0x12, 0x19, 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x70,
-	0x6e, 0x64, 0x2e, 0x47, 0x65, 0x74, 0x50, 0x61, 0x74, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
-	0x74, 0x1a, 0x1a, 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x70, 0x6e, 0x64, 0x2e, 0x47, 0x65,
-	0x74, 0x50, 0x61, 0x74, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x2b, 0x82,
-	0xd3, 0xe4, 0x93, 0x02, 0x25, 0x12, 0x23, 0x2f, 0x70, 0x6e, 0x64, 0x73, 0x2f, 0x7b, 0x70, 0x69,
-	0x64, 0x7d, 0x2f, 0x6f, 0x6e, 0x64, 0x73, 0x2f, 0x7b, 0x64, 0x69, 0x64, 0x7d, 0x2f, 0x70, 0x61,
-	0x74, 0x68, 0x73, 0x2f, 0x7b, 0x70, 0x61, 0x74, 0x68, 0x7d, 0x12, 0x6f, 0x0a, 0x0b, 0x53, 0x65,
-	0x74, 0x50, 0x61, 0x74, 0x68, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x1d, 0x2e, 0x67, 0x6f, 0x73, 0x64,
-	0x6e, 0x2e, 0x70, 0x6e, 0x64, 0x2e, 0x53, 0x65, 0x74, 0x50, 0x61, 0x74, 0x68, 0x4c, 0x69, 0x73,
-	0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e,
-	0x2e, 0x70, 0x6e, 0x64, 0x2e, 0x53, 0x65, 0x74, 0x50, 0x61, 0x74, 0x68, 0x4c, 0x69, 0x73, 0x74,
-	0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x21, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1b,
-	0x3a, 0x01, 0x2a, 0x22, 0x16, 0x2f, 0x70, 0x6e, 0x64, 0x73, 0x2f, 0x7b, 0x70, 0x69, 0x64, 0x7d,
-	0x2f, 0x6f, 0x6e, 0x64, 0x73, 0x2f, 0x70, 0x61, 0x74, 0x68, 0x73, 0x12, 0x66, 0x0a, 0x09, 0x44,
-	0x65, 0x6c, 0x65, 0x74, 0x65, 0x4f, 0x6e, 0x64, 0x12, 0x1b, 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e,
-	0x2e, 0x70, 0x6e, 0x64, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4f, 0x6e, 0x64, 0x52, 0x65,
-	0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x70, 0x6e,
-	0x64, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4f, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f,
-	0x6e, 0x73, 0x65, 0x22, 0x1e, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x18, 0x2a, 0x16, 0x2f, 0x70, 0x6e,
-	0x64, 0x73, 0x2f, 0x7b, 0x70, 0x69, 0x64, 0x7d, 0x2f, 0x6f, 0x6e, 0x64, 0x73, 0x2f, 0x7b, 0x64,
-	0x69, 0x64, 0x7d, 0x42, 0xae, 0x02, 0x5a, 0x2d, 0x63, 0x6f, 0x64, 0x65, 0x2e, 0x66, 0x62, 0x69,
-	0x2e, 0x68, 0x2d, 0x64, 0x61, 0x2e, 0x64, 0x65, 0x2f, 0x64, 0x61, 0x6e, 0x65, 0x74, 0x2f, 0x67,
-	0x6f, 0x73, 0x64, 0x6e, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x67, 0x6f, 0x2f, 0x67, 0x6f, 0x73, 0x64,
-	0x6e, 0x2f, 0x70, 0x6e, 0x64, 0x92, 0x41, 0xfb, 0x01, 0x12, 0xf8, 0x01, 0x0a, 0x10, 0x67, 0x6f,
-	0x53, 0x44, 0x4e, 0x20, 0x4e, 0x6f, 0x72, 0x74, 0x68, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x12, 0x4d,
-	0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x20, 0x42, 0x75, 0x66, 0x66, 0x65, 0x72, 0x20,
-	0x73, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x61,
-	0x6e, 0x64, 0x20, 0x47, 0x6f, 0x20, 0x63, 0x6f, 0x64, 0x65, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x74,
-	0x68, 0x65, 0x20, 0x67, 0x6f, 0x53, 0x44, 0x4e, 0x20, 0x6e, 0x6f, 0x72, 0x74, 0x68, 0x62, 0x6f,
-	0x75, 0x6e, 0x64, 0x20, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x22, 0x3e, 0x0a,
-	0x18, 0x67, 0x6f, 0x53, 0x44, 0x4e, 0x20, 0x4e, 0x6f, 0x72, 0x74, 0x68, 0x62, 0x6f, 0x75, 0x6e,
-	0x64, 0x20, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x12, 0x22, 0x68, 0x74, 0x74, 0x70, 0x73,
-	0x3a, 0x2f, 0x2f, 0x63, 0x6f, 0x64, 0x65, 0x2e, 0x66, 0x62, 0x69, 0x2e, 0x68, 0x2d, 0x64, 0x61,
-	0x2e, 0x64, 0x65, 0x2f, 0x64, 0x61, 0x6e, 0x65, 0x74, 0x2f, 0x61, 0x70, 0x69, 0x2a, 0x50, 0x0a,
-	0x14, 0x42, 0x53, 0x44, 0x20, 0x33, 0x2d, 0x43, 0x6c, 0x61, 0x75, 0x73, 0x65, 0x20, 0x4c, 0x69,
-	0x63, 0x65, 0x6e, 0x73, 0x65, 0x12, 0x38, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x63,
-	0x6f, 0x64, 0x65, 0x2e, 0x66, 0x62, 0x69, 0x2e, 0x68, 0x2d, 0x64, 0x61, 0x2e, 0x64, 0x65, 0x2f,
-	0x64, 0x61, 0x6e, 0x65, 0x74, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x2d, 0x2f, 0x62, 0x6c, 0x6f, 0x62,
-	0x2f, 0x6d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x2f, 0x4c, 0x49, 0x43, 0x45, 0x4e, 0x53, 0x45, 0x32,
-	0x03, 0x30, 0x2e, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
+	0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x29, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74,
+	0x75, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x11, 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e,
+	0x2e, 0x70, 0x6e, 0x64, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x06, 0x73, 0x74, 0x61,
+	0x74, 0x75, 0x73, 0x2a, 0x9c, 0x01, 0x0a, 0x0b, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x53, 0x74,
+	0x61, 0x74, 0x65, 0x12, 0x1c, 0x0a, 0x18, 0x43, 0x48, 0x41, 0x4e, 0x47, 0x45, 0x5f, 0x53, 0x54,
+	0x41, 0x54, 0x45, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10,
+	0x00, 0x12, 0x18, 0x0a, 0x14, 0x43, 0x48, 0x41, 0x4e, 0x47, 0x45, 0x5f, 0x53, 0x54, 0x41, 0x54,
+	0x45, 0x5f, 0x50, 0x45, 0x4e, 0x44, 0x49, 0x4e, 0x47, 0x10, 0x01, 0x12, 0x1a, 0x0a, 0x16, 0x43,
+	0x48, 0x41, 0x4e, 0x47, 0x45, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x45, 0x5f, 0x43, 0x4f, 0x4d, 0x4d,
+	0x49, 0x54, 0x54, 0x45, 0x44, 0x10, 0x02, 0x12, 0x1a, 0x0a, 0x16, 0x43, 0x48, 0x41, 0x4e, 0x47,
+	0x45, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x45, 0x5f, 0x43, 0x4f, 0x4e, 0x46, 0x49, 0x52, 0x4d, 0x45,
+	0x44, 0x10, 0x03, 0x12, 0x1d, 0x0a, 0x19, 0x43, 0x48, 0x41, 0x4e, 0x47, 0x45, 0x5f, 0x53, 0x54,
+	0x41, 0x54, 0x45, 0x5f, 0x49, 0x4e, 0x43, 0x4f, 0x4e, 0x53, 0x49, 0x53, 0x54, 0x45, 0x4e, 0x54,
+	0x10, 0x04, 0x2a, 0x7c, 0x0a, 0x0c, 0x41, 0x70, 0x69, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69,
+	0x6f, 0x6e, 0x12, 0x1d, 0x0a, 0x19, 0x41, 0x50, 0x49, 0x5f, 0x4f, 0x50, 0x45, 0x52, 0x41, 0x54,
+	0x49, 0x4f, 0x4e, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10,
+	0x00, 0x12, 0x18, 0x0a, 0x14, 0x41, 0x50, 0x49, 0x5f, 0x4f, 0x50, 0x45, 0x52, 0x41, 0x54, 0x49,
+	0x4f, 0x4e, 0x5f, 0x55, 0x50, 0x44, 0x41, 0x54, 0x45, 0x10, 0x01, 0x12, 0x19, 0x0a, 0x15, 0x41,
+	0x50, 0x49, 0x5f, 0x4f, 0x50, 0x45, 0x52, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x52, 0x45, 0x50,
+	0x4c, 0x41, 0x43, 0x45, 0x10, 0x02, 0x12, 0x18, 0x0a, 0x14, 0x41, 0x50, 0x49, 0x5f, 0x4f, 0x50,
+	0x45, 0x52, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x44, 0x45, 0x4c, 0x45, 0x54, 0x45, 0x10, 0x03,
+	0x2a, 0x6d, 0x0a, 0x07, 0x53, 0x62, 0x69, 0x54, 0x79, 0x70, 0x65, 0x12, 0x18, 0x0a, 0x14, 0x53,
+	0x42, 0x49, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46,
+	0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x17, 0x0a, 0x13, 0x53, 0x42, 0x49, 0x5f, 0x54, 0x59, 0x50,
+	0x45, 0x5f, 0x4f, 0x50, 0x45, 0x4e, 0x43, 0x4f, 0x4e, 0x46, 0x49, 0x47, 0x10, 0x01, 0x12, 0x1a,
+	0x0a, 0x16, 0x53, 0x42, 0x49, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x43, 0x4f, 0x4e, 0x54, 0x41,
+	0x49, 0x4e, 0x45, 0x52, 0x49, 0x53, 0x45, 0x44, 0x10, 0x02, 0x12, 0x13, 0x0a, 0x0f, 0x53, 0x42,
+	0x49, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x50, 0x4c, 0x55, 0x47, 0x49, 0x4e, 0x10, 0x03, 0x2a,
+	0x69, 0x0a, 0x09, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x19, 0x0a, 0x15,
+	0x4f, 0x50, 0x45, 0x52, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43,
+	0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x14, 0x0a, 0x10, 0x4f, 0x50, 0x45, 0x52, 0x41,
+	0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x43, 0x52, 0x45, 0x41, 0x54, 0x45, 0x10, 0x01, 0x12, 0x14, 0x0a,
+	0x10, 0x4f, 0x50, 0x45, 0x52, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x43, 0x4f, 0x4d, 0x4d, 0x49,
+	0x54, 0x10, 0x02, 0x12, 0x15, 0x0a, 0x11, 0x4f, 0x50, 0x45, 0x52, 0x41, 0x54, 0x49, 0x4f, 0x4e,
+	0x5f, 0x43, 0x4f, 0x4e, 0x46, 0x49, 0x52, 0x4d, 0x10, 0x03, 0x2a, 0x41, 0x0a, 0x06, 0x53, 0x74,
+	0x61, 0x74, 0x75, 0x73, 0x12, 0x16, 0x0a, 0x12, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x55,
+	0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x0d, 0x0a, 0x09,
+	0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x4f, 0x4b, 0x10, 0x01, 0x12, 0x10, 0x0a, 0x0c, 0x53,
+	0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x10, 0x02, 0x32, 0xfc, 0x09,
+	0x0a, 0x0a, 0x50, 0x6e, 0x64, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x63, 0x0a, 0x0a,
+	0x47, 0x65, 0x74, 0x4f, 0x6e, 0x64, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x1c, 0x2e, 0x67, 0x6f, 0x73,
+	0x64, 0x6e, 0x2e, 0x70, 0x6e, 0x64, 0x2e, 0x47, 0x65, 0x74, 0x4f, 0x6e, 0x64, 0x4c, 0x69, 0x73,
+	0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e,
+	0x2e, 0x70, 0x6e, 0x64, 0x2e, 0x47, 0x65, 0x74, 0x4f, 0x6e, 0x64, 0x4c, 0x69, 0x73, 0x74, 0x52,
+	0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x18, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x12, 0x12,
+	0x10, 0x2f, 0x70, 0x6e, 0x64, 0x73, 0x2f, 0x7b, 0x70, 0x69, 0x64, 0x7d, 0x2f, 0x6f, 0x6e, 0x64,
+	0x73, 0x12, 0x5c, 0x0a, 0x06, 0x47, 0x65, 0x74, 0x4f, 0x6e, 0x64, 0x12, 0x18, 0x2e, 0x67, 0x6f,
+	0x73, 0x64, 0x6e, 0x2e, 0x70, 0x6e, 0x64, 0x2e, 0x47, 0x65, 0x74, 0x4f, 0x6e, 0x64, 0x52, 0x65,
+	0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x70, 0x6e,
+	0x64, 0x2e, 0x47, 0x65, 0x74, 0x4f, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
+	0x22, 0x1d, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x17, 0x12, 0x15, 0x2f, 0x70, 0x6e, 0x64, 0x73, 0x2f,
+	0x7b, 0x70, 0x69, 0x64, 0x7d, 0x2f, 0x6f, 0x6e, 0x64, 0x2f, 0x7b, 0x64, 0x69, 0x64, 0x7d, 0x12,
+	0x66, 0x0a, 0x0a, 0x53, 0x65, 0x74, 0x4f, 0x6e, 0x64, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x1c, 0x2e,
+	0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x70, 0x6e, 0x64, 0x2e, 0x53, 0x65, 0x74, 0x4f, 0x6e, 0x64,
+	0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x67, 0x6f,
+	0x73, 0x64, 0x6e, 0x2e, 0x70, 0x6e, 0x64, 0x2e, 0x53, 0x65, 0x74, 0x4f, 0x6e, 0x64, 0x4c, 0x69,
+	0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1b, 0x82, 0xd3, 0xe4, 0x93,
+	0x02, 0x15, 0x3a, 0x01, 0x2a, 0x22, 0x10, 0x2f, 0x70, 0x6e, 0x64, 0x73, 0x2f, 0x7b, 0x70, 0x69,
+	0x64, 0x7d, 0x2f, 0x6f, 0x6e, 0x64, 0x73, 0x12, 0x63, 0x0a, 0x0a, 0x47, 0x65, 0x74, 0x53, 0x62,
+	0x69, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x1c, 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x70, 0x6e,
+	0x64, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x62, 0x69, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75,
+	0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x70, 0x6e, 0x64, 0x2e,
+	0x47, 0x65, 0x74, 0x53, 0x62, 0x69, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
+	0x73, 0x65, 0x22, 0x18, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x12, 0x12, 0x10, 0x2f, 0x70, 0x6e, 0x64,
+	0x73, 0x2f, 0x7b, 0x70, 0x69, 0x64, 0x7d, 0x2f, 0x73, 0x62, 0x69, 0x73, 0x12, 0x5d, 0x0a, 0x06,
+	0x47, 0x65, 0x74, 0x53, 0x62, 0x69, 0x12, 0x18, 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x70,
+	0x6e, 0x64, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x62, 0x69, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
+	0x1a, 0x19, 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x70, 0x6e, 0x64, 0x2e, 0x47, 0x65, 0x74,
+	0x53, 0x62, 0x69, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1e, 0x82, 0xd3, 0xe4,
+	0x93, 0x02, 0x18, 0x12, 0x16, 0x2f, 0x70, 0x6e, 0x64, 0x73, 0x2f, 0x7b, 0x70, 0x69, 0x64, 0x7d,
+	0x2f, 0x73, 0x62, 0x69, 0x73, 0x2f, 0x7b, 0x73, 0x69, 0x64, 0x7d, 0x12, 0x66, 0x0a, 0x0a, 0x53,
+	0x65, 0x74, 0x53, 0x62, 0x69, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x1c, 0x2e, 0x67, 0x6f, 0x73, 0x64,
+	0x6e, 0x2e, 0x70, 0x6e, 0x64, 0x2e, 0x53, 0x65, 0x74, 0x53, 0x62, 0x69, 0x4c, 0x69, 0x73, 0x74,
+	0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e,
+	0x70, 0x6e, 0x64, 0x2e, 0x53, 0x65, 0x74, 0x53, 0x62, 0x69, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65,
+	0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1b, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x15, 0x3a, 0x01,
+	0x2a, 0x22, 0x10, 0x2f, 0x70, 0x6e, 0x64, 0x73, 0x2f, 0x7b, 0x70, 0x69, 0x64, 0x7d, 0x2f, 0x73,
+	0x62, 0x69, 0x73, 0x12, 0x6f, 0x0a, 0x0d, 0x47, 0x65, 0x74, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65,
+	0x4c, 0x69, 0x73, 0x74, 0x12, 0x1f, 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x70, 0x6e, 0x64,
+	0x2e, 0x47, 0x65, 0x74, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65,
+	0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x70, 0x6e,
+	0x64, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x52,
+	0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1b, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x15, 0x12,
+	0x13, 0x2f, 0x70, 0x6e, 0x64, 0x73, 0x2f, 0x7b, 0x70, 0x69, 0x64, 0x7d, 0x2f, 0x63, 0x68, 0x61,
+	0x6e, 0x67, 0x65, 0x73, 0x12, 0x6a, 0x0a, 0x09, 0x47, 0x65, 0x74, 0x43, 0x68, 0x61, 0x6e, 0x67,
+	0x65, 0x12, 0x1b, 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x70, 0x6e, 0x64, 0x2e, 0x47, 0x65,
+	0x74, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c,
+	0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x70, 0x6e, 0x64, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x68,
+	0x61, 0x6e, 0x67, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x22, 0x82, 0xd3,
+	0xe4, 0x93, 0x02, 0x1c, 0x12, 0x1a, 0x2f, 0x70, 0x6e, 0x64, 0x73, 0x2f, 0x7b, 0x70, 0x69, 0x64,
+	0x7d, 0x2f, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x73, 0x2f, 0x7b, 0x63, 0x75, 0x69, 0x64, 0x7d,
+	0x12, 0x72, 0x0a, 0x0d, 0x53, 0x65, 0x74, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x4c, 0x69, 0x73,
+	0x74, 0x12, 0x1f, 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x70, 0x6e, 0x64, 0x2e, 0x53, 0x65,
+	0x74, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65,
+	0x73, 0x74, 0x1a, 0x20, 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x70, 0x6e, 0x64, 0x2e, 0x53,
+	0x65, 0x74, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70,
+	0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1e, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x18, 0x3a, 0x01, 0x2a, 0x22,
+	0x13, 0x2f, 0x70, 0x6e, 0x64, 0x73, 0x2f, 0x7b, 0x70, 0x69, 0x64, 0x7d, 0x2f, 0x63, 0x68, 0x61,
+	0x6e, 0x67, 0x65, 0x73, 0x12, 0x6d, 0x0a, 0x07, 0x47, 0x65, 0x74, 0x50, 0x61, 0x74, 0x68, 0x12,
+	0x19, 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x70, 0x6e, 0x64, 0x2e, 0x47, 0x65, 0x74, 0x50,
+	0x61, 0x74, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x67, 0x6f, 0x73,
+	0x64, 0x6e, 0x2e, 0x70, 0x6e, 0x64, 0x2e, 0x47, 0x65, 0x74, 0x50, 0x61, 0x74, 0x68, 0x52, 0x65,
+	0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x2b, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x25, 0x12, 0x23,
+	0x2f, 0x70, 0x6e, 0x64, 0x73, 0x2f, 0x7b, 0x70, 0x69, 0x64, 0x7d, 0x2f, 0x6f, 0x6e, 0x64, 0x73,
+	0x2f, 0x7b, 0x64, 0x69, 0x64, 0x7d, 0x2f, 0x70, 0x61, 0x74, 0x68, 0x73, 0x2f, 0x7b, 0x70, 0x61,
+	0x74, 0x68, 0x7d, 0x12, 0x6f, 0x0a, 0x0b, 0x53, 0x65, 0x74, 0x50, 0x61, 0x74, 0x68, 0x4c, 0x69,
+	0x73, 0x74, 0x12, 0x1d, 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x70, 0x6e, 0x64, 0x2e, 0x53,
+	0x65, 0x74, 0x50, 0x61, 0x74, 0x68, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
+	0x74, 0x1a, 0x1e, 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x70, 0x6e, 0x64, 0x2e, 0x53, 0x65,
+	0x74, 0x50, 0x61, 0x74, 0x68, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
+	0x65, 0x22, 0x21, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1b, 0x3a, 0x01, 0x2a, 0x22, 0x16, 0x2f, 0x70,
+	0x6e, 0x64, 0x73, 0x2f, 0x7b, 0x70, 0x69, 0x64, 0x7d, 0x2f, 0x6f, 0x6e, 0x64, 0x73, 0x2f, 0x70,
+	0x61, 0x74, 0x68, 0x73, 0x12, 0x66, 0x0a, 0x09, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4f, 0x6e,
+	0x64, 0x12, 0x1b, 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x70, 0x6e, 0x64, 0x2e, 0x44, 0x65,
+	0x6c, 0x65, 0x74, 0x65, 0x4f, 0x6e, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c,
+	0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x70, 0x6e, 0x64, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74,
+	0x65, 0x4f, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1e, 0x82, 0xd3,
+	0xe4, 0x93, 0x02, 0x18, 0x2a, 0x16, 0x2f, 0x70, 0x6e, 0x64, 0x73, 0x2f, 0x7b, 0x70, 0x69, 0x64,
+	0x7d, 0x2f, 0x6f, 0x6e, 0x64, 0x73, 0x2f, 0x7b, 0x64, 0x69, 0x64, 0x7d, 0x42, 0xae, 0x02, 0x5a,
+	0x2d, 0x63, 0x6f, 0x64, 0x65, 0x2e, 0x66, 0x62, 0x69, 0x2e, 0x68, 0x2d, 0x64, 0x61, 0x2e, 0x64,
+	0x65, 0x2f, 0x64, 0x61, 0x6e, 0x65, 0x74, 0x2f, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2f, 0x61, 0x70,
+	0x69, 0x2f, 0x67, 0x6f, 0x2f, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2f, 0x70, 0x6e, 0x64, 0x92, 0x41,
+	0xfb, 0x01, 0x12, 0xf8, 0x01, 0x0a, 0x10, 0x67, 0x6f, 0x53, 0x44, 0x4e, 0x20, 0x4e, 0x6f, 0x72,
+	0x74, 0x68, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x12, 0x4d, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f,
+	0x6c, 0x20, 0x42, 0x75, 0x66, 0x66, 0x65, 0x72, 0x20, 0x73, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69,
+	0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x47, 0x6f, 0x20, 0x63,
+	0x6f, 0x64, 0x65, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x74, 0x68, 0x65, 0x20, 0x67, 0x6f, 0x53, 0x44,
+	0x4e, 0x20, 0x6e, 0x6f, 0x72, 0x74, 0x68, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x20, 0x49, 0x6e, 0x74,
+	0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x22, 0x3e, 0x0a, 0x18, 0x67, 0x6f, 0x53, 0x44, 0x4e, 0x20,
+	0x4e, 0x6f, 0x72, 0x74, 0x68, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x20, 0x70, 0x72, 0x6f, 0x6a, 0x65,
+	0x63, 0x74, 0x12, 0x22, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x63, 0x6f, 0x64, 0x65,
+	0x2e, 0x66, 0x62, 0x69, 0x2e, 0x68, 0x2d, 0x64, 0x61, 0x2e, 0x64, 0x65, 0x2f, 0x64, 0x61, 0x6e,
+	0x65, 0x74, 0x2f, 0x61, 0x70, 0x69, 0x2a, 0x50, 0x0a, 0x14, 0x42, 0x53, 0x44, 0x20, 0x33, 0x2d,
+	0x43, 0x6c, 0x61, 0x75, 0x73, 0x65, 0x20, 0x4c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x12, 0x38,
+	0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x63, 0x6f, 0x64, 0x65, 0x2e, 0x66, 0x62, 0x69,
+	0x2e, 0x68, 0x2d, 0x64, 0x61, 0x2e, 0x64, 0x65, 0x2f, 0x64, 0x61, 0x6e, 0x65, 0x74, 0x2f, 0x61,
+	0x70, 0x69, 0x2f, 0x2d, 0x2f, 0x62, 0x6c, 0x6f, 0x62, 0x2f, 0x6d, 0x61, 0x73, 0x74, 0x65, 0x72,
+	0x2f, 0x4c, 0x49, 0x43, 0x45, 0x4e, 0x53, 0x45, 0x32, 0x03, 0x30, 0x2e, 0x31, 0x62, 0x06, 0x70,
+	0x72, 0x6f, 0x74, 0x6f, 0x33,
 }
 
 var (
@@ -2816,55 +2836,56 @@ var file_gosdn_pnd_pnd_proto_depIdxs = []int32{
 	39, // 14: gosdn.pnd.OrchestratedNetworkingDevice.device:type_name -> gnmi.Notification
 	38, // 15: gosdn.pnd.OrchestratedNetworkingDevice.sbi:type_name -> gosdn.southbound.SouthboundInterface
 	0,  // 16: gosdn.pnd.Change.state:type_name -> gosdn.pnd.ChangeState
-	27, // 17: gosdn.pnd.SetOndListRequest.ond:type_name -> gosdn.pnd.SetOnd
-	28, // 18: gosdn.pnd.SetSbiListRequest.sbi:type_name -> gosdn.pnd.SetSbi
-	29, // 19: gosdn.pnd.SetChangeListRequest.change:type_name -> gosdn.pnd.SetChange
-	26, // 20: gosdn.pnd.SetPathListRequest.change_request:type_name -> gosdn.pnd.ChangeRequest
-	1,  // 21: gosdn.pnd.ChangeRequest.api_op:type_name -> gosdn.pnd.ApiOperation
-	38, // 22: gosdn.pnd.SetOnd.sbi:type_name -> gosdn.southbound.SouthboundInterface
-	40, // 23: gosdn.pnd.SetOnd.transport_option:type_name -> gosdn.transport.TransportOption
-	2,  // 24: gosdn.pnd.SetSbi.sbi_type:type_name -> gosdn.pnd.SbiType
-	3,  // 25: gosdn.pnd.SetChange.op:type_name -> gosdn.pnd.Operation
-	4,  // 26: gosdn.pnd.SetResponse.status:type_name -> gosdn.pnd.Status
-	4,  // 27: gosdn.pnd.SetOndListResponse.status:type_name -> gosdn.pnd.Status
-	30, // 28: gosdn.pnd.SetOndListResponse.responses:type_name -> gosdn.pnd.SetResponse
-	4,  // 29: gosdn.pnd.SetChangeListResponse.status:type_name -> gosdn.pnd.Status
-	30, // 30: gosdn.pnd.SetChangeListResponse.responses:type_name -> gosdn.pnd.SetResponse
-	4,  // 31: gosdn.pnd.SetChangeResponse.status:type_name -> gosdn.pnd.Status
-	4,  // 32: gosdn.pnd.SetSbiListResponse.status:type_name -> gosdn.pnd.Status
-	30, // 33: gosdn.pnd.SetSbiListResponse.responses:type_name -> gosdn.pnd.SetResponse
-	4,  // 34: gosdn.pnd.SetPathListResponse.status:type_name -> gosdn.pnd.Status
-	30, // 35: gosdn.pnd.SetPathListResponse.responses:type_name -> gosdn.pnd.SetResponse
-	4,  // 36: gosdn.pnd.DeleteOndResponse.status:type_name -> gosdn.pnd.Status
-	5,  // 37: gosdn.pnd.PndService.GetOndList:input_type -> gosdn.pnd.GetOndListRequest
-	6,  // 38: gosdn.pnd.PndService.GetOnd:input_type -> gosdn.pnd.GetOndRequest
-	22, // 39: gosdn.pnd.PndService.SetOndList:input_type -> gosdn.pnd.SetOndListRequest
-	7,  // 40: gosdn.pnd.PndService.GetSbiList:input_type -> gosdn.pnd.GetSbiListRequest
-	8,  // 41: gosdn.pnd.PndService.GetSbi:input_type -> gosdn.pnd.GetSbiRequest
-	23, // 42: gosdn.pnd.PndService.SetSbiList:input_type -> gosdn.pnd.SetSbiListRequest
-	9,  // 43: gosdn.pnd.PndService.GetChangeList:input_type -> gosdn.pnd.GetChangeListRequest
-	10, // 44: gosdn.pnd.PndService.GetChange:input_type -> gosdn.pnd.GetChangeRequest
-	24, // 45: gosdn.pnd.PndService.SetChangeList:input_type -> gosdn.pnd.SetChangeListRequest
-	11, // 46: gosdn.pnd.PndService.GetPath:input_type -> gosdn.pnd.GetPathRequest
-	25, // 47: gosdn.pnd.PndService.SetPathList:input_type -> gosdn.pnd.SetPathListRequest
-	36, // 48: gosdn.pnd.PndService.DeleteOnd:input_type -> gosdn.pnd.DeleteOndRequest
-	13, // 49: gosdn.pnd.PndService.GetOndList:output_type -> gosdn.pnd.GetOndListResponse
-	12, // 50: gosdn.pnd.PndService.GetOnd:output_type -> gosdn.pnd.GetOndResponse
-	31, // 51: gosdn.pnd.PndService.SetOndList:output_type -> gosdn.pnd.SetOndListResponse
-	15, // 52: gosdn.pnd.PndService.GetSbiList:output_type -> gosdn.pnd.GetSbiListResponse
-	14, // 53: gosdn.pnd.PndService.GetSbi:output_type -> gosdn.pnd.GetSbiResponse
-	34, // 54: gosdn.pnd.PndService.SetSbiList:output_type -> gosdn.pnd.SetSbiListResponse
-	18, // 55: gosdn.pnd.PndService.GetChangeList:output_type -> gosdn.pnd.GetChangeListResponse
-	17, // 56: gosdn.pnd.PndService.GetChange:output_type -> gosdn.pnd.GetChangeResponse
-	32, // 57: gosdn.pnd.PndService.SetChangeList:output_type -> gosdn.pnd.SetChangeListResponse
-	16, // 58: gosdn.pnd.PndService.GetPath:output_type -> gosdn.pnd.GetPathResponse
-	35, // 59: gosdn.pnd.PndService.SetPathList:output_type -> gosdn.pnd.SetPathListResponse
-	37, // 60: gosdn.pnd.PndService.DeleteOnd:output_type -> gosdn.pnd.DeleteOndResponse
-	49, // [49:61] is the sub-list for method output_type
-	37, // [37:49] is the sub-list for method input_type
-	37, // [37:37] is the sub-list for extension type_name
-	37, // [37:37] is the sub-list for extension extendee
-	0,  // [0:37] is the sub-list for field type_name
+	39, // 17: gosdn.pnd.Change.diff:type_name -> gnmi.Notification
+	27, // 18: gosdn.pnd.SetOndListRequest.ond:type_name -> gosdn.pnd.SetOnd
+	28, // 19: gosdn.pnd.SetSbiListRequest.sbi:type_name -> gosdn.pnd.SetSbi
+	29, // 20: gosdn.pnd.SetChangeListRequest.change:type_name -> gosdn.pnd.SetChange
+	26, // 21: gosdn.pnd.SetPathListRequest.change_request:type_name -> gosdn.pnd.ChangeRequest
+	1,  // 22: gosdn.pnd.ChangeRequest.api_op:type_name -> gosdn.pnd.ApiOperation
+	38, // 23: gosdn.pnd.SetOnd.sbi:type_name -> gosdn.southbound.SouthboundInterface
+	40, // 24: gosdn.pnd.SetOnd.transport_option:type_name -> gosdn.transport.TransportOption
+	2,  // 25: gosdn.pnd.SetSbi.sbi_type:type_name -> gosdn.pnd.SbiType
+	3,  // 26: gosdn.pnd.SetChange.op:type_name -> gosdn.pnd.Operation
+	4,  // 27: gosdn.pnd.SetResponse.status:type_name -> gosdn.pnd.Status
+	4,  // 28: gosdn.pnd.SetOndListResponse.status:type_name -> gosdn.pnd.Status
+	30, // 29: gosdn.pnd.SetOndListResponse.responses:type_name -> gosdn.pnd.SetResponse
+	4,  // 30: gosdn.pnd.SetChangeListResponse.status:type_name -> gosdn.pnd.Status
+	30, // 31: gosdn.pnd.SetChangeListResponse.responses:type_name -> gosdn.pnd.SetResponse
+	4,  // 32: gosdn.pnd.SetChangeResponse.status:type_name -> gosdn.pnd.Status
+	4,  // 33: gosdn.pnd.SetSbiListResponse.status:type_name -> gosdn.pnd.Status
+	30, // 34: gosdn.pnd.SetSbiListResponse.responses:type_name -> gosdn.pnd.SetResponse
+	4,  // 35: gosdn.pnd.SetPathListResponse.status:type_name -> gosdn.pnd.Status
+	30, // 36: gosdn.pnd.SetPathListResponse.responses:type_name -> gosdn.pnd.SetResponse
+	4,  // 37: gosdn.pnd.DeleteOndResponse.status:type_name -> gosdn.pnd.Status
+	5,  // 38: gosdn.pnd.PndService.GetOndList:input_type -> gosdn.pnd.GetOndListRequest
+	6,  // 39: gosdn.pnd.PndService.GetOnd:input_type -> gosdn.pnd.GetOndRequest
+	22, // 40: gosdn.pnd.PndService.SetOndList:input_type -> gosdn.pnd.SetOndListRequest
+	7,  // 41: gosdn.pnd.PndService.GetSbiList:input_type -> gosdn.pnd.GetSbiListRequest
+	8,  // 42: gosdn.pnd.PndService.GetSbi:input_type -> gosdn.pnd.GetSbiRequest
+	23, // 43: gosdn.pnd.PndService.SetSbiList:input_type -> gosdn.pnd.SetSbiListRequest
+	9,  // 44: gosdn.pnd.PndService.GetChangeList:input_type -> gosdn.pnd.GetChangeListRequest
+	10, // 45: gosdn.pnd.PndService.GetChange:input_type -> gosdn.pnd.GetChangeRequest
+	24, // 46: gosdn.pnd.PndService.SetChangeList:input_type -> gosdn.pnd.SetChangeListRequest
+	11, // 47: gosdn.pnd.PndService.GetPath:input_type -> gosdn.pnd.GetPathRequest
+	25, // 48: gosdn.pnd.PndService.SetPathList:input_type -> gosdn.pnd.SetPathListRequest
+	36, // 49: gosdn.pnd.PndService.DeleteOnd:input_type -> gosdn.pnd.DeleteOndRequest
+	13, // 50: gosdn.pnd.PndService.GetOndList:output_type -> gosdn.pnd.GetOndListResponse
+	12, // 51: gosdn.pnd.PndService.GetOnd:output_type -> gosdn.pnd.GetOndResponse
+	31, // 52: gosdn.pnd.PndService.SetOndList:output_type -> gosdn.pnd.SetOndListResponse
+	15, // 53: gosdn.pnd.PndService.GetSbiList:output_type -> gosdn.pnd.GetSbiListResponse
+	14, // 54: gosdn.pnd.PndService.GetSbi:output_type -> gosdn.pnd.GetSbiResponse
+	34, // 55: gosdn.pnd.PndService.SetSbiList:output_type -> gosdn.pnd.SetSbiListResponse
+	18, // 56: gosdn.pnd.PndService.GetChangeList:output_type -> gosdn.pnd.GetChangeListResponse
+	17, // 57: gosdn.pnd.PndService.GetChange:output_type -> gosdn.pnd.GetChangeResponse
+	32, // 58: gosdn.pnd.PndService.SetChangeList:output_type -> gosdn.pnd.SetChangeListResponse
+	16, // 59: gosdn.pnd.PndService.GetPath:output_type -> gosdn.pnd.GetPathResponse
+	35, // 60: gosdn.pnd.PndService.SetPathList:output_type -> gosdn.pnd.SetPathListResponse
+	37, // 61: gosdn.pnd.PndService.DeleteOnd:output_type -> gosdn.pnd.DeleteOndResponse
+	50, // [50:62] is the sub-list for method output_type
+	38, // [38:50] is the sub-list for method input_type
+	38, // [38:38] is the sub-list for extension type_name
+	38, // [38:38] is the sub-list for extension extendee
+	0,  // [0:38] is the sub-list for field type_name
 }
 
 func init() { file_gosdn_pnd_pnd_proto_init() }
diff --git a/api/go/gosdn/pnd/pnd.pb.gw.go b/api/go/gosdn/pnd/pnd.pb.gw.go
index 2b75200c8..61782289d 100644
--- a/api/go/gosdn/pnd/pnd.pb.gw.go
+++ b/api/go/gosdn/pnd/pnd.pb.gw.go
@@ -587,7 +587,7 @@ func request_PndService_GetChange_0(ctx context.Context, marshaler runtime.Marsh
 		return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "cuid")
 	}
 
-	protoReq.Cuid, err = runtime.String(val)
+	protoReq.Cuid, err = runtime.StringSlice(val, ",")
 	if err != nil {
 		return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "cuid", err)
 	}
@@ -630,7 +630,7 @@ func local_request_PndService_GetChange_0(ctx context.Context, marshaler runtime
 		return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "cuid")
 	}
 
-	protoReq.Cuid, err = runtime.String(val)
+	protoReq.Cuid, err = runtime.StringSlice(val, ",")
 	if err != nil {
 		return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "cuid", err)
 	}
diff --git a/api/openapiv2/gosdn_northbound.swagger.json b/api/openapiv2/gosdn_northbound.swagger.json
index 4a016bc2c..17faac28f 100644
--- a/api/openapiv2/gosdn_northbound.swagger.json
+++ b/api/openapiv2/gosdn_northbound.swagger.json
@@ -18,13 +18,13 @@
       "name": "PndService"
     },
     {
-      "name": "Collector"
+      "name": "gNMI"
     },
     {
-      "name": "gNMI"
+      "name": "AuthService"
     },
     {
-      "name": "AgentManager"
+      "name": "UserService"
     },
     {
       "name": "SbiService"
@@ -36,13 +36,13 @@
       "name": "CsbiService"
     },
     {
-      "name": "AuthService"
+      "name": "AgentManager"
     },
     {
       "name": "RoleService"
     },
     {
-      "name": "UserService"
+      "name": "Collector"
     }
   ],
   "consumes": [
@@ -383,7 +383,12 @@
             "name": "cuid",
             "in": "path",
             "required": true,
-            "type": "string"
+            "type": "array",
+            "items": {
+              "type": "string"
+            },
+            "collectionFormat": "csv",
+            "minItems": 1
           },
           {
             "name": "timestamp",
@@ -2479,6 +2484,9 @@
           "type": "string",
           "format": "int64"
         },
+        "id": {
+          "type": "string"
+        },
         "status": {
           "$ref": "#/definitions/gosdnpndStatus"
         }
@@ -2564,6 +2572,9 @@
         },
         "state": {
           "$ref": "#/definitions/pndChangeState"
+        },
+        "diff": {
+          "$ref": "#/definitions/gnmiNotification"
         }
       }
     },
diff --git a/api/proto/buf.lock b/api/proto/buf.lock
index 60d8de11d..ffdb2e279 100644
--- a/api/proto/buf.lock
+++ b/api/proto/buf.lock
@@ -4,8 +4,14 @@ deps:
   - remote: buf.build
     owner: googleapis
     repository: googleapis
+    branch: main
     commit: f3590c56d388417ebbedefae77ac12bf
+    digest: b1-nbZ1ZLsYdwXyEysqVWKYATvTXYr_alNRBebrjXpIv6k=
+    create_time: 2022-04-23T15:03:48.462865Z
   - remote: buf.build
     owner: grpc-ecosystem
     repository: grpc-gateway
+    branch: main
     commit: febd9e8be39b4f4b878b9c64bcc203fd
+    digest: b1-K5jSHBrJ24jZXRgQgkmphZuP-cAL2b90ssKrgvDK2hU=
+    create_time: 2022-04-17T01:28:07.574665Z
diff --git a/api/proto/gosdn/pnd/pnd.proto b/api/proto/gosdn/pnd/pnd.proto
index 11bed8ef5..927c0cd89 100644
--- a/api/proto/gosdn/pnd/pnd.proto
+++ b/api/proto/gosdn/pnd/pnd.proto
@@ -118,34 +118,34 @@ service PndService {
 
 message GetOndListRequest {
   int64 timestamp = 1;          // Timestamp in nanoseconds since Epoch.
-  string pid = 4;
+  string pid = 2;
 }
 
 message GetOndRequest {
   int64 timestamp = 1;          // Timestamp in nanoseconds since Epoch.
-  repeated string did = 3;
-  string pid = 4;
+  repeated string did = 2;
+  string pid = 3;
 }
 
 message GetSbiListRequest {
   int64 timestamp = 1;          // Timestamp in nanoseconds since Epoch.
-  string pid = 4;
+  string pid = 2;
 }
 message GetSbiRequest {
   int64 timestamp = 1;          // Timestamp in nanoseconds since Epoch.
-  repeated string sid = 3;
-  string pid = 4;
+  repeated string sid = 2;
+  string pid = 3;
 }
 
 message GetChangeListRequest {
   int64 timestamp = 1;          // Timestamp in nanoseconds since Epoch.
-  string pid = 4;
+  string pid = 2;
 }
 
 message GetChangeRequest {
   int64 timestamp = 1;          // Timestamp in nanoseconds since Epoch.
-  string cuid = 3;
-  string pid = 4;
+  repeated string cuid = 2;
+  string pid = 3;
 }
 
 message GetPathRequest {
@@ -235,8 +235,8 @@ enum ChangeState {
 message Change {
   string id = 1;
   int64 age = 2;
-
   ChangeState state = 3;
+  gnmi.Notification diff = 4;
 }
 
 message SetOndListRequest {
@@ -310,7 +310,8 @@ message SetChange {
 
 message SetResponse{
   int64 timestamp = 1;          // Timestamp in nanoseconds since Epoch.
-  Status status = 2;
+  string id = 2;
+  Status status = 3;
 }
 
 message SetOndListResponse{
@@ -344,8 +345,8 @@ message SetPathListResponse{
 
 message DeleteOndRequest {
   int64 timestamp = 1;          // Timestamp in nanoseconds since Epoch.
-  string pid = 4;
-  string did = 5;
+  string pid = 2;
+  string did = 3;
 }
 
 message DeleteOndResponse {
diff --git a/cli/adapter/OndAdapter.go b/cli/adapter/OndAdapter.go
deleted file mode 100644
index b8e8da308..000000000
--- a/cli/adapter/OndAdapter.go
+++ /dev/null
@@ -1 +0,0 @@
-package adapter
diff --git a/cli/adapter/PndAdapter.go b/cli/adapter/PndAdapter.go
index a03b5480b..53339e847 100644
--- a/cli/adapter/PndAdapter.go
+++ b/cli/adapter/PndAdapter.go
@@ -5,15 +5,12 @@ import (
 
 	"code.fbi.h-da.de/danet/gosdn/api/go/gosdn/core"
 	ppb "code.fbi.h-da.de/danet/gosdn/api/go/gosdn/pnd"
-	spb "code.fbi.h-da.de/danet/gosdn/api/go/gosdn/southbound"
 	tpb "code.fbi.h-da.de/danet/gosdn/api/go/gosdn/transport"
 	"code.fbi.h-da.de/danet/gosdn/controller/api"
-	"code.fbi.h-da.de/danet/gosdn/controller/interfaces/change"
 	"code.fbi.h-da.de/danet/gosdn/controller/interfaces/southbound"
 	"code.fbi.h-da.de/danet/gosdn/controller/nucleus/errors"
 	"github.com/google/uuid"
 	"github.com/openconfig/goyang/pkg/yang"
-	log "github.com/sirupsen/logrus"
 	"golang.org/x/sync/errgroup"
 	"google.golang.org/protobuf/proto"
 )
@@ -69,22 +66,22 @@ func (p *PndAdapter) GetSbiSchemaTree(ctx context.Context, sid uuid.UUID) (map[s
 
 // GetDevice requests one or multiple devices belonging to a given
 // PrincipalNetworkDomain from the controller.
-func (p *PndAdapter) GetDevice(ctx context.Context, identifier ...string) ([]*ppb.OrchestratedNetworkingDevice, error) {
+func (p *PndAdapter) GetDevice(ctx context.Context, identifier ...string) (*ppb.GetOndResponse, error) {
 	resp, err := api.GetDevice(ctx, p.endpoint, p.id.String(), identifier...)
 	if err != nil {
 		return nil, err
 	}
-	return resp.Ond, nil
+	return resp, nil
 }
 
 // GetDevices requests all devices belonging to the PrincipalNetworkDomain
 // attached to this adapter.
-func (p *PndAdapter) GetDevices(ctx context.Context) ([]*ppb.OrchestratedNetworkingDevice, error) {
+func (p *PndAdapter) GetDevices(ctx context.Context) (*ppb.GetOndListResponse, error) {
 	resp, err := api.GetDevices(ctx, p.endpoint, p.id.String())
 	if err != nil {
 		return nil, err
 	}
-	return resp.Ond, nil
+	return resp, nil
 }
 
 // RemoveDevice removes a device from the controller
@@ -108,22 +105,21 @@ func (p *PndAdapter) RemovePnd(ctx context.Context, pid uuid.UUID) (*core.Delete
 // ChangeOND sends an API call to the controller requesting the creation of
 // a change from the provided Operation, path and value. The Change is marked
 // as Pending and times out after the specified timeout period
-func (p *PndAdapter) ChangeOND(ctx context.Context, duid uuid.UUID, operation ppb.ApiOperation, path string, value ...string) (uuid.UUID, error) {
+func (p *PndAdapter) ChangeOND(ctx context.Context, duid uuid.UUID, operation ppb.ApiOperation, path string, value ...string) (*ppb.SetPathListResponse, error) {
 	var v string
 	if len(value) != 0 {
 		v = value[0]
 	}
 	resp, err := api.ChangeRequest(ctx, p.endpoint, duid.String(), p.id.String(), path, v, operation)
 	if err != nil {
-		return uuid.Nil, err
+		return nil, err
 	}
-	log.Info(resp)
-	return uuid.Nil, err
+	return resp, err
 }
 
 // Request sends an API call to the controller requesting the specified path
 // for the specified device
-func (p *PndAdapter) Request(ctx context.Context, did uuid.UUID, path string) (proto.Message, error) {
+func (p *PndAdapter) Request(ctx context.Context, did uuid.UUID, path string) (*ppb.GetPathResponse, error) {
 	resp, err := api.GetPath(ctx, p.endpoint, p.id.String(), did.String(), path)
 	if err != nil {
 		return nil, err
@@ -169,22 +165,22 @@ func (p *PndAdapter) ContainsDevice(uuid.UUID) bool {
 
 // GetSbi sends an API call to the controller requesting the
 // registered SBI with the provided ID.
-func (p *PndAdapter) GetSbi(ctx context.Context, sid ...string) ([]*spb.SouthboundInterface, error) {
+func (p *PndAdapter) GetSbi(ctx context.Context, sid ...string) (*ppb.GetSbiResponse, error) {
 	resp, err := api.GetSbi(ctx, p.endpoint, p.id.String(), sid...)
 	if err != nil {
 		return nil, err
 	}
-	return resp.Sbi, nil
+	return resp, nil
 }
 
 // GetSBIs sends an API call to the controller requesting the
 // registered SBIs. Not implemented, always returns nil
-func (p *PndAdapter) GetSBIs(ctx context.Context) ([]*spb.SouthboundInterface, error) {
+func (p *PndAdapter) GetSBIs(ctx context.Context) (*ppb.GetSbiListResponse, error) {
 	resp, err := api.GetSBIs(ctx, p.endpoint, p.id.String())
 	if err != nil {
 		return nil, err
 	}
-	return resp.Sbi, nil
+	return resp, nil
 }
 
 // ID returns the PND Adapter's UUID
@@ -199,57 +195,67 @@ func (p *PndAdapter) Endpoint() string {
 
 // PendingChanges sends an API call to the controller requesting
 // the UUIDs of all pending changes
-func (p *PndAdapter) PendingChanges(ctx context.Context) []uuid.UUID {
+func (p *PndAdapter) PendingChanges(ctx context.Context) ([]*ppb.Change, error) {
 	resp, err := api.GetChanges(ctx, p.endpoint, p.id.String())
 	if err != nil {
-		log.Error(err)
-		return nil
+		return nil, err
 	}
-	return filterChanges(ppb.ChangeState_CHANGE_STATE_PENDING, resp)
+	return filterChanges(ppb.ChangeState_CHANGE_STATE_PENDING, resp), nil
 }
 
 // CommittedChanges sends an API call to the controller requesting
 // the UUIDs of all committed changes
-func (p *PndAdapter) CommittedChanges(ctx context.Context) []uuid.UUID {
+func (p *PndAdapter) CommittedChanges(ctx context.Context) ([]*ppb.Change, error) {
 	resp, err := api.GetChanges(ctx, p.endpoint, p.id.String())
 	if err != nil {
-		log.Error(err)
-		return nil
+		return nil, err
 	}
-	return filterChanges(ppb.ChangeState_CHANGE_STATE_COMMITTED, resp)
+	return filterChanges(ppb.ChangeState_CHANGE_STATE_COMMITTED, resp), nil
 }
 
-// GetChange sends an API call to the controller requesting the specified change
-func (p *PndAdapter) GetChange(uuid.UUID) (change.Change, error) {
-	return nil, &errors.ErrNotYetImplemented{}
+// ConfirmedChanges sends an API call to the controller requesting
+// the UUIDs of all confirmed changes
+func (p *PndAdapter) ConfirmedChanges(ctx context.Context) ([]*ppb.Change, error) {
+	resp, err := api.GetChanges(ctx, p.endpoint, p.id.String())
+	if err != nil {
+		return nil, err
+	}
+	return filterChanges(ppb.ChangeState_CHANGE_STATE_CONFIRMED, resp), nil
+}
+
+// GetChange sends an API call to the controller requesting one or more changes
+// for the specific PND
+func (p *PndAdapter) GetChange(ctx context.Context, identifier ...string) (*ppb.GetChangeResponse, error) {
+	resp, err := api.GetChange(ctx, p.endpoint, p.id.String(), identifier...)
+	if err != nil {
+		return nil, err
+	}
+	return resp, nil
 }
 
 // Commit sends an API call to the controller committing the specified change
-func (p *PndAdapter) Commit(ctx context.Context, cuid uuid.UUID) error {
+func (p *PndAdapter) Commit(ctx context.Context, cuid uuid.UUID) (*ppb.SetChangeListResponse, error) {
 	resp, err := api.Commit(ctx, p.endpoint, p.id.String(), cuid.String())
 	if err != nil {
-		return err
+		return nil, err
 	}
-	log.Info(resp)
-	return nil
+	return resp, nil
 }
 
 // Confirm sends an API call to the controller confirming the specified change
-func (p *PndAdapter) Confirm(ctx context.Context, cuid uuid.UUID) error {
+func (p *PndAdapter) Confirm(ctx context.Context, cuid uuid.UUID) (*ppb.SetChangeListResponse, error) {
 	resp, err := api.Confirm(ctx, p.endpoint, p.id.String(), cuid.String())
 	if err != nil {
-		return err
+		return nil, err
 	}
-	log.Info(resp)
-	return nil
+	return resp, nil
 }
 
-func filterChanges(state ppb.ChangeState, resp *ppb.GetChangeListResponse) []uuid.UUID {
-	changes := make([]uuid.UUID, 0)
+func filterChanges(state ppb.ChangeState, resp *ppb.GetChangeListResponse) []*ppb.Change {
+	changes := make([]*ppb.Change, 0)
 	for _, ch := range resp.Change {
 		if ch.State == state {
-			id, _ := uuid.Parse(ch.Id)
-			changes = append(changes, id)
+			changes = append(changes, ch)
 		}
 	}
 	return changes
diff --git a/cli/adapter/PndAdapter_test.go b/cli/adapter/PndAdapter_test.go
index 2f5b1612a..2c49e7804 100644
--- a/cli/adapter/PndAdapter_test.go
+++ b/cli/adapter/PndAdapter_test.go
@@ -385,7 +385,7 @@ func TestPndAdapter_PendingChanges(t *testing.T) {
 				id:       tt.fields.id,
 				endpoint: tt.fields.endpoint,
 			}
-			if got := p.PendingChanges(context.TODO()); !reflect.DeepEqual(got, tt.want) {
+			if got, _ := p.PendingChanges(context.TODO()); !reflect.DeepEqual(got, tt.want) {
 				t.Errorf("PndAdapter.PendingChanges() = %v, want %v", got, tt.want)
 			}
 		})
@@ -410,7 +410,7 @@ func TestPndAdapter_CommittedChanges(t *testing.T) {
 				id:       tt.fields.id,
 				endpoint: tt.fields.endpoint,
 			}
-			if got := p.CommittedChanges(context.TODO()); !reflect.DeepEqual(got, tt.want) {
+			if got, _ := p.CommittedChanges(context.TODO()); !reflect.DeepEqual(got, tt.want) {
 				t.Errorf("PndAdapter.CommittedChanges() = %v, want %v", got, tt.want)
 			}
 		})
@@ -423,7 +423,7 @@ func TestPndAdapter_GetChange(t *testing.T) {
 		endpoint string
 	}
 	type args struct {
-		in uuid.UUID
+		in []string
 	}
 	tests := []struct {
 		name    string
@@ -440,7 +440,7 @@ func TestPndAdapter_GetChange(t *testing.T) {
 				id:       tt.fields.id,
 				endpoint: tt.fields.endpoint,
 			}
-			got, err := p.GetChange(tt.args.in)
+			got, err := p.GetChange(context.TODO(), tt.args.in...)
 			if (err != nil) != tt.wantErr {
 				t.Errorf("PndAdapter.GetChange() error = %v, wantErr %v", err, tt.wantErr)
 				return
@@ -474,7 +474,7 @@ func TestPndAdapter_Commit(t *testing.T) {
 				id:       tt.fields.id,
 				endpoint: tt.fields.endpoint,
 			}
-			if err := p.Commit(context.TODO(), tt.args.cuid); (err != nil) != tt.wantErr {
+			if _, err := p.Commit(context.TODO(), tt.args.cuid); (err != nil) != tt.wantErr {
 				t.Errorf("PndAdapter.Commit() error = %v, wantErr %v", err, tt.wantErr)
 			}
 		})
@@ -503,7 +503,7 @@ func TestPndAdapter_Confirm(t *testing.T) {
 				id:       tt.fields.id,
 				endpoint: tt.fields.endpoint,
 			}
-			if err := p.Confirm(context.TODO(), tt.args.cuid); (err != nil) != tt.wantErr {
+			if _, err := p.Confirm(context.TODO(), tt.args.cuid); (err != nil) != tt.wantErr {
 				t.Errorf("PndAdapter.Confirm() error = %v, wantErr %v", err, tt.wantErr)
 			}
 		})
diff --git a/cli/cmd/changeCommit.go b/cli/cmd/changeCommit.go
index 8bdc0ea41..0994ee2f6 100644
--- a/cli/cmd/changeCommit.go
+++ b/cli/cmd/changeCommit.go
@@ -33,7 +33,7 @@ package cmd
 
 import (
 	"github.com/google/uuid"
-	log "github.com/sirupsen/logrus"
+	"github.com/pterm/pterm"
 	"github.com/spf13/cobra"
 )
 
@@ -48,10 +48,14 @@ Change UUID must be specified as positional argument.`,
 	Run: func(cmd *cobra.Command, args []string) {
 		cuid, err := uuid.Parse(args[0])
 		if err != nil {
-			log.Fatal(err)
+			pterm.Error.Println(err)
 		}
-		if err := pndAdapter.Commit(createContextWithAuthorization(), cuid); err != nil {
-			log.Fatal(err)
+		resp, err := pndAdapter.Commit(createContextWithAuthorization(), cuid)
+		if err != nil {
+			pterm.Error.Println(err)
+		}
+		for _, r := range resp.GetResponses() {
+			pterm.Info.Println(r.String())
 		}
 	},
 }
diff --git a/cli/cmd/changeConfirm.go b/cli/cmd/changeConfirm.go
index 4fa511580..20a49e536 100644
--- a/cli/cmd/changeConfirm.go
+++ b/cli/cmd/changeConfirm.go
@@ -33,7 +33,7 @@ package cmd
 
 import (
 	"github.com/google/uuid"
-	log "github.com/sirupsen/logrus"
+	"github.com/pterm/pterm"
 	"github.com/spf13/cobra"
 )
 
@@ -48,10 +48,15 @@ Change UUID must be specified as positional argument`,
 	Run: func(cmd *cobra.Command, args []string) {
 		cuid, err := uuid.Parse(args[0])
 		if err != nil {
-			log.Fatal(err)
+			pterm.Error.Println(err)
 		}
-		if err := pndAdapter.Confirm(createContextWithAuthorization(), cuid); err != nil {
-			log.Fatal(err)
+
+		resp, err := pndAdapter.Confirm(createContextWithAuthorization(), cuid)
+		if err != nil {
+			pterm.Error.Println(err)
+		}
+		for _, r := range resp.GetResponses() {
+			pterm.Info.Println(r.String())
 		}
 	},
 }
diff --git a/cli/cmd/init.go b/cli/cmd/changeGet.go
similarity index 57%
rename from cli/cmd/init.go
rename to cli/cmd/changeGet.go
index f2d809e87..6495b1e3f 100644
--- a/cli/cmd/init.go
+++ b/cli/cmd/changeGet.go
@@ -32,44 +32,41 @@ POSSIBILITY OF SUCH DAMAGE.
 package cmd
 
 import (
-	"fmt"
-	"os"
-
-	log "github.com/sirupsen/logrus"
+	"github.com/pterm/pterm"
 	"github.com/spf13/cobra"
-	"github.com/spf13/viper"
+	"google.golang.org/protobuf/encoding/protojson"
 )
 
-var controllerAPIEndpoint string
+// confirmCmd represents the confirm command
+var getCmd = &cobra.Command{
+	Use:   "get [uuid]",
+	Args:  cobra.ExactArgs(1),
+	Short: "returns information about the requested change",
+	Long: `Returns detailed information about a specific change. The
+    changes UUID has to be specified via a positional argument.`,
 
-// initCmd represents the init command
-var initCmd = &cobra.Command{
-	Use:   "init",
-	Short: "initialise controller",
-	Long: `Initialise PND and SBI and saves values to config file on controller.
-The --controller flag is required to change the controller address`,
+	Run: func(cmd *cobra.Command, args []string) {
+		changes, err := pndAdapter.GetChange(createContextWithAuthorization(), args[0])
+		if err != nil {
+			pterm.Error.Println(err)
+		}
+		for _, c := range changes.GetChange() {
+			title := pterm.Sprintf("Change with ID: %s", c.GetId())
+			panel1 := pterm.DefaultBox.WithTitle("Age:").Sprint(c.GetAge())
+			panel2 := pterm.DefaultBox.WithTitle("State:").Sprint(c.GetState())
+			panel3 := pterm.DefaultBox.WithTitle("Diff:").Sprint(protojson.Format(c.GetDiff()))
 
-	RunE: func(cmd *cobra.Command, args []string) error {
-		log.Infof("New controller address: %v", viper.GetString("controllerAPIEndpoint"))
+			panels, _ := pterm.DefaultPanel.WithPanels(pterm.Panels{
+				{{Data: panel1}},
+				{{Data: panel2}},
+				{{Data: panel3}},
+			}).Srender()
 
-		if err := viper.WriteConfig(); err != nil {
-			fmt.Fprintln(os.Stderr, "Could not write config:", err)
+			pterm.DefaultBox.WithTitle(title).WithTitleTopCenter().WithRightPadding(0).WithBottomPadding(0).Println(panels)
 		}
-		return nil
 	},
 }
 
 func init() {
-	rootCmd.AddCommand(initCmd)
-
-	initCmd.Flags().StringVar(&controllerAPIEndpoint, "controller", "gosdn-develop.apps.ocp.fbi.h-da.de:55055", "address of the controller")
-	err := viper.BindPFlag("controllerAPIEndpoint", initCmd.Flags().Lookup("controller"))
-	if err != nil {
-		fmt.Fprintln(os.Stderr, "Could not bind controllerAPIEndpoint:", err)
-	}
-
-	// Set controller flag as required (possibly not?)
-	//if err := initCmd.MarkFlagRequired("controller"); err != nil {
-	// 	fmt.Fprintln(os.Stderr, "Could not mark controller flag as required:", err)
-	//}
+	changeCmd.AddCommand(getCmd)
 }
diff --git a/cli/cmd/changeList.go b/cli/cmd/changeList.go
index dcd3dc4f4..af5224133 100644
--- a/cli/cmd/changeList.go
+++ b/cli/cmd/changeList.go
@@ -32,7 +32,7 @@ POSSIBILITY OF SUCH DAMAGE.
 package cmd
 
 import (
-	log "github.com/sirupsen/logrus"
+	"github.com/pterm/pterm"
 	"github.com/spf13/cobra"
 )
 
@@ -43,17 +43,33 @@ var changeListCmd = &cobra.Command{
 	Short:   "list all changes",
 	Long:    `Lists all configuration changes with their UUIDs.`,
 
-	Run: func(cmd *cobra.Command, args []string) {
-		committed := pndAdapter.CommittedChanges(createContextWithAuthorization())
-		log.Info("committed changes:")
-		for i, ch := range committed {
-			log.Infof("    Change %v: %v", i+1, ch.String())
+	RunE: func(cmd *cobra.Command, args []string) error {
+		spinner, _ := pterm.DefaultSpinner.Start("Process change list request")
+		committed, err := pndAdapter.CommittedChanges(createContextWithAuthorization())
+		if err != nil {
+			spinner.Fail(err)
+			return err
 		}
-		pending := pndAdapter.PendingChanges(createContextWithAuthorization())
-		log.Info("pending changes:")
-		for i, ch := range pending {
-			log.Infof("    Change %v: %v", i+1, ch.String())
+		pending, err := pndAdapter.PendingChanges(createContextWithAuthorization())
+		if err != nil {
+			spinner.Fail(err)
+			return err
 		}
+
+		// TODO: maybe we want to return more information about changes? E.g.,
+		// the diff of the change (probably only for a single get of a change).
+		// This would require us to change pndAdapter methods.
+		data := pterm.TableData{[]string{"UUID", "Status"}}
+		for _, ch := range pending {
+			data = append(data, []string{ch.String(), "pending"})
+		}
+		for _, ch := range committed {
+			data = append(data, []string{ch.String(), "commited"})
+		}
+
+		spinner.Success()
+		pterm.DefaultTable.WithHasHeader().WithData(data).Render()
+		return nil
 	},
 }
 
diff --git a/cli/cmd/deviceCreate.go b/cli/cmd/deviceCreate.go
index 56781bf23..efd182a0d 100644
--- a/cli/cmd/deviceCreate.go
+++ b/cli/cmd/deviceCreate.go
@@ -33,9 +33,8 @@ package cmd
 
 import (
 	"github.com/google/uuid"
-	log "github.com/sirupsen/logrus"
+	"github.com/pterm/pterm"
 	"github.com/spf13/cobra"
-	"google.golang.org/protobuf/encoding/protojson"
 
 	spb "code.fbi.h-da.de/danet/gosdn/api/go/gosdn/southbound"
 	tpb "code.fbi.h-da.de/danet/gosdn/api/go/gosdn/transport"
@@ -50,8 +49,10 @@ Device address must be provided with IP and port,e.g., 192.168.1.1:6030. User cr
 if they diverge from the default credentials (user:'admin' and pw:'arista').`,
 
 	RunE: func(cmd *cobra.Command, args []string) error {
+		spinner, _ := pterm.DefaultSpinner.Start("Creating new device")
 		err := checkIPPort(address)
 		if err != nil {
+			spinner.Fail(err)
 			return err
 		}
 
@@ -73,16 +74,19 @@ if they diverge from the default credentials (user:'admin' and pw:'arista').`,
 		}
 		sid, err := uuid.Parse(cliSbi)
 		if err != nil {
+			spinner.Fail(err)
 			return err
 		}
 
 		resp, err := pndAdapter.AddDevice(createContextWithAuthorization(), deviceName, opt, sid)
 		if err != nil {
+			spinner.Fail(err)
 			return err
 		}
 
-		log.Info(protojson.Format(resp))
-
+		for _, r := range resp.GetResponses() {
+			spinner.Success("Device has been created with ID: ", r.GetId())
+		}
 		return nil
 	},
 }
diff --git a/cli/cmd/deviceDelete.go b/cli/cmd/deviceDelete.go
index 82769ea90..c354ccc2c 100644
--- a/cli/cmd/deviceDelete.go
+++ b/cli/cmd/deviceDelete.go
@@ -34,7 +34,7 @@ package cmd
 import (
 	ppb "code.fbi.h-da.de/danet/gosdn/api/go/gosdn/pnd"
 	"github.com/google/uuid"
-	log "github.com/sirupsen/logrus"
+	"github.com/pterm/pterm"
 	"github.com/spf13/cobra"
 )
 
@@ -46,17 +46,27 @@ var deviceDeleteCmd = &cobra.Command{
 	Long: `Delete a path for a given orchestrated network device.
 The device UUID and request path must be specified as a positional arguments.`,
 
-	Run: func(cmd *cobra.Command, args []string) {
+	RunE: func(cmd *cobra.Command, args []string) error {
+		spinner, _ := pterm.DefaultSpinner.Start("Create a path deletion request.")
 		did, err := uuid.Parse(args[0])
 		if err != nil {
-			log.Fatal(err)
+			spinner.Fail(err)
+			return err
 		}
-		log.Info(pndAdapter.ChangeOND(
+		resp, err := pndAdapter.ChangeOND(
 			createContextWithAuthorization(),
 			did,
 			ppb.ApiOperation_API_OPERATION_DELETE,
 			args[1],
-		))
+		)
+		for _, r := range resp.Responses {
+			if r.Status == ppb.Status_STATUS_OK {
+				spinner.Success("A change for path deletion for Device: ", did.String(), "has been created -> Change ID: ", r.GetId())
+			} else {
+				spinner.Fail("An error occured while creating a path deletion request for Device with ID: ", r.GetId(), r.GetStatus())
+			}
+		}
+		return nil
 	},
 }
 
diff --git a/cli/cmd/deviceGet.go b/cli/cmd/deviceGet.go
index 0bbaaff0b..271eeca4a 100644
--- a/cli/cmd/deviceGet.go
+++ b/cli/cmd/deviceGet.go
@@ -33,7 +33,7 @@ package cmd
 
 import (
 	"github.com/google/uuid"
-	log "github.com/sirupsen/logrus"
+	"github.com/pterm/pterm"
 	"github.com/spf13/cobra"
 	"google.golang.org/protobuf/encoding/protojson"
 )
@@ -46,22 +46,37 @@ var deviceGetCmd = &cobra.Command{
 	Long: `Requests a path from a specified orchestrated network device on the controller.
 The device UUID and request path must be specified as a positional arguments.`,
 
-	Run: func(cmd *cobra.Command, args []string) {
+	RunE: func(cmd *cobra.Command, args []string) error {
 		did, err := uuid.Parse(args[0])
 		if err != nil {
-			log.Fatal(err)
+			pterm.Error.Println(err)
+			return err
 		}
 
-		message, err := pndAdapter.Request(
+		res, err := pndAdapter.Request(
 			createContextWithAuthorization(),
 			did,
 			args[1],
 		)
 		if err != nil {
-			log.Error(err)
+			pterm.Error.Println(err)
+			return err
 		}
 
-		log.Info(protojson.Format(message))
+		for _, n := range res.Device {
+			panel1 := pterm.DefaultBox.WithTitle("Timestamp:").Sprint(n.GetTimestamp())
+			panel2 := pterm.DefaultBox.WithTitle("Requested Path:").Sprint(args[1])
+			panel3 := pterm.DefaultBox.WithTitle("Update:").Sprint(protojson.Format(n.Update[0]))
+
+			panels, _ := pterm.DefaultPanel.WithPanels(pterm.Panels{
+				{{Data: panel1}},
+				{{Data: panel2}},
+				{{Data: panel3}},
+			}).Srender()
+
+			pterm.DefaultBox.WithRightPadding(0).WithBottomPadding(0).Println(panels)
+		}
+		return nil
 	},
 }
 
diff --git a/cli/cmd/deviceList.go b/cli/cmd/deviceList.go
index 3e0d7408f..c74939942 100644
--- a/cli/cmd/deviceList.go
+++ b/cli/cmd/deviceList.go
@@ -32,8 +32,7 @@ POSSIBILITY OF SUCH DAMAGE.
 package cmd
 
 import (
-	"github.com/google/uuid"
-	log "github.com/sirupsen/logrus"
+	"github.com/pterm/pterm"
 
 	"github.com/spf13/cobra"
 )
@@ -46,23 +45,22 @@ var deviceListCmd = &cobra.Command{
 	Long:    "List all orchestrated network devices within the current PND.",
 
 	RunE: func(cmd *cobra.Command, args []string) error {
-		respONDs, err := pndAdapter.GetDevices(createContextWithAuthorization())
+		spinner, _ := pterm.DefaultSpinner.Start("Fetching data from controller")
+
+		resp, err := pndAdapter.GetDevices(createContextWithAuthorization())
 		if err != nil {
+			spinner.Fail(err)
 			return err
 		}
 
-		for i, dev := range respONDs {
-			log.Infof("OND %v: name: %v, uuid: %v", i+1, dev.Name, dev.Id)
-			sid, err := uuid.Parse(dev.GetSbi().GetId())
-			if err != nil {
-				return err
-			}
-			tree, err := pndAdapter.GetSbiSchemaTree(createContextWithAuthorization(), sid)
-			if err != nil {
-				return err
-			}
-			log.Infof("   SchemaTree: %v", tree)
+		data := pterm.TableData{[]string{"UUID", "Name", "SBI-UUID", "SBI-Type"}}
+		for _, dev := range resp.GetOnd() {
+			data = append(data, []string{dev.GetId(), dev.GetName(), dev.GetSbi().GetId(), dev.GetSbi().GetType().String()})
 		}
+
+		spinner.Success()
+
+		pterm.DefaultTable.WithHasHeader().WithData(data).Render()
 		return nil
 	},
 }
diff --git a/cli/cmd/deviceRemove.go b/cli/cmd/deviceRemove.go
index 37170c2de..6cbdf8125 100644
--- a/cli/cmd/deviceRemove.go
+++ b/cli/cmd/deviceRemove.go
@@ -32,7 +32,7 @@ POSSIBILITY OF SUCH DAMAGE.
 package cmd
 
 import (
-	log "github.com/sirupsen/logrus"
+	"github.com/pterm/pterm"
 
 	"github.com/google/uuid"
 	"github.com/spf13/cobra"
@@ -48,15 +48,18 @@ var deviceRemoveCmd = &cobra.Command{
 The device UUID must be specified as a positional argument.`,
 
 	RunE: func(cmd *cobra.Command, args []string) error {
+		spinner, _ := pterm.DefaultSpinner.Start("Removing device with ID: ", args[0])
 		did, err := uuid.Parse(args[0])
 		if err != nil {
+			spinner.Fail(err)
 			return err
 		}
-		resp, err := pndAdapter.RemoveDevice(createContextWithAuthorization(), did)
+		_, err = pndAdapter.RemoveDevice(createContextWithAuthorization(), did)
 		if err != nil {
+			spinner.Fail(err)
 			return err
 		}
-		log.Infof("Deletion of OND with ID %v: %s", did, resp.GetStatus().String())
+		spinner.Success("PND has been deleted, ID: ", did.String())
 		return nil
 	},
 }
diff --git a/cli/cmd/deviceSet.go b/cli/cmd/deviceSet.go
index a8088d34a..8cd63cb2a 100644
--- a/cli/cmd/deviceSet.go
+++ b/cli/cmd/deviceSet.go
@@ -34,7 +34,7 @@ package cmd
 import (
 	ppb "code.fbi.h-da.de/danet/gosdn/api/go/gosdn/pnd"
 	"github.com/google/uuid"
-	log "github.com/sirupsen/logrus"
+	"github.com/pterm/pterm"
 	"github.com/spf13/cobra"
 )
 
@@ -52,25 +52,38 @@ The device UUID, request path and value must be specified as positional argument
 To enable replacing behaviour (destructive!), set the --replace flag."`,
 
 	Run: func(cmd *cobra.Command, args []string) {
+		spinner, _ := pterm.DefaultSpinner.Start("Create a path set request.")
 		did, err := uuid.Parse(args[0])
 		if err != nil {
-			log.Fatal(err)
+			spinner.Fail(err)
 		}
 		var operation ppb.ApiOperation
 		if replace {
 			operation = ppb.ApiOperation_API_OPERATION_REPLACE
-			log.Info("Replace")
+			spinner.UpdateText("Replace generated and sent")
 		} else {
 			operation = ppb.ApiOperation_API_OPERATION_UPDATE
-			log.Info("Update")
+			spinner.UpdateText("Update generated and sent")
 		}
-		log.Info(pndAdapter.ChangeOND(
+
+		resp, err := pndAdapter.ChangeOND(
 			createContextWithAuthorization(),
 			did,
 			operation,
 			args[1],
 			args[2],
-		))
+		)
+		if err != nil {
+			spinner.Fail(err)
+		}
+
+		for _, r := range resp.GetResponses() {
+			if r.Status == ppb.Status_STATUS_OK {
+				spinner.Success("A change for Device: ", did.String(), "has been created -> Change ID: ", r.GetId())
+			} else {
+				spinner.Fail("An error occured while creating a path set request for Device with ID: ", r.GetId(), r.GetStatus())
+			}
+		}
 	},
 }
 
diff --git a/cli/cmd/deviceShow.go b/cli/cmd/deviceShow.go
index 7fb419883..1e1536825 100644
--- a/cli/cmd/deviceShow.go
+++ b/cli/cmd/deviceShow.go
@@ -32,7 +32,7 @@ POSSIBILITY OF SUCH DAMAGE.
 package cmd
 
 import (
-	log "github.com/sirupsen/logrus"
+	"github.com/pterm/pterm"
 	"github.com/spf13/cobra"
 )
 
@@ -46,8 +46,17 @@ Device UUID or name must be specified as a positional argument.
 The device information returned is the information as currently stored in the controller.
 The actual device is not queried directly.`,
 
-	Run: func(cmd *cobra.Command, args []string) {
-		log.Info(pndAdapter.GetDevice(createContextWithAuthorization(), args[0]))
+	RunE: func(cmd *cobra.Command, args []string) error {
+		resp, err := pndAdapter.GetDevice(createContextWithAuthorization(), args[0])
+		if err != nil {
+			pterm.Error.Println(err)
+			return err
+		}
+		data := pterm.TableData{[]string{"UUID", "Name", "SBI-UUID", "SBI-Type"}}
+		for _, dev := range resp.GetOnd() {
+			data = append(data, []string{dev.GetId(), dev.GetName(), dev.GetSbi().GetId(), dev.GetSbi().GetType().String()})
+		}
+		return nil
 	},
 }
 
diff --git a/cli/cmd/login.go b/cli/cmd/login.go
index 3d9aba572..e1c8fdeb4 100644
--- a/cli/cmd/login.go
+++ b/cli/cmd/login.go
@@ -35,7 +35,7 @@ import (
 	"context"
 
 	"code.fbi.h-da.de/danet/gosdn/controller/api"
-	log "github.com/sirupsen/logrus"
+	"github.com/pterm/pterm"
 	"github.com/spf13/cobra"
 	"github.com/spf13/viper"
 )
@@ -48,25 +48,26 @@ var loginCmd = &cobra.Command{
     User credentials need to be provided in the body`,
 
 	RunE: func(cmd *cobra.Command, args []string) error {
+		spinner, _ := pterm.DefaultSpinner.Start("Login attempt for user: ", nbUserName)
+
+		if controllerAPIEndpoint != "" {
+			if err := viper.WriteConfig(); err != nil {
+				pterm.Error.Println("Could not write config:", err)
+			}
+			pterm.Info.Println("New controller address: ", viper.GetString("controllerAPIEndpoint"))
+		}
+
 		// TODO: maybe add credentials in context instead of context.TODO()
 		resp, err := api.Login(context.TODO(), viper.GetString("controllerAPIEndpoint"), nbUserName, nbUserPwd)
 		if err != nil {
+			spinner.Fail("Login failed: ", err)
 			return err
 		}
 
-		userToken = resp.Token
-
-		if err := api.Init(createContextWithAuthorization(), viper.GetString("controllerAPIEndpoint")); err != nil {
-			return err
-		}
+		spinner.Success("Authentication for ", nbUserName, " was successful.")
 
-		sbiResp, err := api.GetSBIs(createContextWithAuthorization(), viper.GetString("controllerAPIEndpoint"), viper.GetString("CLI_PND"))
-		if err != nil {
-			return err
-		}
-		sid := sbiResp.Sbi[0].GetId()
-		viper.Set("CLI_SBI", sid)
-		log.Infof("SBI: %v", sid)
+		userToken = resp.Token
+		pterm.Info.Println("Authentication-User-Token:", userToken)
 
 		return nil
 	},
@@ -74,10 +75,17 @@ var loginCmd = &cobra.Command{
 
 var nbUserName string
 var nbUserPwd string
+var controllerAPIEndpoint string
 
 func init() {
 	rootCmd.AddCommand(loginCmd)
 
 	loginCmd.Flags().StringVar(&nbUserName, "u", "", "username for login")
 	loginCmd.Flags().StringVar(&nbUserPwd, "p", "", "pwd for login")
+	loginCmd.Flags().StringVar(&controllerAPIEndpoint, "controller", viper.GetString("controllerAPIEndpoint"), "address of the controller")
+
+	err := viper.BindPFlag("controllerAPIEndpoint", loginCmd.Flags().Lookup("controller"))
+	if err != nil {
+		pterm.Error.Println("Could not bind controllerAPIEndpoint:", err)
+	}
 }
diff --git a/cli/cmd/pndCreate.go b/cli/cmd/pndCreate.go
index f08d429d2..a2859604d 100644
--- a/cli/cmd/pndCreate.go
+++ b/cli/cmd/pndCreate.go
@@ -32,18 +32,17 @@ POSSIBILITY OF SUCH DAMAGE.
 package cmd
 
 import (
+	"code.fbi.h-da.de/danet/gosdn/api/go/gosdn/core"
 	"code.fbi.h-da.de/danet/gosdn/controller/api"
+	"github.com/pterm/pterm"
 	"github.com/spf13/cobra"
 	"github.com/spf13/viper"
-	"google.golang.org/protobuf/encoding/protojson"
-
-	log "github.com/sirupsen/logrus"
 )
 
 // pndCreateCmd represents the create command
 var pndCreateCmd = &cobra.Command{
 	Use:   "create [description]",
-	Args:  cobra.ExactArgs(1),
+	Args:  cobra.ExactArgs(0),
 	Short: "creates a new principal network domain to the controller",
 	Long: `A principal network domain is a main networking entity. This can be a
 campus building or site.
@@ -52,21 +51,31 @@ A description must be passed as positional argument. A name and default SBI can
 passed using parameters.`,
 
 	RunE: func(cmd *cobra.Command, args []string) error {
-		resp, err := api.AddPnd(createContextWithAuthorization(), viper.GetString("controllerApiEndpoint"), pndName, args[0], pndDefaultSbi)
+		spinner, _ := pterm.DefaultSpinner.Start("Creating new PND")
+		resp, err := api.AddPnd(createContextWithAuthorization(), viper.GetString("controllerApiEndpoint"), pndName, pndDescription, pndDefaultSbi)
 		if err != nil {
+			spinner.Fail(err)
 			return err
 		}
-		log.Info(protojson.Format(resp))
+
+		if resp.Status == core.Status_STATUS_OK {
+			spinner.Success("PND has been created with name: ", pndName)
+		} else {
+			spinner.Fail("Failed creating the PND with name: ", pndName)
+		}
+
 		return nil
 	},
 }
 
 var pndName string
 var pndDefaultSbi string
+var pndDescription string
 
 func init() {
 	pndCmd.AddCommand(pndCreateCmd)
 
 	pndCreateCmd.Flags().StringVar(&pndName, "name", "", "the name of the pnd")
+	pndCreateCmd.Flags().StringVar(&pndDescription, "description", "", "description of the pnd")
 	pndCreateCmd.Flags().StringVar(&pndDefaultSbi, "sbi", "openconfig", "the default SBI of the pnd")
 }
diff --git a/cli/cmd/pndGet.go b/cli/cmd/pndGet.go
index ef5e36a32..7fa6c956f 100644
--- a/cli/cmd/pndGet.go
+++ b/cli/cmd/pndGet.go
@@ -32,7 +32,7 @@ package cmd
 
 import (
 	"code.fbi.h-da.de/danet/gosdn/controller/api"
-	log "github.com/sirupsen/logrus"
+	"github.com/pterm/pterm"
 	"github.com/spf13/cobra"
 	"github.com/spf13/viper"
 )
@@ -44,13 +44,19 @@ var pndGetCmd = &cobra.Command{
 	Long:  `Get one or multiple PNDs by uuid or name and print them to stdout.`,
 
 	RunE: func(cmd *cobra.Command, args []string) error {
+		spinner, _ := pterm.DefaultSpinner.Start("Fetching requested PNDs from controller.")
 		resp, err := api.GetPnd(createContextWithAuthorization(), viper.GetString("controllerApiEndpoint"), args...)
 		if err != nil {
+			spinner.Fail(err)
 			return err
 		}
-		for i, pnd := range resp.Pnd {
-			log.Infof("PND %v: %v\n\tuuid: %v", i+1, pnd.Name, pnd.Id)
+		data := pterm.TableData{[]string{"UUID", "Name", "Description"}}
+		for _, pnd := range resp.Pnd {
+			data = append(data, []string{pnd.GetId(), pnd.GetName(), pnd.GetDescription()})
+
 		}
+		spinner.Success()
+		pterm.DefaultTable.WithHasHeader().WithData(data).Render()
 		return nil
 	},
 }
diff --git a/cli/cmd/pndList.go b/cli/cmd/pndList.go
index 2f44d74b6..65006b0c7 100644
--- a/cli/cmd/pndList.go
+++ b/cli/cmd/pndList.go
@@ -33,7 +33,7 @@ package cmd
 
 import (
 	"code.fbi.h-da.de/danet/gosdn/controller/api"
-	log "github.com/sirupsen/logrus"
+	"github.com/pterm/pterm"
 
 	"github.com/spf13/cobra"
 )
@@ -46,14 +46,21 @@ var pndListCmd = &cobra.Command{
 	Long:    `List all information about the current PND.`,
 
 	RunE: func(cmd *cobra.Command, args []string) error {
-
-		resp, err := api.GetPnd(createContextWithAuthorization(), pndAdapter.Endpoint(), pndAdapter.ID().String())
+		spinner, _ := pterm.DefaultSpinner.Start("Fetching PND list from controller")
+		resp, err := api.GetPnds(createContextWithAuthorization(), pndAdapter.Endpoint())
 		if err != nil {
+			spinner.Fail(err)
 			return err
 		}
-		for i, pnd := range resp.Pnd {
-			log.Infof("PND %v: name: %v, uuid: %v", i+1, pnd.Name, pnd.Id)
+
+		data := pterm.TableData{[]string{"UUID", "Name", "Description"}}
+		for _, pnd := range resp.Pnd {
+			data = append(data, []string{pnd.GetId(), pnd.GetName(), pnd.GetDescription()})
 		}
+
+		spinner.Success()
+
+		pterm.DefaultTable.WithHasHeader().WithData(data).Render()
 		return nil
 	},
 }
diff --git a/cli/cmd/pndRemove.go b/cli/cmd/pndRemove.go
index ed4890a75..98fb573ee 100644
--- a/cli/cmd/pndRemove.go
+++ b/cli/cmd/pndRemove.go
@@ -32,7 +32,7 @@ POSSIBILITY OF SUCH DAMAGE.
 package cmd
 
 import (
-	log "github.com/sirupsen/logrus"
+	"github.com/pterm/pterm"
 
 	"github.com/google/uuid"
 	"github.com/spf13/cobra"
@@ -42,19 +42,22 @@ import (
 var pndRemoveCmd = &cobra.Command{
 	Use:     "remove",
 	Aliases: []string{"rm"},
-	Short:   "TODO - not yet implemented",
-	Long:    `TODO - not yet implemented`,
+	Short:   "Removes the PND with the provided ID",
+	Long:    "Removes the PND with the provided ID",
 
 	RunE: func(cmd *cobra.Command, args []string) error {
+		spinner, _ := pterm.DefaultSpinner.Start("Removing PND with ID: ", args[0])
 		pid, err := uuid.Parse(args[0])
 		if err != nil {
+			spinner.Fail(err)
 			return err
 		}
-		resp, err := pndAdapter.RemovePnd(createContextWithAuthorization(), pid)
+		_, err = pndAdapter.RemovePnd(createContextWithAuthorization(), pid)
 		if err != nil {
+			spinner.Fail(err)
 			return err
 		}
-		log.Infof("Deletion of PND with ID %v: %s", pid, resp.GetStatus().String())
+		spinner.Success("PND has been deleted, ID: ", pid.String())
 		return nil
 	},
 }
diff --git a/cli/cmd/pndUse.go b/cli/cmd/pndUse.go
index 22be64cab..f3f77d797 100644
--- a/cli/cmd/pndUse.go
+++ b/cli/cmd/pndUse.go
@@ -34,7 +34,7 @@ package cmd
 import (
 	"code.fbi.h-da.de/danet/gosdn/cli/adapter"
 	"code.fbi.h-da.de/danet/gosdn/controller/api"
-	log "github.com/sirupsen/logrus"
+	"github.com/pterm/pterm"
 	"github.com/spf13/cobra"
 	"github.com/spf13/viper"
 )
@@ -51,25 +51,32 @@ var pndUseCmd = &cobra.Command{
 
 		newPndAdapter, err := adapter.NewPndAdapter(newPND, viper.GetString("controllerAPIEndpoint"))
 		if err != nil {
-			log.Fatal(err)
+			pterm.Error.Println(err)
 			return err
 		}
 
 		_, err = api.GetPnd(createContextWithAuthorization(), viper.GetString("controllerAPIEndpoint"), newPND)
 		if err != nil {
-			log.Fatal(err)
+			pterm.Error.Println(err)
+			return err
+		}
+
+		sbi, err := api.GetSBIs(createContextWithAuthorization(), viper.GetString("controllerAPIEndpoint"), newPND)
+		if err != nil {
+			pterm.Error.Println(err)
 			return err
 		}
 
 		viper.Set("CLI_PND", newPND)
+		viper.Set("CLI_SBI", sbi.GetSbi()[0].GetId())
 
 		err = viper.WriteConfig()
 		if err != nil {
-			log.Fatal(err)
+			pterm.Error.Println(err)
 			return err
 		}
 		pndAdapter = newPndAdapter
-		log.Infof("PND with ID: %s set for usage", pndAdapter.ID().String())
+		pterm.Info.Printf("PND with ID: %s has been set for usage.\n", pndAdapter.ID().String())
 		return nil
 	},
 }
diff --git a/cli/cmd/prompt.go b/cli/cmd/prompt.go
index e9704be94..ecbb6f12a 100644
--- a/cli/cmd/prompt.go
+++ b/cli/cmd/prompt.go
@@ -36,21 +36,23 @@ import (
 	"os"
 	"strings"
 
-	"code.fbi.h-da.de/danet/gosdn/api/go/gosdn/pnd"
 	"code.fbi.h-da.de/danet/gosdn/cli/completer"
+	"code.fbi.h-da.de/danet/gosdn/controller/api"
 	"github.com/c-bata/go-prompt"
 	"github.com/google/uuid"
+	"github.com/openconfig/goyang/pkg/yang"
+	"github.com/pterm/pterm"
 	"github.com/spf13/cobra"
 	"github.com/spf13/pflag"
+	"github.com/spf13/viper"
 )
 
-var suggestions []prompt.Suggest
-
 // PromptCompleter provides completion for a device
 type PromptCompleter struct {
-	//NOTE: not too sure about this but for now it should be sufficient
-	deviceID               uuid.UUID
 	yangSchemaCompleterMap map[uuid.UUID]*completer.YangSchemaCompleter
+	currentSuggestions     []prompt.Suggest
+	document               *prompt.Document
+	history                []string
 }
 
 // NewPromptCompleter returns a new promptCompleter
@@ -62,25 +64,35 @@ func NewPromptCompleter() *PromptCompleter {
 
 // Run starts the interactive completion
 func (pc *PromptCompleter) Run() {
-	fmt.Println("Welcome to the interactive mode of gosdnc.")
-	defer fmt.Println("Bye!")
+	title, _ := pterm.DefaultBigText.WithLetters(
+		pterm.NewLettersFromString("go"),
+		pterm.NewLettersFromStringWithStyle("SDN", pterm.NewStyle(pterm.FgCyan)),
+		pterm.NewLettersFromString("c"),
+	).Srender()
+	description := pterm.DefaultBasicText.Sprint("Control your goSDN controller like you've never done it before!")
+	pterm.DefaultCenter.Println(title)
+	pterm.DefaultCenter.Println(description)
 
 	p := prompt.New(
 		executeFunc,
 		pc.cstmCompleter,
 		prompt.OptionTitle("gosdnc-prompt: interactive gosdn CLI"),
 		prompt.OptionPrefix(">>> "),
+		prompt.OptionPrefixTextColor(prompt.Cyan),
 		prompt.OptionCompletionWordSeparator(completer.YangSchemaCompletionSeperator),
 		prompt.OptionShowCompletionAtStart(),
-		prompt.OptionSuggestionBGColor(prompt.DarkBlue),
-		prompt.OptionSuggestionTextColor(prompt.DarkGray),
-		prompt.OptionDescriptionTextColor(prompt.White),
-		prompt.OptionDescriptionBGColor(prompt.DarkGray),
-		prompt.OptionSelectedSuggestionBGColor(prompt.DarkRed),
+		prompt.OptionCompletionOnDown(),
+		prompt.OptionHistory(pc.history),
+		prompt.OptionSuggestionBGColor(prompt.DarkGray),
+		prompt.OptionSuggestionTextColor(prompt.LightGray),
+		prompt.OptionDescriptionTextColor(prompt.DarkGray),
+		prompt.OptionDescriptionBGColor(prompt.LightGray),
+		prompt.OptionSelectedSuggestionBGColor(prompt.Cyan),
 		prompt.OptionSelectedSuggestionTextColor(prompt.DarkGray),
-		prompt.OptionSelectedDescriptionBGColor(prompt.DarkGray),
-		prompt.OptionSelectedDescriptionTextColor(prompt.White),
+		prompt.OptionSelectedDescriptionBGColor(prompt.LightGray),
+		prompt.OptionSelectedDescriptionTextColor(prompt.DarkGray),
 	)
+
 	p.Run()
 }
 
@@ -96,106 +108,231 @@ func executeFunc(s string) {
 	}
 }
 
-func flagVisitor(f *pflag.Flag) {
-	if !f.Hidden {
-		suggestions = append(suggestions, prompt.Suggest{Text: "--" + f.Name, Description: f.Usage})
-	}
-}
-
 func (pc *PromptCompleter) cstmCompleter(d prompt.Document) []prompt.Suggest {
 	// Start with the cobra 'rootCmd' and walk through it
 	// Reference: https://github.com/stromland/cobra-prompt
 	currCmd := rootCmd
-	inputSplit := removeFlagsFromInputSlice(strings.Fields(d.CurrentLine()))
-	if c, _, err := currCmd.Find(inputSplit); err == nil {
+	inputSplit := strings.Fields(d.CurrentLine())
+	inputSplitFiltered, inputFlags := filterFlagSlice(inputSplit)
+	if c, _, err := currCmd.Find(inputSplitFiltered); err == nil {
 		currCmd = c
 	}
 
-	return completionBasedOnCmd(pc, currCmd, inputSplit, d)
+	return completionBasedOnCmd(pc, currCmd, inputSplitFiltered, inputFlags, d)
 }
 
-func removeFlagsFromInputSlice(input []string) []string {
-	r := []string{}
+func filterFlagSlice(input []string) (commandSlice []string, flagSlice []string) {
 	for _, in := range input {
 		if !strings.HasPrefix(in, "--") {
-			r = append(r, in)
+			commandSlice = append(commandSlice, in)
+		} else {
+			flagSlice = append(flagSlice, strings.Split(in, "=")[0])
 		}
 	}
-	return r
+	return commandSlice, flagSlice
 }
 
 func deviceGetCompletion(c *PromptCompleter, d prompt.Document, inputSplit []string) []prompt.Suggest {
-	inputLen := len(inputSplit)
-	if inputLen == 2 || inputLen == 3 {
-		if id, err := uuid.Parse(inputSplit[inputLen-1]); err == nil {
-			if c, ok := c.yangSchemaCompleterMap[id]; ok {
-				return c.Complete(d)
-			}
-			dev, err := pndAdapter.GetDevice(createContextWithAuthorization(), id.String())
-			if err != nil {
-				return []prompt.Suggest{}
-			}
-			sid, err := uuid.Parse(dev[0].GetSbi().GetId())
-			if err != nil {
-				return []prompt.Suggest{}
-			}
-			schemaTree, err := pndAdapter.GetSbiSchemaTree(createContextWithAuthorization(), sid)
-			if err != nil {
-				return []prompt.Suggest{}
-			}
-			c.yangSchemaCompleterMap[id] = completer.NewYangSchemaCompleter(schemaTree["Device"], true)
-			if yc, ok := c.yangSchemaCompleterMap[id]; ok {
-				c.deviceID = id
-				return yc.Complete(d)
-			}
-
+	switch inputLen := len(inputSplit); inputLen {
+	case 2:
+		return c.updateSuggestionsThroughFunc(d, getDevices)
+	case 3:
+		id, err := uuid.Parse(inputSplit[inputLen-1])
+		if err != nil {
+			return c.updateSuggestionsThroughFunc(d, getDevices)
+		}
+		if c, ok := c.yangSchemaCompleterMap[id]; ok {
+			return c.Complete(d)
+		}
+		schemaTree, err := getSchemaTreeForDeviceID(id.String())
+		if err != nil {
 			return []prompt.Suggest{}
 		}
-		if inputLen == 2 || (inputLen == 3 && !(d.GetWordBeforeCursor() == "")) {
-			return prompt.FilterHasPrefix(getDevices(), d.GetWordBeforeCursor(), true)
+		c.yangSchemaCompleterMap[id] = completer.NewYangSchemaCompleter(schemaTree["Device"], true)
+		if yc, ok := c.yangSchemaCompleterMap[id]; ok {
+			return yc.Complete(d)
+		}
+	case 4:
+		if d.GetWordBeforeCursor() == "" || d.GetWordAfterCursor() != "" {
+			return []prompt.Suggest{}
+		}
+		id, err := uuid.Parse(inputSplit[inputLen-2])
+		if err != nil {
+			return c.updateSuggestionsThroughFunc(d, getDevices)
 		}
-	} else {
-		if yc, ok := c.yangSchemaCompleterMap[c.deviceID]; ok {
+		if yc, ok := c.yangSchemaCompleterMap[id]; ok {
 			return yc.Complete(d)
 		}
+	default:
 		return []prompt.Suggest{}
 	}
 	return []prompt.Suggest{}
 }
 
-func cobraCommandCompletion(currCmd *cobra.Command, d prompt.Document, loaded []prompt.Suggest) []prompt.Suggest {
-	suggestions = []prompt.Suggest{}
-	if len(loaded) > 0 {
-		suggestions = append(suggestions, loaded...)
+func (pc *PromptCompleter) updateSuggestionsThroughFunc(d prompt.Document, fn func() ([]prompt.Suggest, error)) []prompt.Suggest {
+	if pc.currentSuggestions == nil {
+		var err error
+		pc.currentSuggestions, err = fn()
+		if err != nil {
+			return prompt.FilterHasPrefix(pc.currentSuggestions, d.GetWordBeforeCursor(), true)
+		}
 	}
+	return prompt.FilterHasPrefix(pc.currentSuggestions, d.GetWordBeforeCursor(), true)
+}
+
+func cobraCommandCompletion(currCmd *cobra.Command, d prompt.Document, inputFlags []string, loaded []prompt.Suggest) []prompt.Suggest {
 	if currCmd.HasAvailableFlags() {
-		// it would be possible to always show the inherited flags, but i think
-		// this is currently not necessary.
-		// currCmd.InheritedFlags().VisitAll(flagVisitor)
-		currCmd.LocalFlags().VisitAll(flagVisitor)
+		currCmd.LocalFlags().VisitAll(
+			func(f *pflag.Flag) {
+				if !f.Hidden && !sliceContains(inputFlags, "--"+f.Name) {
+					loaded = append(loaded, prompt.Suggest{Text: "--" + f.Name, Description: f.Usage})
+				}
+			},
+		)
 	}
 
 	for _, cmd := range currCmd.Commands() {
-		suggestions = append(suggestions, prompt.Suggest{Text: cmd.Name(), Description: cmd.Short})
+		loaded = append(loaded, prompt.Suggest{Text: cmd.Name(), Description: cmd.Short})
 	}
-	return prompt.FilterHasPrefix(suggestions, d.GetWordBeforeCursor(), true)
+
+	return prompt.FilterHasPrefix(loaded, d.GetWordBeforeCursor(), true)
 }
 
-func completionBasedOnCmd(c *PromptCompleter, cmd *cobra.Command, inputSplit []string, d prompt.Document) []prompt.Suggest {
+//nolint
+func completionBasedOnCmd(c *PromptCompleter, cmd *cobra.Command, inputSplit []string, inputFlags []string, d prompt.Document) []prompt.Suggest {
 	switch cmd {
-	case pndUseCmd, pndGetCmd:
-		return cobraCommandCompletion(cmd, d, getPnds())
+	case pndUseCmd, pndGetCmd, pndRemoveCmd:
+		if len(inputSplit) < 3 || (len(inputSplit) == 3 && d.GetWordBeforeCursor() != "") {
+			suggestions := c.updateSuggestionsThroughFunc(d, getPnds)
+			return cobraCommandCompletion(cmd, d, inputFlags, suggestions)
+		}
 	case commitCmd:
-		return getChangesByType(pnd.ChangeState_CHANGE_STATE_PENDING)
+		if len(inputSplit) < 3 || (len(inputSplit) == 3 && d.GetWordBeforeCursor() != "") {
+			return c.updateSuggestionsThroughFunc(d, getCommitedChanges)
+		}
 	case confirmCmd:
-		return getChangesByType(pnd.ChangeState_CHANGE_STATE_COMMITTED)
+		if len(inputSplit) < 3 || (len(inputSplit) == 3 && d.GetWordBeforeCursor() != "") {
+			return c.updateSuggestionsThroughFunc(d, getConfirmedChanges)
+		}
+	case deviceRemoveCmd:
+		if len(inputSplit) < 3 || (len(inputSplit) == 3 && d.GetWordBeforeCursor() != "") {
+			return c.updateSuggestionsThroughFunc(d, getDevices)
+		}
 	case deviceGetCmd, deviceSetCmd:
 		return deviceGetCompletion(c, d, inputSplit)
 	case deviceShowCmd:
-		return getDevices()
+		devices, err := getDevices()
+		if err != nil {
+			return []prompt.Suggest{}
+		}
+		return devices
+	case deviceCmd, pndCmd, changeCmd:
+		c.currentSuggestions = nil
+		return cobraCommandCompletion(cmd, d, inputFlags, []prompt.Suggest{})
 	default:
-		return cobraCommandCompletion(cmd, d, []prompt.Suggest{})
+		return cobraCommandCompletion(cmd, d, inputFlags, []prompt.Suggest{})
+	}
+
+	return []prompt.Suggest{}
+}
+
+// getDevices is a helper function which requests devices from the controller
+// and gives feedback about the current pulling status with the help of pterm
+// the result is converted into a prompt.Suggest slice.
+func getDevices() ([]prompt.Suggest, error) {
+	spinner, _ := pterm.DefaultSpinner.Start("Fetching devices from controller.")
+	resp, err := pndAdapter.GetDevices(createContextWithAuthorization())
+	if err != nil {
+		spinner.Fail(err)
+		return []prompt.Suggest{}, err
+	}
+
+	s := []prompt.Suggest{}
+	for _, ond := range resp.Ond {
+		s = append(s, prompt.Suggest{Text: ond.GetId(), Description: ond.GetName()})
+	}
+	spinner.Success()
+	return completer.SortSuggestionByText(s), nil
+}
+
+// getSchemaTreeForDeviceID is a helper function which requests the SBI's
+// schema tree of a specific device. The function gives feedback about the
+// current pulling status with the help of pterm.
+func getSchemaTreeForDeviceID(id string) (map[string]*yang.Entry, error) {
+	spinner, _ := pterm.DefaultSpinner.Start("Fetching schema tree for Device with ID: ", id)
+	dev, err := pndAdapter.GetDevice(createContextWithAuthorization(), id)
+	if err != nil {
+		spinner.Fail(err)
+		return nil, err
+	}
+	sid, err := uuid.Parse(dev.GetOnd()[0].GetSbi().GetId())
+	if err != nil {
+		spinner.Fail(err)
+		return nil, err
+	}
+	spinner.Success()
+	return pndAdapter.GetSbiSchemaTree(createContextWithAuthorization(), sid)
+}
+
+// getPnds is a helper function which requests pnds from the controller and
+// gives feedback about the current pulling status with the help of pterm the
+// result is converted into a prompt.Suggest slice.
+func getPnds() ([]prompt.Suggest, error) {
+	spinner, _ := pterm.DefaultSpinner.Start("Fetching PNDs from controller.")
+	resp, err := api.GetIds(createContextWithAuthorization(), viper.GetString("controllerAPIEndpoint"))
+	if err != nil {
+		spinner.Fail(err)
+		return []prompt.Suggest{}, err
+	}
+
+	s := []prompt.Suggest{}
+	for _, pnd := range resp {
+		s = append(s, prompt.Suggest{Text: pnd.GetId(), Description: pnd.GetDescription()})
+	}
+	spinner.Success()
+	return completer.SortSuggestionByText(s), nil
+}
+
+// getCommitedChanges is a helper function which requests all the commited
+// changes from the controller and gives feedback about the current pulling
+// status with the help of pterm the result is converted into a prompt.Suggest
+// slice.
+func getCommitedChanges() ([]prompt.Suggest, error) {
+	spinner, _ := pterm.DefaultSpinner.Start("Fetching commited changes.")
+
+	resp, err := pndAdapter.CommittedChanges(createContextWithAuthorization())
+	if err != nil {
+		spinner.Fail(err)
+		return []prompt.Suggest{}, err
+	}
+
+	s := []prompt.Suggest{}
+	for _, change := range resp {
+		s = append(s, prompt.Suggest{Text: change.GetId(), Description: change.State.String()})
+	}
+	spinner.Success()
+	return completer.SortSuggestionByText(s), nil
+}
+
+// getConfirmedChanges is a helper function which requests all the confirmed
+// changes from the controller and gives feedback about the current pulling
+// status with the help of pterm the result is converted into a prompt.Suggest
+// slice.
+func getConfirmedChanges() ([]prompt.Suggest, error) {
+	spinner, _ := pterm.DefaultSpinner.Start("Fetching confirmed changes.")
+
+	resp, err := pndAdapter.ConfirmedChanges(createContextWithAuthorization())
+	if err != nil {
+		spinner.Fail(err)
+		return []prompt.Suggest{}, err
+	}
+
+	s := []prompt.Suggest{}
+	for _, change := range resp {
+		s = append(s, prompt.Suggest{Text: change.GetId(), Description: change.State.String()})
 	}
+	spinner.Success()
+	return completer.SortSuggestionByText(s), nil
 }
 
 var exitCmd = &cobra.Command{
diff --git a/cli/cmd/root.go b/cli/cmd/root.go
index 3fdfffe20..bf5c80408 100644
--- a/cli/cmd/root.go
+++ b/cli/cmd/root.go
@@ -67,7 +67,8 @@ The login command must be called for authorization.
 // Execute adds all child commands to the root command and sets flags appropriately.
 // This is called by main.main(). It only needs to happen once to the rootCmd.
 func Execute() {
-	cobra.CheckErr(rootCmd.Execute())
+	rootCmd.Execute()
+	//cobra.CheckErr(rootCmd.Execute())
 }
 
 func init() {
diff --git a/cli/cmd/utils.go b/cli/cmd/utils.go
index cf6a03780..0e5df4a66 100644
--- a/cli/cmd/utils.go
+++ b/cli/cmd/utils.go
@@ -36,11 +36,6 @@ import (
 	"errors"
 	"net"
 
-	"code.fbi.h-da.de/danet/gosdn/api/go/gosdn/pnd"
-	"code.fbi.h-da.de/danet/gosdn/cli/completer"
-	"code.fbi.h-da.de/danet/gosdn/controller/api"
-	"github.com/c-bata/go-prompt"
-	"github.com/spf13/viper"
 	"google.golang.org/grpc/metadata"
 )
 
@@ -60,45 +55,14 @@ func checkIPPort(string) error {
 	return nil
 }
 
-func getDevices() []prompt.Suggest {
-	resp, err := api.GetDevices(createContextWithAuthorization(), pndAdapter.Endpoint(), pndAdapter.ID().String())
-	if err != nil {
-		return []prompt.Suggest{}
-	}
-
-	s := []prompt.Suggest{}
-	for _, ond := range resp.Ond {
-		s = append(s, prompt.Suggest{Text: ond.GetId(), Description: ond.GetName()})
-	}
-	return completer.SortSuggestionByText(s)
-}
-
-func getPnds() []prompt.Suggest {
-	resp, err := api.GetIds(createContextWithAuthorization(), viper.GetString("controllerAPIEndpoint"))
-	if err != nil {
-		return []prompt.Suggest{}
-	}
-
-	s := []prompt.Suggest{}
-	for _, pnd := range resp {
-		s = append(s, prompt.Suggest{Text: pnd.GetId(), Description: pnd.GetDescription()})
-	}
-	return completer.SortSuggestionByText(s)
-}
-
-func getChangesByType(cType pnd.ChangeState) []prompt.Suggest {
-	resp, err := api.GetChanges(createContextWithAuthorization(), pndAdapter.Endpoint(), pndAdapter.ID().String())
-	if err != nil {
-		return []prompt.Suggest{}
-	}
-
-	s := []prompt.Suggest{}
-	for _, change := range resp.GetChange() {
-		if change.GetState() == cType {
-			s = append(s, prompt.Suggest{Text: change.GetId(), Description: change.State.String()})
+// sliceContains checks if a slice contains the given item
+func sliceContains[T comparable](slice []T, toCompare T) bool {
+	for _, sliceEntry := range slice {
+		if sliceEntry == toCompare {
+			return true
 		}
 	}
-	return completer.SortSuggestionByText(s)
+	return false
 }
 
 func createContextWithAuthorization() context.Context {
diff --git a/controller/api/change.go b/controller/api/change.go
index e469db6c1..57b826085 100644
--- a/controller/api/change.go
+++ b/controller/api/change.go
@@ -2,6 +2,7 @@ package api
 
 import (
 	"context"
+	"errors"
 	"time"
 
 	ppb "code.fbi.h-da.de/danet/gosdn/api/go/gosdn/pnd"
@@ -21,6 +22,23 @@ func GetChanges(ctx context.Context, addr, pnd string) (*ppb.GetChangeListRespon
 	return client.GetChangeList(ctx, req)
 }
 
+// GetChange requests one or more changes from the controller
+func GetChange(ctx context.Context, addr string, pnd string, args ...string) (*ppb.GetChangeResponse, error) {
+	client, err := nbi.PndClient(addr, dialOptions...)
+	if err != nil {
+		return nil, err
+	}
+	if len(args) <= 0 {
+		return nil, errors.New("not enough arguments")
+	}
+	req := &ppb.GetChangeRequest{
+		Timestamp: time.Now().UnixNano(),
+		Pid:       pnd,
+		Cuid:      args,
+	}
+	return client.GetChange(ctx, req)
+}
+
 // Commit sends a Commit request for one or multiple changes to the
 // controller.
 func Commit(ctx context.Context, addr, pnd string, cuids ...string) (*ppb.SetChangeListResponse, error) {
@@ -61,9 +79,10 @@ func CommitConfirm(ctx context.Context, addr, pnd string, changes []*ppb.SetChan
 	return client.SetChangeList(ctx, req)
 }
 
-// ChangeRequest change creates a ChangeRequest for the specified OND. ApiOperations are
-// used to specify the type of the change (update, replace, delete as specified
-// in https://github.com/openconfig/reference/blob/master/rpc/gnmi/gnmi-specification.md#34-modifying-state)
+// ChangeRequest creates a ChangeRequest for the specified OND. ApiOperations
+// are used to specify the type of the change (update, replace, delete as
+// specified in
+// https://github.com/openconfig/reference/blob/master/rpc/gnmi/gnmi-specification.md#34-modifying-state)
 // For delete operations the value field needs to contain an empty string.
 func ChangeRequest(ctx context.Context, addr, did, pid, path, value string, op ppb.ApiOperation) (*ppb.SetPathListResponse, error) {
 	req := &ppb.ChangeRequest{
diff --git a/controller/api/initialise_test.go b/controller/api/initialise_test.go
index efcc249ed..a1c317e32 100644
--- a/controller/api/initialise_test.go
+++ b/controller/api/initialise_test.go
@@ -85,9 +85,26 @@ func bootstrapUnitTest() {
 	userService = rbacImpl.NewUserService(rbacImpl.NewMemoryUserStore())
 	roleService = rbacImpl.NewRoleService(rbacImpl.NewMemoryRoleStore())
 
+	previousHostname := "previousHostname"
+	intendedHostname := "intendedHostname"
+
 	mockChange := &mocks.Change{}
 	mockChange.On("Age").Return(time.Hour)
 	mockChange.On("State").Return(ppb.ChangeState_CHANGE_STATE_INCONSISTENT)
+	mockChange.On("PreviousState").Return(&openconfig.Device{
+		System: &openconfig.OpenconfigSystem_System{
+			Config: &openconfig.OpenconfigSystem_System_Config{
+				Hostname: &previousHostname,
+			},
+		},
+	})
+	mockChange.On("IntendedState").Return(&openconfig.Device{
+		System: &openconfig.OpenconfigSystem_System{
+			Config: &openconfig.OpenconfigSystem_System_Config{
+				Hostname: &intendedHostname,
+			},
+		},
+	})
 
 	mockPnd := mocks.NetworkDomain{}
 	mockPnd.On("ID").Return(pndUUID)
@@ -96,7 +113,7 @@ func bootstrapUnitTest() {
 	mockPnd.On("PendingChanges").Return([]uuid.UUID{changeUUID})
 	mockPnd.On("CommittedChanges").Return([]uuid.UUID{changeUUID})
 	mockPnd.On("GetChange", mock.Anything).Return(mockChange, nil)
-	mockPnd.On("AddDevice", mock.Anything, mock.Anything, mock.Anything).Return(nil)
+	mockPnd.On("AddDevice", mock.Anything, mock.Anything, mock.Anything).Return(nil, nil)
 	mockPnd.On("GetDevice", mock.Anything).Return(&nucleus.CommonDevice{
 		UUID:  deviceUUID,
 		Model: &openconfig.Device{},
diff --git a/controller/api/pnd.go b/controller/api/pnd.go
index 791ebefc6..01957053a 100644
--- a/controller/api/pnd.go
+++ b/controller/api/pnd.go
@@ -56,9 +56,6 @@ func GetPnds(ctx context.Context, addr string, args ...string) (*pb.GetPndListRe
 	if err != nil {
 		return nil, err
 	}
-	if len(args) <= 0 {
-		return nil, errors.New("not enough arguments")
-	}
 
 	req := &pb.GetPndListRequest{
 		Timestamp: time.Now().UnixNano(),
diff --git a/controller/interfaces/change/change.go b/controller/interfaces/change/change.go
index ba8075db9..40e8cc90e 100644
--- a/controller/interfaces/change/change.go
+++ b/controller/interfaces/change/change.go
@@ -18,6 +18,8 @@ type Change interface {
 	Confirm() error
 	State() ppb.ChangeState
 	Age() time.Duration
+	PreviousState() ygot.GoStruct
+	IntendedState() ygot.GoStruct
 }
 
 // Payload contains two ygot.GoStructs, the first represents the original state
diff --git a/controller/interfaces/networkdomain/pnd.go b/controller/interfaces/networkdomain/pnd.go
index 2c86f6260..fc9dec411 100644
--- a/controller/interfaces/networkdomain/pnd.go
+++ b/controller/interfaces/networkdomain/pnd.go
@@ -16,7 +16,7 @@ type NetworkDomain interface {
 	Destroy() error
 	AddSbi(s southbound.SouthboundInterface) error
 	RemoveSbi(uuid.UUID) error
-	AddDevice(name string, opts *tpb.TransportOption, sid uuid.UUID) error
+	AddDevice(name string, opts *tpb.TransportOption, sid uuid.UUID) (uuid.UUID, error)
 	GetDevice(identifier string) (device.Device, error)
 	RemoveDevice(uuid.UUID) error
 	Devices() []device.Device
diff --git a/controller/mocks/Change.go b/controller/mocks/Change.go
index 9c3e9b9f2..fb370384e 100644
--- a/controller/mocks/Change.go
+++ b/controller/mocks/Change.go
@@ -1,14 +1,18 @@
-// Code generated by mockery v2.10.0. DO NOT EDIT.
+// Code generated by mockery v2.11.0. DO NOT EDIT.
 
 package mocks
 
 import (
-	time "time"
+	testing "testing"
 
 	pnd "code.fbi.h-da.de/danet/gosdn/api/go/gosdn/pnd"
 	mock "github.com/stretchr/testify/mock"
 
+	time "time"
+
 	uuid "github.com/google/uuid"
+
+	ygot "github.com/openconfig/ygot/ygot"
 )
 
 // Change is an autogenerated mock type for the Change type
@@ -74,6 +78,38 @@ func (_m *Change) ID() uuid.UUID {
 	return r0
 }
 
+// IntendedState provides a mock function with given fields:
+func (_m *Change) IntendedState() ygot.GoStruct {
+	ret := _m.Called()
+
+	var r0 ygot.GoStruct
+	if rf, ok := ret.Get(0).(func() ygot.GoStruct); ok {
+		r0 = rf()
+	} else {
+		if ret.Get(0) != nil {
+			r0 = ret.Get(0).(ygot.GoStruct)
+		}
+	}
+
+	return r0
+}
+
+// PreviousState provides a mock function with given fields:
+func (_m *Change) PreviousState() ygot.GoStruct {
+	ret := _m.Called()
+
+	var r0 ygot.GoStruct
+	if rf, ok := ret.Get(0).(func() ygot.GoStruct); ok {
+		r0 = rf()
+	} else {
+		if ret.Get(0) != nil {
+			r0 = ret.Get(0).(ygot.GoStruct)
+		}
+	}
+
+	return r0
+}
+
 // State provides a mock function with given fields:
 func (_m *Change) State() pnd.ChangeState {
 	ret := _m.Called()
@@ -87,3 +123,12 @@ func (_m *Change) State() pnd.ChangeState {
 
 	return r0
 }
+
+// NewChange creates a new instance of Change. It also registers a cleanup function to assert the mocks expectations.
+func NewChange(t testing.TB) *Change {
+	mock := &Change{}
+
+	t.Cleanup(func() { mock.AssertExpectations(t) })
+
+	return mock
+}
diff --git a/controller/mocks/Device.go b/controller/mocks/Device.go
index 5004309d1..4b42cddd7 100644
--- a/controller/mocks/Device.go
+++ b/controller/mocks/Device.go
@@ -1,4 +1,4 @@
-// Code generated by mockery v2.10.0. DO NOT EDIT.
+// Code generated by mockery v2.11.0. DO NOT EDIT.
 
 package mocks
 
@@ -7,6 +7,8 @@ import (
 	mock "github.com/stretchr/testify/mock"
 	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
 
+	testing "testing"
+
 	transport "code.fbi.h-da.de/danet/gosdn/controller/interfaces/transport"
 
 	uuid "github.com/google/uuid"
@@ -19,32 +21,32 @@ type Device struct {
 	mock.Mock
 }
 
-// ID provides a mock function with given fields:
-func (_m *Device) ID() uuid.UUID {
+// GetModel provides a mock function with given fields:
+func (_m *Device) GetModel() ygot.ValidatedGoStruct {
 	ret := _m.Called()
 
-	var r0 uuid.UUID
-	if rf, ok := ret.Get(0).(func() uuid.UUID); ok {
+	var r0 ygot.ValidatedGoStruct
+	if rf, ok := ret.Get(0).(func() ygot.ValidatedGoStruct); ok {
 		r0 = rf()
 	} else {
 		if ret.Get(0) != nil {
-			r0 = ret.Get(0).(uuid.UUID)
+			r0 = ret.Get(0).(ygot.ValidatedGoStruct)
 		}
 	}
 
 	return r0
 }
 
-// Model provides a mock function with given fields:
-func (_m *Device) Model() ygot.GoStruct {
+// ID provides a mock function with given fields:
+func (_m *Device) ID() uuid.UUID {
 	ret := _m.Called()
 
-	var r0 ygot.GoStruct
-	if rf, ok := ret.Get(0).(func() ygot.GoStruct); ok {
+	var r0 uuid.UUID
+	if rf, ok := ret.Get(0).(func() uuid.UUID); ok {
 		r0 = rf()
 	} else {
 		if ret.Get(0) != nil {
-			r0 = ret.Get(0).(ygot.GoStruct)
+			r0 = ret.Get(0).(uuid.UUID)
 		}
 	}
 
@@ -110,3 +112,12 @@ func (_m *Device) Transport() transport.Transport {
 
 	return r0
 }
+
+// NewDevice creates a new instance of Device. It also registers a cleanup function to assert the mocks expectations.
+func NewDevice(t testing.TB) *Device {
+	mock := &Device{}
+
+	t.Cleanup(func() { mock.AssertExpectations(t) })
+
+	return mock
+}
diff --git a/controller/mocks/NetworkDomain.go b/controller/mocks/NetworkDomain.go
index 607db2834..22e6e7bfc 100644
--- a/controller/mocks/NetworkDomain.go
+++ b/controller/mocks/NetworkDomain.go
@@ -1,4 +1,4 @@
-// Code generated by mockery v2.10.0. DO NOT EDIT.
+// Code generated by mockery v2.11.0. DO NOT EDIT.
 
 package mocks
 
@@ -14,6 +14,8 @@ import (
 
 	southbound "code.fbi.h-da.de/danet/gosdn/controller/interfaces/southbound"
 
+	testing "testing"
+
 	transport "code.fbi.h-da.de/danet/gosdn/api/go/gosdn/transport"
 
 	uuid "github.com/google/uuid"
@@ -25,17 +27,26 @@ type NetworkDomain struct {
 }
 
 // AddDevice provides a mock function with given fields: name, opts, sid
-func (_m *NetworkDomain) AddDevice(name string, opts *transport.TransportOption, sid uuid.UUID) error {
+func (_m *NetworkDomain) AddDevice(name string, opts *transport.TransportOption, sid uuid.UUID) (uuid.UUID, error) {
 	ret := _m.Called(name, opts, sid)
 
-	var r0 error
-	if rf, ok := ret.Get(0).(func(string, *transport.TransportOption, uuid.UUID) error); ok {
+	var r0 uuid.UUID
+	if rf, ok := ret.Get(0).(func(string, *transport.TransportOption, uuid.UUID) uuid.UUID); ok {
 		r0 = rf(name, opts, sid)
 	} else {
-		r0 = ret.Error(0)
+		if ret.Get(0) != nil {
+			r0 = ret.Get(0).(uuid.UUID)
+		}
 	}
 
-	return r0
+	var r1 error
+	if rf, ok := ret.Get(1).(func(string, *transport.TransportOption, uuid.UUID) error); ok {
+		r1 = rf(name, opts, sid)
+	} else {
+		r1 = ret.Error(1)
+	}
+
+	return r0, r1
 }
 
 // AddSbi provides a mock function with given fields: s
@@ -393,3 +404,12 @@ func (_m *NetworkDomain) RequestAll(_a0 string) error {
 
 	return r0
 }
+
+// NewNetworkDomain creates a new instance of NetworkDomain. It also registers a cleanup function to assert the mocks expectations.
+func NewNetworkDomain(t testing.TB) *NetworkDomain {
+	mock := &NetworkDomain{}
+
+	t.Cleanup(func() { mock.AssertExpectations(t) })
+
+	return mock
+}
diff --git a/controller/mocks/Plugin.go b/controller/mocks/Plugin.go
index f69729e0c..b6d86b916 100644
--- a/controller/mocks/Plugin.go
+++ b/controller/mocks/Plugin.go
@@ -1,11 +1,14 @@
-// Code generated by mockery v2.10.0. DO NOT EDIT.
+// Code generated by mockery v2.11.0. DO NOT EDIT.
 
 package mocks
 
 import (
+	testing "testing"
+
 	plugin "code.fbi.h-da.de/danet/gosdn/controller/interfaces/plugin"
-	uuid "github.com/google/uuid"
 	mock "github.com/stretchr/testify/mock"
+
+	uuid "github.com/google/uuid"
 )
 
 // Plugin is an autogenerated mock type for the Plugin type
@@ -86,3 +89,12 @@ func (_m *Plugin) Update() error {
 
 	return r0
 }
+
+// NewPlugin creates a new instance of Plugin. It also registers a cleanup function to assert the mocks expectations.
+func NewPlugin(t testing.TB) *Plugin {
+	mock := &Plugin{}
+
+	t.Cleanup(func() { mock.AssertExpectations(t) })
+
+	return mock
+}
diff --git a/controller/mocks/SouthboundInterface.go b/controller/mocks/SouthboundInterface.go
index abf903d86..ca8fa0a15 100644
--- a/controller/mocks/SouthboundInterface.go
+++ b/controller/mocks/SouthboundInterface.go
@@ -1,4 +1,4 @@
-// Code generated by mockery v2.10.0. DO NOT EDIT.
+// Code generated by mockery v2.11.0. DO NOT EDIT.
 
 package mocks
 
@@ -7,6 +7,8 @@ import (
 	gnmi "github.com/openconfig/gnmi/proto/gnmi"
 	mock "github.com/stretchr/testify/mock"
 
+	testing "testing"
+
 	uuid "github.com/google/uuid"
 
 	yang "github.com/openconfig/goyang/pkg/yang"
@@ -143,3 +145,12 @@ func (_m *SouthboundInterface) Unmarshal(_a0 []byte, _a1 *gnmi.Path, _a2 ygot.Va
 
 	return r0
 }
+
+// NewSouthboundInterface creates a new instance of SouthboundInterface. It also registers a cleanup function to assert the mocks expectations.
+func NewSouthboundInterface(t testing.TB) *SouthboundInterface {
+	mock := &SouthboundInterface{}
+
+	t.Cleanup(func() { mock.AssertExpectations(t) })
+
+	return mock
+}
diff --git a/controller/mocks/Storable.go b/controller/mocks/Storable.go
index 2f37e9dc9..9219bcfc0 100644
--- a/controller/mocks/Storable.go
+++ b/controller/mocks/Storable.go
@@ -1,10 +1,12 @@
-// Code generated by mockery v2.10.0. DO NOT EDIT.
+// Code generated by mockery v2.11.0. DO NOT EDIT.
 
 package mocks
 
 import (
 	mock "github.com/stretchr/testify/mock"
 
+	testing "testing"
+
 	uuid "github.com/google/uuid"
 )
 
@@ -28,3 +30,12 @@ func (_m *Storable) ID() uuid.UUID {
 
 	return r0
 }
+
+// NewStorable creates a new instance of Storable. It also registers a cleanup function to assert the mocks expectations.
+func NewStorable(t testing.TB) *Storable {
+	mock := &Storable{}
+
+	t.Cleanup(func() { mock.AssertExpectations(t) })
+
+	return mock
+}
diff --git a/controller/mocks/Transport.go b/controller/mocks/Transport.go
index b2c7aa34f..ae80536a4 100644
--- a/controller/mocks/Transport.go
+++ b/controller/mocks/Transport.go
@@ -1,4 +1,4 @@
-// Code generated by mockery v2.10.0. DO NOT EDIT.
+// Code generated by mockery v2.11.0. DO NOT EDIT.
 
 package mocks
 
@@ -9,6 +9,8 @@ import (
 
 	mock "github.com/stretchr/testify/mock"
 
+	testing "testing"
+
 	ytypes "github.com/openconfig/ygot/ytypes"
 )
 
@@ -109,3 +111,12 @@ func (_m *Transport) Type() string {
 
 	return r0
 }
+
+// NewTransport creates a new instance of Transport. It also registers a cleanup function to assert the mocks expectations.
+func NewTransport(t testing.TB) *Transport {
+	mock := &Transport{}
+
+	t.Cleanup(func() { mock.AssertExpectations(t) })
+
+	return mock
+}
diff --git a/controller/northbound/server/pnd.go b/controller/northbound/server/pnd.go
index 6d5300845..2ef00339a 100644
--- a/controller/northbound/server/pnd.go
+++ b/controller/northbound/server/pnd.go
@@ -393,7 +393,7 @@ func (p pndServer) GetChange(ctx context.Context, request *ppb.GetChangeRequest)
 		log.Error(err)
 		return nil, status.Errorf(codes.Aborted, "%v", err)
 	}
-	changes, err := fillChanges(pnd, false, request.Cuid)
+	changes, err := fillChanges(pnd, false, request.Cuid...)
 	if err != nil {
 		log.Error(err)
 		return nil, status.Errorf(codes.Aborted, "%v", err)
@@ -469,10 +469,17 @@ func fillChanges(pnd networkdomain.NetworkDomain, all bool, cuid ...string) ([]*
 			return nil, status.Errorf(codes.Aborted, "%v", err)
 		}
 
+		diff, err := ygot.Diff(c.PreviousState(), c.IntendedState())
+		if err != nil {
+			log.Error(err)
+			return nil, status.Errorf(codes.Aborted, "%v", err)
+		}
+
 		changes[i] = &ppb.Change{
 			Id:    ch.String(),
 			Age:   c.Age().Microseconds(),
 			State: c.State(),
+			Diff:  diff,
 		}
 	}
 	return changes, nil
@@ -492,25 +499,30 @@ func (p pndServer) SetOndList(ctx context.Context, request *ppb.SetOndListReques
 		return nil, handleRPCError(labels, err)
 	}
 
+	deviceIDs := make([]uuid.UUID, 0, len(request.Ond))
 	for _, r := range request.Ond {
 		sid, err := uuid.Parse(r.Sbi.Id)
 		if err != nil {
 			log.Error(err)
 			return nil, status.Errorf(codes.Aborted, "%v", err)
 		}
-		if err := pnd.AddDevice(r.DeviceName, r.TransportOption, sid); err != nil {
+		did, err := pnd.AddDevice(r.DeviceName, r.TransportOption, sid)
+		if err != nil {
 			log.Error(err)
 			return nil, status.Errorf(codes.Aborted, "%v", err)
 		}
+		deviceIDs = append(deviceIDs, did)
+	}
+
+	r := make([]*ppb.SetResponse, len(deviceIDs))
+	for i, did := range deviceIDs {
+		r[i] = &ppb.SetResponse{Id: did.String(), Status: ppb.Status_STATUS_OK}
 	}
+
 	return &ppb.SetOndListResponse{
 		Timestamp: time.Now().UnixNano(),
 		Status:    ppb.Status_STATUS_OK,
-		Responses: []*ppb.SetResponse{
-			{
-				Status: ppb.Status_STATUS_OK,
-			},
-		},
+		Responses: r,
 	}, nil
 }
 
diff --git a/controller/nucleus/change.go b/controller/nucleus/change.go
index 6da303875..935360ca5 100644
--- a/controller/nucleus/change.go
+++ b/controller/nucleus/change.go
@@ -116,6 +116,18 @@ func (c *Change) State() ppb.ChangeState {
 	return state
 }
 
+// PreviousState returns the previous state of the devices config as
+// ygot.GoStruct.
+func (c *Change) PreviousState() ygot.GoStruct {
+	return c.previousState
+}
+
+// IntendedState returns the intended state of the devices config as
+// ygot.GoStruct.
+func (c *Change) IntendedState() ygot.GoStruct {
+	return c.intendedState
+}
+
 func stateManager(ctx context.Context, ch *Change, timeout time.Duration) (chan<- ppb.ChangeState, <-chan ppb.ChangeState, <-chan error) {
 	stateIn := make(chan ppb.ChangeState)
 	stateOut := make(chan ppb.ChangeState)
diff --git a/controller/nucleus/principalNetworkDomain.go b/controller/nucleus/principalNetworkDomain.go
index 3d23862bc..ad4b601c7 100644
--- a/controller/nucleus/principalNetworkDomain.go
+++ b/controller/nucleus/principalNetworkDomain.go
@@ -215,32 +215,31 @@ func (pnd *pndImplementation) RemoveSbi(sid uuid.UUID) error {
 }
 
 // AddDevice adds a new device to the PND
-func (pnd *pndImplementation) AddDevice(name string, opt *tpb.TransportOption, sid uuid.UUID) error {
+func (pnd *pndImplementation) AddDevice(name string, opt *tpb.TransportOption, sid uuid.UUID) (uuid.UUID, error) {
 	labels := prometheus.Labels{"type": opt.Type.String()}
 	start := metrics.StartHook(labels, deviceCreationsTotal)
 	defer metrics.FinishHook(labels, start, deviceCreationDurationSecondsTotal, deviceCreationDurationSeconds)
 	var sbi southbound.SouthboundInterface
+	var err error
 
 	switch t := opt.Type; t {
 	case spb.Type_TYPE_CONTAINERISED:
 		return pnd.handleCsbiEnrolment(name, opt)
 	case spb.Type_TYPE_PLUGIN:
-		var err error
 		sbi, err = pnd.requestPlugin(name, opt)
 		if err != nil {
-			return err
+			return uuid.Nil, err
 		}
 	default:
-		var err error
 		sbi, err = pnd.sbic.Get(store.Query{ID: sid})
 		if err != nil {
-			return err
+			return uuid.Nil, err
 		}
 	}
 
 	d, err := NewDevice(name, uuid.Nil, opt, sbi)
 	if err != nil {
-		return err
+		return uuid.Nil, err
 	}
 	return pnd.addDevice(d)
 }
@@ -302,13 +301,13 @@ func (pnd *pndImplementation) removeSbi(id uuid.UUID) error {
 }
 
 // addDevice adds a device to the PND's device store.
-func (pnd *pndImplementation) addDevice(device device.Device) error {
+func (pnd *pndImplementation) addDevice(device device.Device) (uuid.UUID, error) {
 	err := pnd.devices.Add(device)
 	if err != nil {
-		return err
+		return uuid.Nil, err
 	}
 
-	return nil
+	return device.ID(), nil
 }
 
 func (pnd *pndImplementation) removeDevice(id uuid.UUID) error {
@@ -492,7 +491,7 @@ func (pnd *pndImplementation) handleCsbiDeletion(id uuid.UUID) error {
 	return nil
 }
 
-func (pnd *pndImplementation) handleCsbiEnrolment(name string, opt *tpb.TransportOption) error {
+func (pnd *pndImplementation) handleCsbiEnrolment(name string, opt *tpb.TransportOption) (uuid.UUID, error) {
 	g := new(errgroup.Group)
 	ctx, cancel := context.WithTimeout(context.Background(), time.Minute*5)
 	defer cancel()
@@ -502,20 +501,26 @@ func (pnd *pndImplementation) handleCsbiEnrolment(name string, opt *tpb.Transpor
 	}
 	resp, err := pnd.csbiClient.Create(ctx, req)
 	if err != nil {
-		return err
+		return uuid.Nil, err
 	}
+	// the slice only contains one deployment
+	var devID uuid.UUID
 	for _, d := range resp.Deployments {
 		dCopy := d
 		g.Go(func() error {
-			return pnd.createCsbiDevice(ctx, name, dCopy, opt)
+			devID, err = pnd.createCsbiDevice(ctx, name, dCopy, opt)
+			if err != nil {
+				return err
+			}
+			return nil
 		})
 	}
 	err = g.Wait()
 	if err != nil {
-		return err
+		return uuid.Nil, err
 	}
 
-	return nil
+	return devID, nil
 }
 
 // createCsbiDevice is a helper method for cSBI device creation. The method
@@ -526,10 +531,10 @@ func (pnd *pndImplementation) createCsbiDevice(
 	name string,
 	d *cpb.Deployment,
 	opt *tpb.TransportOption,
-) error {
+) (uuid.UUID, error) {
 	id, err := uuid.Parse(d.Id)
 	if err != nil {
-		return err
+		return uuid.Nil, err
 	}
 	ch := make(chan device.Details, 1)
 	pnd.callback(id, ch)
@@ -547,7 +552,7 @@ func (pnd *pndImplementation) createCsbiDevice(
 		log.Infof("syn from csbi %v", deviceDetails.ID)
 		id, err := uuid.Parse(deviceDetails.ID)
 		if err != nil {
-			return err
+			return uuid.Nil, err
 		}
 		csbiTransportOptions := &tpb.TransportOption{
 			Address:         deviceDetails.Address,
@@ -568,41 +573,42 @@ func (pnd *pndImplementation) createCsbiDevice(
 		// here and in csbi.
 		gClient, err := pnd.csbiClient.GetGoStruct(ctx, req)
 		if err != nil {
-			return err
+			return uuid.Nil, err
 		}
 		csbiID, err := saveGenericClientStreamToFile(gClient, "gostructs.go", uuid.New())
 		if err != nil {
-			return err
+			return uuid.Nil, err
 		}
 		// TODO: this is currently just a workaround needs major adjustments
 		// here and in csbi.
 		mClient, err := pnd.csbiClient.GetManifest(ctx, req)
 		if err != nil {
-			return err
+			return uuid.Nil, err
 		}
 		_, err = saveGenericClientStreamToFile(mClient, "plugin.yml", csbiID)
 		if err != nil {
-			return err
+			return uuid.Nil, err
 		}
 		csbi, err := NewSBI(spb.Type_TYPE_CONTAINERISED, csbiID)
 		if err != nil {
-			return err
+			return uuid.Nil, err
 		}
 		err = pnd.sbic.Add(csbi)
 		if err != nil {
-			return err
+			return uuid.Nil, err
 		}
 		d, err := NewDevice(name, uuid.Nil, csbiTransportOptions, csbi)
 		if err != nil {
-			return err
+			return uuid.Nil, err
 		}
 		d.(*CsbiDevice).UUID = id
 		ch <- device.Details{TransportOption: opt}
 		if err := pnd.devices.Add(d); err != nil {
-			return err
+			return uuid.Nil, err
 		}
+		return id, nil
 	}
-	return nil
+	return uuid.Nil, nil
 }
 
 // requestPlugin is a feature for cSBIs and sends a plugin request to the cSBI
diff --git a/controller/nucleus/principalNetworkDomain_test.go b/controller/nucleus/principalNetworkDomain_test.go
index 2045bd626..a53a7790f 100644
--- a/controller/nucleus/principalNetworkDomain_test.go
+++ b/controller/nucleus/principalNetworkDomain_test.go
@@ -115,7 +115,7 @@ func Test_pndImplementation_AddDevice(t *testing.T) {
 				t.Error(err)
 			}
 
-			err := pnd.AddDevice(tt.args.name, tt.args.opts, defaultSbiID)
+			_, err := pnd.AddDevice(tt.args.name, tt.args.opts, defaultSbiID)
 			if (err != nil) != tt.wantErr {
 				t.Errorf("AddDevice() error = %v, wantErr %v", err, tt.wantErr)
 			}
@@ -290,7 +290,8 @@ func Test_pndImplementation_MarshalDevice(t *testing.T) {
 				sbi:       sbi,
 				transport: nil,
 			}
-			if err := pnd.addDevice(d); err != nil {
+			_, err = pnd.addDevice(d)
+			if err != nil {
 				t.Error(err)
 			}
 			got, err := pnd.MarshalDevice(tt.args.uuid.String())
@@ -339,7 +340,8 @@ func Test_pndImplementation_RemoveDevice(t *testing.T) {
 				sbi:       sbi,
 				transport: nil,
 			}
-			if err := pnd.addDevice(d); err != nil {
+			_, err = pnd.addDevice(d)
+			if err != nil {
 				t.Error(err)
 			}
 			if err := pnd.RemoveDevice(tt.args.uuid); (err != nil) != tt.wantErr {
@@ -454,10 +456,12 @@ func Test_pndImplementation_RemoveSbiWithAssociatedDevices(t *testing.T) {
 			if err := pnd.addSbi(&OpenConfig{id: defaultSbiID}); err != nil {
 				t.Error(err)
 			}
-			if err := pnd.AddDevice("associatedDevice", opts, tt.args.id); err != nil {
+			_, err = pnd.AddDevice("associatedDevice", opts, tt.args.id)
+			if err != nil {
 				t.Error(err)
 			}
-			if err := pnd.AddDevice("associatedDevice2", opts, tt.args.id); err != nil {
+			_, err = pnd.AddDevice("associatedDevice2", opts, tt.args.id)
+			if err != nil {
 				t.Error(err)
 			}
 			if tt.name == "exclusively remove associated devices" {
@@ -465,7 +469,8 @@ func Test_pndImplementation_RemoveSbiWithAssociatedDevices(t *testing.T) {
 				if err := pnd.addSbi(&OpenConfig{id: newID}); err != nil {
 					t.Error(err)
 				}
-				if err := pnd.AddDevice("associatedDevice2", opts, newID); err != nil {
+				_, err := pnd.AddDevice("associatedDevice2", opts, newID)
+				if err != nil {
 					t.Error(err)
 				}
 			}
@@ -560,7 +565,7 @@ func Test_pndImplementation_Request(t *testing.T) {
 				transport: &transport,
 			}
 
-			_ = pnd.addDevice(deviceWithMockTransport)
+			_, _ = pnd.addDevice(deviceWithMockTransport)
 
 			_, err = pnd.Request(tt.args.uuid, tt.args.path)
 			if (err != nil) != tt.wantErr {
@@ -644,7 +649,7 @@ func Test_pndImplementation_RequestAll(t *testing.T) {
 				transport: &transport,
 			}
 
-			_ = pnd.addDevice(deviceWithMockTransport)
+			_, _ = pnd.addDevice(deviceWithMockTransport)
 
 			device, _ := pnd.devices.Get(store.Query{ID: mdid})
 			if device == nil {
@@ -756,7 +761,8 @@ func Test_pndImplementation_ChangeOND(t *testing.T) {
 			if err := pnd.addSbi(&OpenConfig{id: defaultSbiID}); err != nil {
 				t.Error(err)
 			}
-			if err := pnd.AddDevice("testdevice", opts, defaultSbiID); err != nil {
+			_, err := pnd.AddDevice("testdevice", opts, defaultSbiID)
+			if err != nil {
 				t.Error(err)
 				return
 			}
@@ -799,7 +805,8 @@ func Test_pndImplementation_GetDevice(t *testing.T) {
 		t.Error(err)
 		return
 	}
-	if err = pnd.addDevice(d); err != nil {
+	_, err = pnd.addDevice(d)
+	if err != nil {
 		t.Error(err)
 		return
 	}
@@ -859,7 +866,8 @@ func Test_pndImplementation_GetDeviceByName(t *testing.T) {
 		t.Error(err)
 		return
 	}
-	if err = pnd.addDevice(d); err != nil {
+	_, err = pnd.addDevice(d)
+	if err != nil {
 		t.Error(err)
 		return
 	}
@@ -933,11 +941,12 @@ func Test_pndImplementation_Confirm(t *testing.T) {
 			d := mockDevice()
 			tr := d.Transport().(*mocks.Transport)
 			tr.On("Set", mockContext, mock.Anything, mock.Anything).Return(nil)
-			if err := pnd.addDevice(d); err != nil {
+			_, err := pnd.addDevice(d)
+			if err != nil {
 				t.Error(err)
 				return
 			}
-			_, err := pnd.ChangeOND(d.ID(), ppb.ApiOperation_API_OPERATION_UPDATE, "system/config/hostname", "ceos3000")
+			_, err = pnd.ChangeOND(d.ID(), ppb.ApiOperation_API_OPERATION_UPDATE, "system/config/hostname", "ceos3000")
 			if err != nil {
 				t.Error(err)
 				return
diff --git a/controller/test/integration/nucleusIntegration_test.go b/controller/test/integration/nucleusIntegration_test.go
index c7d44567d..b325c8554 100644
--- a/controller/test/integration/nucleusIntegration_test.go
+++ b/controller/test/integration/nucleusIntegration_test.go
@@ -177,7 +177,8 @@ func TestGnmi_SetValidIntegration(t *testing.T) {
 		t.Error(err)
 		return
 	}
-	if err := pnd.AddDevice("test", opt, sbi.ID()); err != nil {
+	_, err = pnd.AddDevice("test", opt, sbi.ID())
+	if err != nil {
 		t.Error(err)
 		return
 	}
diff --git a/go.mod b/go.mod
index 9718a98b6..b53bb1331 100644
--- a/go.mod
+++ b/go.mod
@@ -28,6 +28,7 @@ require (
 require (
 	github.com/c-bata/go-prompt v0.2.6
 	github.com/mitchellh/go-homedir v1.1.0
+	github.com/pterm/pterm v0.12.41
 	github.com/spf13/pflag v1.0.5
 	go.mongodb.org/mongo-driver v1.8.4
 	google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa
@@ -35,6 +36,14 @@ require (
 
 require github.com/sethvargo/go-password v0.2.0
 
+require (
+	github.com/atomicgo/cursor v0.0.1 // indirect
+	github.com/gookit/color v1.5.0 // indirect
+	github.com/rivo/uniseg v0.2.0 // indirect
+	github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778 // indirect
+	golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect
+)
+
 require (
 	github.com/Microsoft/go-winio v0.5.1 // indirect
 	github.com/Microsoft/hcsshim v0.9.2 // indirect
@@ -61,7 +70,7 @@ require (
 	github.com/magiconair/properties v1.8.5 // indirect
 	github.com/mattn/go-colorable v0.1.7 // indirect
 	github.com/mattn/go-isatty v0.0.12 // indirect
-	github.com/mattn/go-runewidth v0.0.9 // indirect
+	github.com/mattn/go-runewidth v0.0.13 // indirect
 	github.com/mattn/go-tty v0.0.3 // indirect
 	github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 // indirect
 	github.com/mitchellh/mapstructure v1.4.2 // indirect
@@ -88,7 +97,7 @@ require (
 	go.opencensus.io v0.23.0 // indirect
 	golang.org/x/crypto v0.0.0-20210817164053-32db794688a5 // indirect
 	golang.org/x/net v0.0.0-20211216030914-fe4d6282115f // indirect
-	golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e // indirect
+	golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8 // indirect
 	golang.org/x/text v0.3.7 // indirect
 	golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
 	gopkg.in/ini.v1 v1.64.0 // indirect
diff --git a/go.sum b/go.sum
index edc081bb5..a4c712aba 100644
--- a/go.sum
+++ b/go.sum
@@ -77,6 +77,14 @@ github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBp
 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/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0=
+github.com/MarvinJWendt/testza v0.1.0/go.mod h1:7AxNvlfeHP7Z/hDQ5JtE3OKYT3XFUeLCDE2DQninSqs=
+github.com/MarvinJWendt/testza v0.2.1/go.mod h1:God7bhG8n6uQxwdScay+gjm9/LnO4D3kkcZX4hv9Rp8=
+github.com/MarvinJWendt/testza v0.2.8/go.mod h1:nwIcjmr0Zz+Rcwfh3/4UhBp7ePKVhuBExvZqnKYWlII=
+github.com/MarvinJWendt/testza v0.2.10/go.mod h1:pd+VWsoGUiFtq+hRKSU1Bktnn+DMCSrDrXDpX2bG66k=
+github.com/MarvinJWendt/testza v0.2.12/go.mod h1:JOIegYyV7rX+7VZ9r77L/eH6CfJHHzXjB69adAhzZkI=
+github.com/MarvinJWendt/testza v0.3.0/go.mod h1:eFcL4I0idjtIx8P9C6KkAuLgATNKpX4/2oUqKc6bF2c=
+github.com/MarvinJWendt/testza v0.3.5 h1:g9krITRRlIsF1eO9sUKXtiTw670gZIIk6T08Keeo1nM=
+github.com/MarvinJWendt/testza v0.3.5/go.mod h1:ExbTpWmA1z2E9HSskvrNcwApoX4F9bID692s10nuHRY=
 github.com/Microsoft/go-winio v0.4.11/go.mod h1:VhR8bwka0BXejwEJY73c50VrPtXAaKcyvVC4A4RozmA=
 github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA=
 github.com/Microsoft/go-winio v0.4.15-0.20190919025122-fc70bd9a86b5/go.mod h1:tTuCMEN+UleMWgg9dVx4Hu52b1bJo+59jBh3ajtinzw=
@@ -140,6 +148,8 @@ github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj
 github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
 github.com/aryann/difflib v0.0.0-20170710044230-e206f873d14a/go.mod h1:DAHtR1m6lCRdSC2Tm3DSWRPvIPr6xNKyeHdqDQSQT+A=
 github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
+github.com/atomicgo/cursor v0.0.1 h1:xdogsqa6YYlLfM+GyClC/Lchf7aiMerFiZQn7soTOoU=
+github.com/atomicgo/cursor v0.0.1/go.mod h1:cBON2QmmrysudxNBFthvMtN32r3jxVRIvzkUiF/RuIk=
 github.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQwij/eHl5CU=
 github.com/aws/aws-sdk-go v1.15.11/go.mod h1:mFuSZ37Z9YOHbQEwBWztmVzqXrEkub65tZoCYDt7FT0=
 github.com/aws/aws-sdk-go v1.27.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
@@ -557,6 +567,9 @@ github.com/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pf
 github.com/googleapis/gnostic v0.4.1/go.mod h1:LRhVm6pbyptWbWbuZ38d1eyptfvIytN3ir6b65WBswg=
 github.com/googleapis/gnostic v0.5.1/go.mod h1:6U4PtQXGIEt/Z3h5MAT7FNofLnw9vXk2cUuW7uA/OeU=
 github.com/googleapis/gnostic v0.5.5/go.mod h1:7+EbHbldMins07ALC74bsA81Ovc97DwqyJO1AENw9kA=
+github.com/gookit/color v1.4.2/go.mod h1:fqRyamkC1W8uxl+lxCQxOT09l/vYfZ+QeiX3rKQHCoQ=
+github.com/gookit/color v1.5.0 h1:1Opow3+BWDwqor78DcJkJCIwnkviFi+rrOANki9BUFw=
+github.com/gookit/color v1.5.0/go.mod h1:43aQb+Zerm/BWh2GnrgOQm7ffz7tvQXEKV6BFMl7wAo=
 github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
 github.com/gopherjs/gopherjs v0.0.0-20200217142428-fce0ec30dd00/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
 github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
@@ -671,9 +684,14 @@ github.com/klauspost/compress v1.11.9/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYs
 github.com/klauspost/compress v1.11.13/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
 github.com/klauspost/compress v1.13.6 h1:P76CopJELS0TiO2mebmnzgWaajssP/EszplttgQxcgc=
 github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
+github.com/klauspost/cpuid v1.2.0 h1:NMpwD2G9JSFOE1/TJjGSo5zG7Yb2bTe7eq1jH+irmeE=
 github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
 github.com/klauspost/cpuid/v2 v2.0.2/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
 github.com/klauspost/cpuid/v2 v2.0.4/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
+github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
+github.com/klauspost/cpuid/v2 v2.0.10/go.mod h1:g2LTdtYhdyuGPqyWyv7qRAmj1WBqxuObKfj5c0PQa7c=
+github.com/klauspost/cpuid/v2 v2.0.12 h1:p9dKCg8i4gmOxtv35DvrYoWqYzQrvEVdjQ762Y0OqZE=
+github.com/klauspost/cpuid/v2 v2.0.12/go.mod h1:g2LTdtYhdyuGPqyWyv7qRAmj1WBqxuObKfj5c0PQa7c=
 github.com/klauspost/pgzip v1.2.4/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs=
 github.com/klauspost/pgzip v1.2.5/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs=
 github.com/klauspost/reedsolomon v1.9.11/go.mod h1:nLvuzNvy1ZDNQW30IuMc2ZWCbiqrJgdLoUS2X8HAUVg=
@@ -722,8 +740,9 @@ github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHX
 github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
 github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
 github.com/mattn/go-runewidth v0.0.6/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
-github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0=
 github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
+github.com/mattn/go-runewidth v0.0.13 h1:lTGmDsbAYt5DmK6OnoV7EuIF1wEIFAcxld6ypU4OSgU=
+github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
 github.com/mattn/go-shellwords v1.0.3/go.mod h1:3xCvwCdWdlDJUrvuMn7Wuy9eWs4pE8vqg+NOMyg4B2o=
 github.com/mattn/go-shellwords v1.0.6/go.mod h1:3xCvwCdWdlDJUrvuMn7Wuy9eWs4pE8vqg+NOMyg4B2o=
 github.com/mattn/go-shellwords v1.0.12/go.mod h1:EZzvwXDESEeg03EKmM+RmDnNOPKG4lLtQsUlTZDWQ8Y=
@@ -962,8 +981,19 @@ github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1
 github.com/prometheus/procfs v0.7.3 h1:4jVXhlkAyzOScmCkXBTOLRLTz8EeU+eyjrwB/EPq0VU=
 github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
 github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
+github.com/pterm/pterm v0.12.27/go.mod h1:PhQ89w4i95rhgE+xedAoqous6K9X+r6aSOI2eFF7DZI=
+github.com/pterm/pterm v0.12.29/go.mod h1:WI3qxgvoQFFGKGjGnJR849gU0TsEOvKn5Q8LlY1U7lg=
+github.com/pterm/pterm v0.12.30/go.mod h1:MOqLIyMOgmTDz9yorcYbcw+HsgoZo3BQfg2wtl3HEFE=
+github.com/pterm/pterm v0.12.31/go.mod h1:32ZAWZVXD7ZfG0s8qqHXePte42kdz8ECtRyEejaWgXU=
+github.com/pterm/pterm v0.12.33/go.mod h1:x+h2uL+n7CP/rel9+bImHD5lF3nM9vJj80k9ybiiTTE=
+github.com/pterm/pterm v0.12.36/go.mod h1:NjiL09hFhT/vWjQHSj1athJpx6H8cjpHXNAK5bUw8T8=
+github.com/pterm/pterm v0.12.40/go.mod h1:ffwPLwlbXxP+rxT0GsgDTzS3y3rmpAO1NMjUkGTYf8s=
+github.com/pterm/pterm v0.12.41 h1:e2BRfFo1H9nL8GY0S3ImbZqfZ/YimOk9XtkhoobKJVs=
+github.com/pterm/pterm v0.12.41/go.mod h1:LW/G4J2A42XlTaPTAGRPvbBfF4UXvHWhC6SN7ueU4jU=
 github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
 github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
+github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
+github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
 github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
 github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
 github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
@@ -979,6 +1009,8 @@ github.com/sclevine/spec v1.2.0/go.mod h1:W4J29eT/Kzv7/b9IWLB055Z+qvVC9vt0Arko24
 github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
 github.com/seccomp/libseccomp-golang v0.9.1/go.mod h1:GbW5+tmTXfcxTToHLXlScSlAvWlF4P2Ca7zGrPiEpWo=
 github.com/seccomp/libseccomp-golang v0.9.2-0.20210429002308-3879420cc921/go.mod h1:JA8cRccbGaA1s33RQf7Y1+q9gHmZX1yB/z9WDN1C6fg=
+github.com/sergi/go-diff v1.2.0 h1:XU+rvMAioB0UC3q1MFrIQy4Vo5/4VsRDQQXHsEya6xQ=
+github.com/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
 github.com/sethvargo/go-password v0.2.0 h1:BTDl4CC/gjf/axHMaDQtw507ogrXLci6XRiLc7i/UHI=
 github.com/sethvargo/go-password v0.2.0/go.mod h1:Ym4Mr9JXLBycr02MFuVQ/0JHidNetSgbzutTr3zsYXE=
 github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
@@ -1092,6 +1124,8 @@ github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:
 github.com/xeipuuv/gojsonschema v0.0.0-20180618132009-1d523034197f/go.mod h1:5yf86TLmAcydyeJq5YvxkGPE2fm/u4myDekKRoLuqhs=
 github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8/go.mod h1:HUYIGzjTL3rfEspMxjDjgmT5uz5wzYJKVo23qUhYTos=
 github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
+github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778 h1:QldyIu/L63oPpyvQmHgvgickp1Yw510KJOqX7H24mg8=
+github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778/go.mod h1:2MuV+tbUrU1zIOPMxZ5EncGwgmMJsa+9ucAQZXxsObs=
 github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
 github.com/xtaci/kcp-go v5.4.20+incompatible/go.mod h1:bN6vIwHQbfHaHtFpEssmWsN45a+AZwO7eyRCmEIbtvE=
 github.com/xtaci/lossyconn v0.0.0-20190602105132-8df528c0c9ae/go.mod h1:gXtu8J62kEgmN++bm9BVICuT/e8yiLI2KFobd/TRFsE=
@@ -1423,14 +1457,18 @@ golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBc
 golang.org/x/sys v0.0.0-20210831042530-f4d43177bf5e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20210903071746-97244b99971b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20210906170528-6f6e22806c34/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20211013075003-97ac67df715c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20211116061358-0a5406a5449c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e h1:fLOSk5Q00efkSvAm+4xcoXD+RRmLmmulPn5I3Y9F2EM=
 golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8 h1:OH54vjqzRWmbJ62fjuhxy7AxFFgoHN0/DPc/UrL8cAs=
+golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
 golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
 golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
 golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
+golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY=
+golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
 golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/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=
-- 
GitLab