summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorbt <bt@rctt.net>2026-03-14 23:11:15 +0100
committerbt <bt@rctt.net>2026-03-18 16:21:58 +0100
commit54ddec67c477a6fd73b0f623258c0849ba695b88 (patch)
tree3a34b67e62b8788f0611abc4f9f8cfe7954aae46
parent8932846aa4d29d59fd208f40bbfd44d1bb9cf1ff (diff)
downloadsolec-54ddec67c477a6fd73b0f623258c0849ba695b88.tar.gz
solec-54ddec67c477a6fd73b0f623258c0849ba695b88.zip
Basic server implementation
-rw-r--r--README.md14
-rw-r--r--cmd/client/main.go87
-rw-r--r--cmd/daemon/main.go58
-rw-r--r--cmd/mock/main.go41
-rw-r--r--cmd/test/main.go2
-rw-r--r--core/data.go30
-rw-r--r--core/data_test.go3
-rw-r--r--core/network.go23
-rw-r--r--core/payload.go95
-rw-r--r--go.mod2
-rwxr-xr-xhooks/pre-commit8
-rw-r--r--prompt/prompt.go29
-rwxr-xr-xrun.sh6
-rw-r--r--server/server.go188
-rw-r--r--solec.ksy55
-rw-r--r--solec.lua118
-rw-r--r--solec.svg839
-rwxr-xr-xtools/build_spec.sh (renamed from build_spec.sh)0
-rwxr-xr-xtools/run.sh8
19 files changed, 1013 insertions, 593 deletions
diff --git a/README.md b/README.md
index ee8e555..c24b68b 100644
--- a/README.md
+++ b/README.md
@@ -8,18 +8,28 @@ You'll need Go toolchain. Get it [here](https://go.dev/dl/)
```
git clone https://git.sr.ht/~rctt/solec
-cd solecd
+cd solec
go run cmd/daemon/main.go
```
+## Development
+
+Use following to setup Git hooks:
+`git config --local core.hooksPath hooks`
+
+* `tools/run.sh` - build and start server and few clients
+* `tools/build-spec.sh` - build Kaitai spec
+
## Wireshark plugin
To build wireshark plugin you'll need Kaitai Struct Compiler.
KSC currently doesn't support Wireshark plugin generation but
[there is a discussion]("https://github.com/kaitai-io/kaitai_struct/issues/50#issuecomment-1485044090").
-After building foked KSC use `./build_spec.sh` to build the plugin and then put
+After building foked KSC use `./tools/build_spec.sh` to build the plugin and then put
it into Wireshark plugins directory.
+There is a problem with dissecting specific payloads.
+
## TODO
- Protocol
diff --git a/cmd/client/main.go b/cmd/client/main.go
index 6e5d996..2612267 100644
--- a/cmd/client/main.go
+++ b/cmd/client/main.go
@@ -4,58 +4,87 @@ import (
"flag"
"log"
"net"
+ "strings"
"time"
- "git.sr.ht/~rctt/solecd/core"
+ "git.sr.ht/~rctt/solec/core"
+ "git.sr.ht/~rctt/solec/prompt"
)
-var serverAddr string
+var (
+ serverAddr string
+ user string
+ conn net.Conn
+)
func main() {
+ prompt.Commands["*"] = broadcast
+
flag.StringVar(&serverAddr, "a", "localhost:9999", "Server address:port")
+ flag.StringVar(&user, "u", "user", "username")
flag.Parse()
- var d net.Dialer
+ var (
+ d net.Dialer
+ err error
+ )
- conn, err := d.Dial("tcp", serverAddr)
+ log.Println("connecting to " + serverAddr + " as " + user)
+
+ conn, err = d.Dial("tcp", serverAddr)
if err != nil {
log.Fatal("cannot dial: ", err)
}
defer conn.Close()
- ping(conn)
+ hs := core.Handshake{0, 1}
+ if err := core.Send(conn, hs); err != nil {
+ panic(err)
+ }
+
+ auth := core.Auth{user, "pass"}
+ if err := core.Send(conn, auth); err != nil {
+ panic(err)
+ }
+
+ go prompt.Read()
+
+ read(conn)
}
-func ping(conn net.Conn) {
+func read(conn net.Conn) {
for {
- log.Print("ping")
- data, err := core.Encode(core.Pong{Timestamp: time.Now()})
+ payload, err := core.Read(conn)
if err != nil {
panic(err)
}
- if _, err := conn.Write(data); err != nil {
- panic(err)
- }
- test := core.Test{
- Num1: 1,
- Time1: time.Now(),
- Str1: "test string",
- Num2: 2,
- Bin1: []byte{0x01, 0x02, 0x03},
- Num3: 3,
- Str2: "こんにちは",
- Num4: 4,
- }
+ handlePayload(conn, payload)
+ }
+}
- data, err = core.Encode(test)
- if err != nil {
- panic(err)
- }
- if _, err = conn.Write(data); err != nil {
- panic(err)
- }
+func handlePayload(conn net.Conn, payload any) {
+ switch v := payload.(type) {
+ case core.Message:
+ handleMessage(conn, v)
+ }
+}
+
+func handleMessage(conn net.Conn, msg core.Message) {
+ log.Println("received message", msg.Source, "->", msg.Target, msg.Content)
+}
+
+func broadcast(args []string) {
+ msg := core.Message{
+ Source: user,
+ Target: "*",
+ Timestamp: time.Now(),
+ Content: strings.Join(args[0:], " "),
+ }
+
+ log.Println(msg.Content)
- time.Sleep(time.Second)
+ if err := core.Send(conn, msg); err != nil {
+ panic(err)
}
}
diff --git a/cmd/daemon/main.go b/cmd/daemon/main.go
index b55cc69..56b7c16 100644
--- a/cmd/daemon/main.go
+++ b/cmd/daemon/main.go
@@ -1,39 +1,53 @@
package main
import (
- "flag"
+ "bufio"
+ "fmt"
"log"
- "net"
+ "maps"
+ "os"
+ "slices"
+ "strings"
- "git.sr.ht/~rctt/solecd/core"
+ "git.sr.ht/~rctt/solec/server"
)
-var listenAddr string
+var (
+ cmds = map[string]func(args []string){
+ "ping": sendPing,
+ }
-func main() {
- flag.StringVar(&listenAddr, "a", "localhost:9999", "Listening address:port")
- flag.Parse()
+ serv = server.NewServer("localhost:9999")
+)
- log.Print("starting solec daemon mock")
- log.Fatal(listen())
-}
+func main() {
+ fmt.Println("SOLEC MOCK SERVER")
+ fmt.Println("Commands:", slices.Sorted(maps.Keys(cmds)))
-func listen() error {
- ln, err := net.Listen("tcp", listenAddr)
- if err != nil {
- return err
+ if err := serv.Start(); err != nil {
+ panic(err)
}
+ readCmds()
+}
- log.Print("server is listening on: ", listenAddr)
+func readCmds() {
+ sc := bufio.NewScanner(os.Stdin)
+ for sc.Scan() {
+ args := strings.Split(sc.Text(), " ")
- for {
- conn, err := ln.Accept()
- if err != nil {
- log.Print("cannot accept connection: ", err)
+ cmd, ok := cmds[args[0]]
+ if !ok {
+ fmt.Println("unknown command")
+ continue
}
- log.Print("received connection from: ", conn.RemoteAddr())
-
- go core.ReadConnection(conn)
+ cmd(args[1:])
+ }
+ if err := sc.Err(); err != nil {
+ log.Println(err)
}
}
+
+func sendPing(args []string) {
+
+}
diff --git a/cmd/mock/main.go b/cmd/mock/main.go
deleted file mode 100644
index c4c726c..0000000
--- a/cmd/mock/main.go
+++ /dev/null
@@ -1,41 +0,0 @@
-package main
-
-import (
- "bufio"
- "fmt"
- "log"
- "maps"
- "os"
- "slices"
- "strings"
-)
-
-var cmds = map[string]func(args []string){
- "ping": sendPing,
-}
-
-func main() {
- fmt.Println("SOLEC MOCK SERVER")
- fmt.Println("Commands:", slices.Sorted(maps.Keys(cmds)))
-
- scanner := bufio.NewScanner(os.Stdin)
- for scanner.Scan() {
- args := strings.Split(scanner.Text(), " ")
-
- cmd, ok := cmds[args[0]]
- if !ok {
- fmt.Println("unknown command")
- continue
- }
-
- cmd(args[1:])
- }
-
- if err := scanner.Err(); err != nil {
- log.Println(err)
- }
-}
-
-func sendPing(args []string) {
-
-}
diff --git a/cmd/test/main.go b/cmd/test/main.go
index 35eddad..05768ea 100644
--- a/cmd/test/main.go
+++ b/cmd/test/main.go
@@ -5,7 +5,7 @@ import (
"fmt"
"time"
- "git.sr.ht/~rctt/solecd/core"
+ "git.sr.ht/~rctt/solec/core"
)
func main() {
diff --git a/core/data.go b/core/data.go
index 16775db..b25b853 100644
--- a/core/data.go
+++ b/core/data.go
@@ -16,13 +16,21 @@ type PayloadType uint8
const (
PayloadUnknown PayloadType = 0x00
- PayloadHandshake = 0x01
- PayloadPing = 0x02
- PayloadPong = 0x03
- PayloadMessage = 0x04
+ PayloadSuccess = 0x01
+ PayloadError = 0x02
+ PayloadHandshake = 0x03
+ PayloadAuth = 0x04
+ PayloadMessage = 0x05
PayloadTest = 0xFF
)
+type ErrorType uint8
+
+const (
+ ErrorUnknown ErrorType = 0x00
+ ErrorAuthFailed = 0x01
+)
+
type Frame struct {
Length uint16
Type PayloadType
@@ -41,12 +49,13 @@ func Encode(w Wrapper) ([]byte, error) {
for _, p := range payload {
switch v := p.(type) {
case string:
- err := binary.Write(buf, binary.BigEndian, uint16(len(v)))
+ strBytes := []byte(v)
+ err := binary.Write(buf, binary.BigEndian, uint16(len(strBytes)))
if err != nil {
return []byte{}, fmt.Errorf("cannot encode string length: %v", err)
}
- _, err = buf.WriteString(v)
+ _, err = buf.Write(strBytes)
if err != nil {
return []byte{}, fmt.Errorf("cannot encode string: %v", err)
}
@@ -100,11 +109,16 @@ func Decode(buf io.Reader) (any, error) {
}
switch pType {
+ case PayloadSuccess:
+ return Success{}, nil
+ case PayloadError:
+ return DecodeError(buf)
case PayloadHandshake:
return DecodeHandshake(buf)
- case PayloadPing:
- case PayloadPong:
+ case PayloadAuth:
+ return DecodeAuth(buf)
case PayloadMessage:
+ return DecodeMessage(buf)
case PayloadTest:
return DecodeTest(buf)
default:
diff --git a/core/data_test.go b/core/data_test.go
index 1275ef4..af986cc 100644
--- a/core/data_test.go
+++ b/core/data_test.go
@@ -1,6 +1,7 @@
package core
import (
+ "bytes"
"testing"
"time"
@@ -24,7 +25,7 @@ func TestEncoder(t *testing.T) {
t.Error(err)
}
- out, err := Decode(data)
+ out, err := Decode(bytes.NewBuffer(data))
if err != nil {
t.Error(err)
}
diff --git a/core/network.go b/core/network.go
index c182e7f..932cdca 100644
--- a/core/network.go
+++ b/core/network.go
@@ -1,24 +1,19 @@
package core
import (
- "fmt"
"net"
)
-func ReadConnection(conn net.Conn) {
- for {
- payload, err := Decode(conn)
- if err != nil {
- panic(err)
- }
-
- if err := handle(payload); err != nil {
- panic(err)
- }
+func Send(conn net.Conn, payload Wrapper) error {
+ data, err := Encode(payload)
+ if err != nil {
+ return err
}
+
+ _, err = conn.Write(data)
+ return err
}
-func handle(payload any) error {
- fmt.Println(payload)
- return nil
+func Read(conn net.Conn) (any, error) {
+ return Decode(conn)
}
diff --git a/core/payload.go b/core/payload.go
index 0711040..b8e8b9f 100644
--- a/core/payload.go
+++ b/core/payload.go
@@ -5,6 +5,35 @@ import (
"time"
)
+type Success struct{}
+
+func (s Success) Wrap() (PayloadType, []any) {
+ return PayloadSuccess, []any{}
+}
+
+type Error struct {
+ ErrorType ErrorType
+}
+
+func (e Error) Wrap() (PayloadType, []any) {
+ return PayloadError, []any{e.ErrorType}
+}
+
+func DecodeError(buf io.Reader) (Error, error) {
+ var (
+ errorData uint8
+ e Error
+ )
+
+ err := decodeNumeric(buf, &errorData)
+ if err != nil {
+ return e, err
+ }
+
+ e.ErrorType = ErrorType(errorData)
+ return e, nil
+}
+
type Handshake struct {
Major, Minor uint8
}
@@ -31,30 +60,72 @@ func DecodeHandshake(buf io.Reader) (Handshake, error) {
return h, nil
}
-type Ping struct{}
+type Auth struct {
+ Name string
+ Pass string
+}
-func (p Ping) Wrap() (PayloadType, []any) {
- return PayloadPing, []any{}
+func (a Auth) Wrap() (PayloadType, []any) {
+ return PayloadAuth, []any{
+ a.Name, a.Pass,
+ }
}
-type Pong struct {
+func DecodeAuth(buf io.Reader) (Auth, error) {
+ var a Auth
+ err := decodeString(buf, &a.Name)
+ if err != nil {
+ return a, err
+ }
+
+ err = decodeString(buf, &a.Pass)
+ if err != nil {
+ return a, err
+ }
+
+ return a, nil
+}
+
+type Message struct {
+ Source string
+ Target string
Timestamp time.Time
+ Content string
}
-func (p Pong) Wrap() (PayloadType, []any) {
- return PayloadPong, []any{
- p.Timestamp,
+func (m Message) Wrap() (PayloadType, []any) {
+ return PayloadMessage, []any{
+ m.Source,
+ m.Target,
+ m.Timestamp,
+ m.Content,
}
}
-func DecodePong(buf io.Reader) (Pong, error) {
- var p Pong
- err := decodeTime(buf, &p.Timestamp)
+func DecodeMessage(buf io.Reader) (Message, error) {
+ var m Message
+
+ err := decodeString(buf, &m.Source)
+ if err != nil {
+ return m, err
+ }
+
+ err = decodeString(buf, &m.Target)
+ if err != nil {
+ return m, err
+ }
+
+ err = decodeTime(buf, &m.Timestamp)
+ if err != nil {
+ return m, err
+ }
+
+ err = decodeString(buf, &m.Content)
if err != nil {
- return p, err
+ return m, err
}
- return p, nil
+ return m, nil
}
type Test struct {
diff --git a/go.mod b/go.mod
index a4a5a0f..a5887e3 100644
--- a/go.mod
+++ b/go.mod
@@ -1,4 +1,4 @@
-module git.sr.ht/~rctt/solecd
+module git.sr.ht/~rctt/solec
go 1.25.0
diff --git a/hooks/pre-commit b/hooks/pre-commit
new file mode 100755
index 0000000..422b855
--- /dev/null
+++ b/hooks/pre-commit
@@ -0,0 +1,8 @@
+#!/bin/sh
+
+if [ $(git rev-parse --abbrev-ref HEAD) != "main" ]; then
+ exit 0
+fi
+
+echo "Running tests before commit to main"
+go test ./... \ No newline at end of file
diff --git a/prompt/prompt.go b/prompt/prompt.go
new file mode 100644
index 0000000..63c2a60
--- /dev/null
+++ b/prompt/prompt.go
@@ -0,0 +1,29 @@
+package prompt
+
+import (
+ "bufio"
+ "fmt"
+ "log"
+ "os"
+ "strings"
+)
+
+var Commands = make(map[string]func(args []string))
+
+func Read() {
+ sc := bufio.NewScanner(os.Stdin)
+ for sc.Scan() {
+ args := strings.Split(sc.Text(), " ")
+
+ cmd, ok := Commands[args[0]]
+ if !ok {
+ fmt.Println("unknown command")
+ continue
+ }
+
+ cmd(args[1:])
+ }
+ if err := sc.Err(); err != nil {
+ log.Println(err)
+ }
+}
diff --git a/run.sh b/run.sh
deleted file mode 100755
index a33fad9..0000000
--- a/run.sh
+++ /dev/null
@@ -1,6 +0,0 @@
-#!/bin/sh
-
-tmux \
- new-session "go run cmd/daemon/main.go; read" \; \
- split-window "sleep 0.5; go run cmd/client/main.go; read" \; \
- select-layout even-horizontal; \ No newline at end of file
diff --git a/server/server.go b/server/server.go
new file mode 100644
index 0000000..51e71b1
--- /dev/null
+++ b/server/server.go
@@ -0,0 +1,188 @@
+package server
+
+import (
+ "errors"
+ "fmt"
+ "log"
+ "net"
+ "sync"
+
+ "git.sr.ht/~rctt/solec/core"
+)
+
+type Server struct {
+ listenAddr string
+ users map[string]User
+ mu sync.Mutex
+}
+
+type User struct {
+ Name string
+ Conns map[net.Conn]struct{}
+}
+
+func NewServer(listenAddr string) *Server {
+ return &Server{
+ listenAddr: listenAddr,
+ users: make(map[string]User),
+ }
+}
+
+func (s *Server) Start() error {
+ ln, err := net.Listen("tcp", s.listenAddr)
+ if err != nil {
+ return err
+ }
+
+ for {
+ conn, err := ln.Accept()
+ if err != nil {
+ log.Print("cannot accept connection: ", err)
+ }
+
+ log.Print("received connection from: ", conn.RemoteAddr())
+
+ go s.handleConn(conn)
+ }
+}
+
+func (s *Server) handleConn(conn net.Conn) {
+ if err := s.performHandshake(conn); err != nil {
+ log.Println("handshake error", err)
+ return
+ }
+
+ user, err := s.performAuth(conn)
+ if err != nil {
+ log.Println("auth error", err)
+ return
+ }
+
+ defer func() {
+ s.mu.Lock()
+ log.Println("client disconnected: ", user.Name)
+ delete(s.users[user.Name].Conns, conn)
+ if len(s.users[user.Name].Conns) == 0 {
+ log.Println("all connections closed for user:", user.Name)
+ delete(s.users, user.Name)
+ }
+ s.mu.Unlock()
+ }()
+
+ if err := s.readInput(conn, user); err != nil {
+ log.Println("cannot read incomming data", err)
+ }
+}
+
+func (s *Server) performHandshake(conn net.Conn) error {
+ serverHs := core.Handshake{0, 1}
+
+ if err := core.Send(conn, serverHs); err != nil {
+ return err
+ }
+
+ clientPayload, err := core.Decode(conn)
+ if err != nil {
+ return err
+ }
+
+ clientHs, ok := clientPayload.(core.Handshake)
+ if !ok {
+ return errors.New("received payload of invalid type")
+ }
+
+ if serverHs.Major != clientHs.Major {
+ return errors.New("server and client are using different protocol version")
+ }
+
+ return nil
+}
+
+func (s *Server) performAuth(conn net.Conn) (User, error) {
+ clientPayload, err := core.Decode(conn)
+ if err != nil {
+ return User{}, err
+ }
+
+ clientAuth, ok := clientPayload.(core.Auth)
+ if !ok {
+ return User{}, errors.New("received payload of invalid type")
+ }
+
+ user, ok := s.users[clientAuth.Name]
+ if !ok {
+ log.Println("initial connection from user:", clientAuth.Name)
+ user = newUser(conn, clientAuth)
+ s.users[clientAuth.Name] = user
+ return user, nil
+ }
+
+ log.Println("next connection from user:", user.Name)
+ user.Conns[conn] = struct{}{}
+ return user, nil
+}
+
+func newUser(conn net.Conn, auth core.Auth) User {
+ u := User{
+ Name: auth.Name,
+ Conns: make(map[net.Conn]struct{}),
+ }
+
+ u.Conns[conn] = struct{}{}
+ return u
+}
+
+func (s *Server) readInput(conn net.Conn, user User) error {
+ for {
+ payload, err := core.Decode(conn)
+ if err != nil {
+ return fmt.Errorf("decoder error: %w", err)
+ }
+ if err := s.handlePayload(conn, user, payload); err != nil {
+ return fmt.Errorf("payload handler error: %w", err)
+ }
+ }
+}
+
+func (s *Server) handlePayload(conn net.Conn, user User, payload any) error {
+ switch v := payload.(type) {
+ case core.Message:
+ return s.handleMessage(conn, user, v)
+
+ default:
+ return errors.New("invalid payload")
+ }
+}
+
+func (s *Server) handleMessage(conn net.Conn, user User, msg core.Message) error {
+ log.Println("message:", user.Name, "->", msg.Target, msg.Content)
+
+ if msg.Target == "*" {
+ return s.broadcastMessage(conn, user, msg)
+ }
+
+ return nil
+}
+
+func (s *Server) broadcastMessage(conn net.Conn, user User, msg core.Message) error {
+ for _, u := range s.users {
+ if u.Name == user.Name {
+ continue
+ }
+
+ for c := range u.Conns {
+ if err := core.Send(c, msg); err != nil {
+ log.Println("cannot send", err)
+ }
+ }
+ }
+
+ // Forward message for other connections from the same user
+ for c := range s.users[user.Name].Conns {
+ if err := core.Send(c, msg); err != nil {
+ log.Println("cannot send", err)
+ }
+ }
+
+ return nil
+}
diff --git a/solec.ksy b/solec.ksy
index e7c24e1..dcfcc11 100644
--- a/solec.ksy
+++ b/solec.ksy
@@ -3,15 +3,13 @@ meta:
file-extension: hex
endian: be
-doc: |
- SOLEC protocol uses big endian encoding. Frames uses type-length-value format.
-
+doc: SOLEC protocol
doc-ref: https://git.sr.ht/~rctt/solec/blob/main/solec.svg
seq:
- id: type_payload
type: u1
- enum: type
+ enum: payload_type
- id: len_payload
type: u2
- id: payload
@@ -19,20 +17,25 @@ seq:
type:
switch-on: type_payload
cases:
- 'type::handshake': handshake
- 'type::ping': ping
- 'type::pong': pong
- 'type::message': message
- 'type::test': test
+ 'payload_type::success': success
+ 'payload_type::error': error
+ 'payload_type::handshake': handshake
+ 'payload_type::auth': auth
+ 'payload_type::message': message
+ 'payload_type::test': test
enums:
- type:
- 0x01: handshake
- 0x02: ping
- 0x03: pong
- 0x04: message
+ payload_type:
+ 0x01: success
+ 0x02: error
+ 0x03: handshake
+ 0x04: auth
+ 0x05: message
0xFF: test
+ error_type:
+ 0x01: auth_failed
+
types:
string:
doc: UTF-8 encoded string.
@@ -52,6 +55,16 @@ types:
- id: payload
size: len_payload
+ success:
+ doc: Send from server if operation succeded.
+
+ error:
+ doc: Senf from server if operation failed.
+ seq:
+ - id: error_code
+ type: u1
+ enum: error_type
+
handshake:
doc: |
Handshake is sent by the client during connection initialization.
@@ -63,16 +76,12 @@ types:
- id: proto_ver_minor
type: u1
- ping:
- doc: Ping does not contain any payload.
-
- pong:
+ auth:
seq:
- - id: timestamp
- doc: |
- Timestamp is set just before sending the pong message. It can be used
- to meassure packet's travel time between server and client.
- type: u8
+ - id: name
+ type: string
+ - id: pass
+ type: string
message:
doc: |
diff --git a/solec.lua b/solec.lua
index a06a429..85efaad 100644
--- a/solec.lua
+++ b/solec.lua
@@ -32,14 +32,14 @@ table.insert(proto.fields, Solec_String_len_payload)
local str_decode = require("string_decode")
local Solec_String_payload = ProtoField.new('payload', 'Solec.String.payload', ftypes.STRINGZ)
table.insert(proto.fields, Solec_String_payload)
+local Solec_Error_error_code = ProtoField.new('error_code', 'Solec.Error.error_code', ftypes.BYTES)
+table.insert(proto.fields, Solec_Error_error_code)
local Solec_Handshake_proto_ver_major = ProtoField.new('proto_ver_major', 'Solec.Handshake.proto_ver_major', ftypes.UINT8)
table.insert(proto.fields, Solec_Handshake_proto_ver_major)
local Solec_Handshake_proto_ver_minor = ProtoField.new('proto_ver_minor', 'Solec.Handshake.proto_ver_minor', ftypes.UINT8)
table.insert(proto.fields, Solec_Handshake_proto_ver_minor)
local Solec_Message_timestamp = ProtoField.new('timestamp', 'Solec.Message.timestamp', ftypes.UINT32)
table.insert(proto.fields, Solec_Message_timestamp)
-local Solec_Pong_timestamp = ProtoField.new('timestamp', 'Solec.Pong.timestamp', ftypes.UINT32)
-table.insert(proto.fields, Solec_Pong_timestamp)
function proto.dissector(tvb, pinfo, root)
pinfo.cols.protocol = 'Solec'
@@ -49,18 +49,23 @@ function proto.dissector(tvb, pinfo, root)
end
--
--- SOLEC protocol uses big endian encoding. Frames uses type-length-value format.
+-- SOLEC protocol.
-- See also: Source (https://git.sr.ht/~rctt/solec/blob/main/solec.svg)
Solec = class.class(KaitaiStruct)
-Solec.Type = enum.Enum {
- handshake = 1,
- ping = 2,
- pong = 3,
- message = 4,
+Solec.PayloadType = enum.Enum {
+ success = 1,
+ error = 2,
+ handshake = 3,
+ auth = 4,
+ message = 5,
test = 255,
}
+Solec.ErrorType = enum.Enum {
+ auth_failed = 1,
+}
+
function Solec:_init(io, tree, parent, root)
KaitaiStruct._init(self, io)
self._parent = parent
@@ -71,43 +76,49 @@ end
function Solec:_read()
local _offset = self._io:pos()
- self.type_payload = Solec.Type(self._io:read_u1())
+ self.type_payload = Solec.PayloadType(self._io:read_u1())
self._tree:add(Solec_type_payload, self._io._io.tvb(_offset, self._io:pos() - _offset))
local _offset = self._io:pos()
self.len_payload = self._io:read_u2be()
self._tree:add(Solec_len_payload, self._io._io.tvb(_offset, self._io:pos() - _offset), self.len_payload)
local _offset = self._io:pos()
local _on = self.type_payload
- if _on == Solec.Type.message then
+ if _on == Solec.PayloadType.auth then
self._raw_payload = self._io:read_bytes(self.len_payload)
local _tvb = self._io._io.tvb(_offset, self._io:pos() - _offset)
local _io = KaitaiStream(TVBStream(_tvb))
local _tree = self._tree:add(_tvb, 'payload')
- self.payload = Solec.Message(_io, _tree, self, self._root)
- elseif _on == Solec.Type.ping then
+ self.payload = Solec.Auth(_io, _tree, self, self._root)
+ elseif _on == Solec.PayloadType.handshake then
self._raw_payload = self._io:read_bytes(self.len_payload)
local _tvb = self._io._io.tvb(_offset, self._io:pos() - _offset)
local _io = KaitaiStream(TVBStream(_tvb))
local _tree = self._tree:add(_tvb, 'payload')
- self.payload = Solec.Ping(_io, _tree, self, self._root)
- elseif _on == Solec.Type.pong then
+ self.payload = Solec.Handshake(_io, _tree, self, self._root)
+ elseif _on == Solec.PayloadType.test then
self._raw_payload = self._io:read_bytes(self.len_payload)
local _tvb = self._io._io.tvb(_offset, self._io:pos() - _offset)
local _io = KaitaiStream(TVBStream(_tvb))
local _tree = self._tree:add(_tvb, 'payload')
- self.payload = Solec.Pong(_io, _tree, self, self._root)
- elseif _on == Solec.Type.test then
+ self.payload = Solec.Test(_io, _tree, self, self._root)
+ elseif _on == Solec.PayloadType.error then
self._raw_payload = self._io:read_bytes(self.len_payload)
local _tvb = self._io._io.tvb(_offset, self._io:pos() - _offset)
local _io = KaitaiStream(TVBStream(_tvb))
local _tree = self._tree:add(_tvb, 'payload')
- self.payload = Solec.Test(_io, _tree, self, self._root)
- elseif _on == Solec.Type.handshake then
+ self.payload = Solec.Error(_io, _tree, self, self._root)
+ elseif _on == Solec.PayloadType.success then
self._raw_payload = self._io:read_bytes(self.len_payload)
local _tvb = self._io._io.tvb(_offset, self._io:pos() - _offset)
local _io = KaitaiStream(TVBStream(_tvb))
local _tree = self._tree:add(_tvb, 'payload')
- self.payload = Solec.Handshake(_io, _tree, self, self._root)
+ self.payload = Solec.Success(_io, _tree, self, self._root)
+ elseif _on == Solec.PayloadType.message then
+ self._raw_payload = self._io:read_bytes(self.len_payload)
+ local _tvb = self._io._io.tvb(_offset, self._io:pos() - _offset)
+ local _io = KaitaiStream(TVBStream(_tvb))
+ local _tree = self._tree:add(_tvb, 'payload')
+ self.payload = Solec.Message(_io, _tree, self, self._root)
else
self.payload = self._io:read_bytes(self.len_payload)
end
@@ -158,6 +169,22 @@ end
--
+-- Send from server if operation succeded.
+Solec.Success = class.class(KaitaiStruct)
+
+function Solec.Success:_init(io, tree, parent, root)
+ KaitaiStruct._init(self, io)
+ self._parent = parent
+ self._root = root or self
+ self._tree = tree
+ self:_read()
+end
+
+function Solec.Success:_read()
+end
+
+
+--
-- Binary data of unspecifed type.
Solec.Binary = class.class(KaitaiStruct)
@@ -179,6 +206,28 @@ function Solec.Binary:_read()
end
+Solec.Auth = class.class(KaitaiStruct)
+
+function Solec.Auth:_init(io, tree, parent, root)
+ KaitaiStruct._init(self, io)
+ self._parent = parent
+ self._root = root or self
+ self._tree = tree
+ self:_read()
+end
+
+function Solec.Auth:_read()
+ local _offset = self._io:pos()
+ local _tree = self._tree:add(self._io._io.tvb(_offset, 0), 'name')
+ self.name = Solec.String(self._io, _tree, self, self._root)
+ _tree:set_len(self._io:pos() - _offset)
+ local _offset = self._io:pos()
+ local _tree = self._tree:add(self._io._io.tvb(_offset, 0), 'pass')
+ self.pass = Solec.String(self._io, _tree, self, self._root)
+ _tree:set_len(self._io:pos() - _offset)
+end
+
+
--
-- UTF-8 encoded string.
Solec.String = class.class(KaitaiStruct)
@@ -202,10 +251,10 @@ end
--
--- Ping does not contain any payload.
-Solec.Ping = class.class(KaitaiStruct)
+-- Senf from server if operation failed.
+Solec.Error = class.class(KaitaiStruct)
-function Solec.Ping:_init(io, tree, parent, root)
+function Solec.Error:_init(io, tree, parent, root)
KaitaiStruct._init(self, io)
self._parent = parent
self._root = root or self
@@ -213,7 +262,10 @@ function Solec.Ping:_init(io, tree, parent, root)
self:_read()
end
-function Solec.Ping:_read()
+function Solec.Error:_read()
+ local _offset = self._io:pos()
+ self.error_code = Solec.ErrorType(self._io:read_u1())
+ self._tree:add(Solec_Error_error_code, self._io._io.tvb(_offset, self._io:pos() - _offset), self.error_code)
end
@@ -274,25 +326,5 @@ end
--
-- Set just before sending the message.
-Solec.Pong = class.class(KaitaiStruct)
-
-function Solec.Pong:_init(io, tree, parent, root)
- KaitaiStruct._init(self, io)
- self._parent = parent
- self._root = root or self
- self._tree = tree
- self:_read()
-end
-
-function Solec.Pong:_read()
- local _offset = self._io:pos()
- self.timestamp = self._io:read_u8be()
- self._tree:add(Solec_Pong_timestamp, self._io._io.tvb(_offset, self._io:pos() - _offset), self.timestamp)
-end
-
---
--- Timestamp is set just before sending the pong message. It can be used
--- to meassure packet's travel time between server and client.
-
local tcp_port = DissectorTable.get("tcp.port")
tcp_port:add(9999, proto)
diff --git a/solec.svg b/solec.svg
index 63e66fe..40365b4 100644
--- a/solec.svg
+++ b/solec.svg
@@ -4,472 +4,531 @@
<!-- Generated by graphviz version 14.1.3 (20260303.0454)
-->
<!-- Pages: 1 -->
-<svg width="1053pt" height="796pt"
- viewBox="0.00 0.00 1053.00 796.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
-<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 792)">
-<polygon fill="white" stroke="none" points="-4,4 -4,-792 1049.25,-792 1049.25,4 -4,4"/>
+<svg width="1130pt" height="920pt"
+ viewBox="0.00 0.00 1130.00 920.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 916)">
+<polygon fill="white" stroke="none" points="-4,4 -4,-916 1125.75,-916 1125.75,4 -4,4"/>
<g id="clust1" class="cluster">
<title>cluster__solec</title>
-<polygon fill="none" stroke="black" stroke-dasharray="1,5" points="8,-8 8,-780 1037.25,-780 1037.25,-8 8,-8"/>
-<text xml:space="preserve" text-anchor="middle" x="522.62" y="-762.7" font-family="Times,serif" font-size="14.00">Solec</text>
+<polygon fill="none" stroke="black" stroke-dasharray="1,5" points="8,-8 8,-904 1113.75,-904 1113.75,-8 8,-8"/>
+<text xml:space="preserve" text-anchor="middle" x="560.88" y="-886.7" font-family="Times,serif" font-size="14.00">Solec</text>
</g>
<g id="clust2" class="cluster">
-<title>cluster__binary</title>
-<polygon fill="none" stroke="black" stroke-dasharray="1,5" points="779.75,-61 779.75,-195 1012.75,-195 1012.75,-61 779.75,-61"/>
-<text xml:space="preserve" text-anchor="middle" x="896.25" y="-177.7" font-family="Times,serif" font-size="14.00">Solec::Binary</text>
+<title>cluster__auth</title>
+<polygon fill="none" stroke="black" stroke-dasharray="1,5" points="621.25,-755 621.25,-871 780,-871 780,-755 621.25,-755"/>
+<text xml:space="preserve" text-anchor="middle" x="700.62" y="-853.7" font-family="Times,serif" font-size="14.00">Solec::Auth</text>
</g>
<g id="clust3" class="cluster">
-<title>cluster__handshake</title>
-<polygon fill="none" stroke="black" stroke-dasharray="1,5" points="532,-631 532,-747 743.25,-747 743.25,-631 532,-631"/>
-<text xml:space="preserve" text-anchor="middle" x="637.62" y="-729.7" font-family="Times,serif" font-size="14.00">Solec::Handshake</text>
+<title>cluster__binary</title>
+<polygon fill="none" stroke="black" stroke-dasharray="1,5" points="856.25,-61 856.25,-195 1089.25,-195 1089.25,-61 856.25,-61"/>
+<text xml:space="preserve" text-anchor="middle" x="972.75" y="-177.7" font-family="Times,serif" font-size="14.00">Solec::Binary</text>
</g>
<g id="clust4" class="cluster">
-<title>cluster__message</title>
-<polygon fill="none" stroke="black" stroke-dasharray="1,5" points="544.38,-462 544.38,-623 730.88,-623 730.88,-462 544.38,-462"/>
-<text xml:space="preserve" text-anchor="middle" x="637.62" y="-605.7" font-family="Times,serif" font-size="14.00">Solec::Message</text>
+<title>cluster__error</title>
+<polygon fill="none" stroke="black" stroke-dasharray="1,5" points="581.5,-653 581.5,-747 819.75,-747 819.75,-653 581.5,-653"/>
+<text xml:space="preserve" text-anchor="middle" x="700.62" y="-729.7" font-family="Times,serif" font-size="14.00">Solec::Error</text>
</g>
<g id="clust5" class="cluster">
-<title>cluster__ping</title>
-<polygon fill="none" stroke="black" stroke-dasharray="1,5" points="572.88,-377 572.88,-454 702.38,-454 702.38,-377 572.88,-377"/>
-<text xml:space="preserve" text-anchor="middle" x="637.62" y="-436.7" font-family="Times,serif" font-size="14.00">Solec::Ping</text>
+<title>cluster__handshake</title>
+<polygon fill="none" stroke="black" stroke-dasharray="1,5" points="595,-529 595,-645 806.25,-645 806.25,-529 595,-529"/>
+<text xml:space="preserve" text-anchor="middle" x="700.62" y="-627.7" font-family="Times,serif" font-size="14.00">Solec::Handshake</text>
</g>
<g id="clust6" class="cluster">
-<title>cluster__pong</title>
-<polygon fill="none" stroke="black" stroke-dasharray="1,5" points="547.75,-275 547.75,-369 727.5,-369 727.5,-275 547.75,-275"/>
-<text xml:space="preserve" text-anchor="middle" x="637.62" y="-351.7" font-family="Times,serif" font-size="14.00">Solec::Pong</text>
+<title>cluster__message</title>
+<polygon fill="none" stroke="black" stroke-dasharray="1,5" points="607.38,-360 607.38,-521 793.88,-521 793.88,-360 607.38,-360"/>
+<text xml:space="preserve" text-anchor="middle" x="700.62" y="-503.7" font-family="Times,serif" font-size="14.00">Solec::Message</text>
</g>
<g id="clust7" class="cluster">
<title>cluster__string</title>
-<polygon fill="none" stroke="black" stroke-dasharray="1,5" points="763.25,-439 763.25,-573 1029.25,-573 1029.25,-439 763.25,-439"/>
-<text xml:space="preserve" text-anchor="middle" x="896.25" y="-555.7" font-family="Times,serif" font-size="14.00">Solec::String</text>
+<polygon fill="none" stroke="black" stroke-dasharray="1,5" points="839.75,-382 839.75,-516 1105.75,-516 1105.75,-382 839.75,-382"/>
+<text xml:space="preserve" text-anchor="middle" x="972.75" y="-498.7" font-family="Times,serif" font-size="14.00">Solec::String</text>
</g>
<g id="clust8" class="cluster">
+<title>cluster__success</title>
+<polygon fill="none" stroke="black" stroke-dasharray="1,5" points="635.88,-275 635.88,-352 765.38,-352 765.38,-275 635.88,-275"/>
+<text xml:space="preserve" text-anchor="middle" x="700.62" y="-334.7" font-family="Times,serif" font-size="14.00">Solec::Success</text>
+</g>
+<g id="clust9" class="cluster">
<title>cluster__test</title>
-<polygon fill="none" stroke="black" stroke-dasharray="1,5" points="555.62,-16 555.62,-267 719.62,-267 719.62,-16 555.62,-16"/>
-<text xml:space="preserve" text-anchor="middle" x="637.62" y="-249.7" font-family="Times,serif" font-size="14.00">Solec::Test</text>
+<polygon fill="none" stroke="black" stroke-dasharray="1,5" points="618.62,-16 618.62,-267 782.62,-267 782.62,-16 618.62,-16"/>
+<text xml:space="preserve" text-anchor="middle" x="700.62" y="-249.7" font-family="Times,serif" font-size="14.00">Solec::Test</text>
</g>
<!-- solec__seq -->
<g id="node1" class="node">
<title>solec__seq</title>
-<polygon fill="#e0ffe0" stroke="none" points="24,-469.5 24,-492 48.75,-492 48.75,-469.5 24,-469.5"/>
-<polygon fill="none" stroke="black" points="24,-469.5 24,-492 48.75,-492 48.75,-469.5 24,-469.5"/>
-<text xml:space="preserve" text-anchor="start" x="27" y="-476.25" font-family="Times,serif" font-size="14.00">pos</text>
-<polygon fill="#e0ffe0" stroke="none" points="48.75,-469.5 48.75,-492 75.75,-492 75.75,-469.5 48.75,-469.5"/>
-<polygon fill="none" stroke="black" points="48.75,-469.5 48.75,-492 75.75,-492 75.75,-469.5 48.75,-469.5"/>
-<text xml:space="preserve" text-anchor="start" x="51.75" y="-476.25" font-family="Times,serif" font-size="14.00">size</text>
-<polygon fill="#e0ffe0" stroke="none" points="75.75,-469.5 75.75,-492 202.5,-492 202.5,-469.5 75.75,-469.5"/>
-<polygon fill="none" stroke="black" points="75.75,-469.5 75.75,-492 202.5,-492 202.5,-469.5 75.75,-469.5"/>
-<text xml:space="preserve" text-anchor="start" x="127.5" y="-476.25" font-family="Times,serif" font-size="14.00">type</text>
-<polygon fill="#e0ffe0" stroke="none" points="202.5,-469.5 202.5,-492 281.25,-492 281.25,-469.5 202.5,-469.5"/>
-<polygon fill="none" stroke="black" points="202.5,-469.5 202.5,-492 281.25,-492 281.25,-469.5 202.5,-469.5"/>
-<text xml:space="preserve" text-anchor="start" x="236.62" y="-476.25" font-family="Times,serif" font-size="14.00">id</text>
-<polygon fill="none" stroke="black" points="24,-447 24,-469.5 48.75,-469.5 48.75,-447 24,-447"/>
-<text xml:space="preserve" text-anchor="start" x="33" y="-453.75" font-family="Times,serif" font-size="14.00">0</text>
-<polygon fill="none" stroke="black" points="48.75,-447 48.75,-469.5 75.75,-469.5 75.75,-447 48.75,-447"/>
-<text xml:space="preserve" text-anchor="start" x="58.88" y="-453.75" font-family="Times,serif" font-size="14.00">1</text>
-<polygon fill="none" stroke="black" points="75.75,-447 75.75,-469.5 202.5,-469.5 202.5,-447 75.75,-447"/>
-<text xml:space="preserve" text-anchor="start" x="111.38" y="-453.75" font-family="Times,serif" font-size="14.00">u1→Type</text>
-<polygon fill="none" stroke="black" points="202.5,-447 202.5,-469.5 281.25,-469.5 281.25,-447 202.5,-447"/>
-<text xml:space="preserve" text-anchor="start" x="205.5" y="-453.75" font-family="Times,serif" font-size="14.00">type_payload</text>
-<polygon fill="none" stroke="black" points="24,-424.5 24,-447 48.75,-447 48.75,-424.5 24,-424.5"/>
-<text xml:space="preserve" text-anchor="start" x="33" y="-431.25" font-family="Times,serif" font-size="14.00">1</text>
-<polygon fill="none" stroke="black" points="48.75,-424.5 48.75,-447 75.75,-447 75.75,-424.5 48.75,-424.5"/>
-<text xml:space="preserve" text-anchor="start" x="58.88" y="-431.25" font-family="Times,serif" font-size="14.00">2</text>
-<polygon fill="none" stroke="black" points="75.75,-424.5 75.75,-447 202.5,-447 202.5,-424.5 75.75,-424.5"/>
-<text xml:space="preserve" text-anchor="start" x="126" y="-431.25" font-family="Times,serif" font-size="14.00">u2be</text>
-<polygon fill="none" stroke="black" points="202.5,-424.5 202.5,-447 281.25,-447 281.25,-424.5 202.5,-424.5"/>
-<text xml:space="preserve" text-anchor="start" x="208.88" y="-431.25" font-family="Times,serif" font-size="14.00">len_payload</text>
-<polygon fill="none" stroke="black" points="24,-402 24,-424.5 48.75,-424.5 48.75,-402 24,-402"/>
-<text xml:space="preserve" text-anchor="start" x="33" y="-408.75" font-family="Times,serif" font-size="14.00">3</text>
-<polygon fill="none" stroke="black" points="48.75,-402 48.75,-424.5 75.75,-424.5 75.75,-402 48.75,-402"/>
-<text xml:space="preserve" text-anchor="start" x="56.62" y="-408.75" font-family="Times,serif" font-size="14.00">...</text>
-<polygon fill="none" stroke="black" points="75.75,-402 75.75,-424.5 202.5,-424.5 202.5,-402 75.75,-402"/>
-<text xml:space="preserve" text-anchor="start" x="78.75" y="-408.75" font-family="Times,serif" font-size="14.00">switch (type_payload)</text>
-<polygon fill="none" stroke="black" points="202.5,-402 202.5,-424.5 281.25,-424.5 281.25,-402 202.5,-402"/>
-<text xml:space="preserve" text-anchor="start" x="220.5" y="-408.75" font-family="Times,serif" font-size="14.00">payload</text>
+<polygon fill="#e0ffe0" stroke="none" points="24,-567.5 24,-590 48.75,-590 48.75,-567.5 24,-567.5"/>
+<polygon fill="none" stroke="black" points="24,-567.5 24,-590 48.75,-590 48.75,-567.5 24,-567.5"/>
+<text xml:space="preserve" text-anchor="start" x="27" y="-574.25" font-family="Times,serif" font-size="14.00">pos</text>
+<polygon fill="#e0ffe0" stroke="none" points="48.75,-567.5 48.75,-590 75.75,-590 75.75,-567.5 48.75,-567.5"/>
+<polygon fill="none" stroke="black" points="48.75,-567.5 48.75,-590 75.75,-590 75.75,-567.5 48.75,-567.5"/>
+<text xml:space="preserve" text-anchor="start" x="51.75" y="-574.25" font-family="Times,serif" font-size="14.00">size</text>
+<polygon fill="#e0ffe0" stroke="none" points="75.75,-567.5 75.75,-590 202.5,-590 202.5,-567.5 75.75,-567.5"/>
+<polygon fill="none" stroke="black" points="75.75,-567.5 75.75,-590 202.5,-590 202.5,-567.5 75.75,-567.5"/>
+<text xml:space="preserve" text-anchor="start" x="127.5" y="-574.25" font-family="Times,serif" font-size="14.00">type</text>
+<polygon fill="#e0ffe0" stroke="none" points="202.5,-567.5 202.5,-590 281.25,-590 281.25,-567.5 202.5,-567.5"/>
+<polygon fill="none" stroke="black" points="202.5,-567.5 202.5,-590 281.25,-590 281.25,-567.5 202.5,-567.5"/>
+<text xml:space="preserve" text-anchor="start" x="236.62" y="-574.25" font-family="Times,serif" font-size="14.00">id</text>
+<polygon fill="none" stroke="black" points="24,-545 24,-567.5 48.75,-567.5 48.75,-545 24,-545"/>
+<text xml:space="preserve" text-anchor="start" x="33" y="-551.75" font-family="Times,serif" font-size="14.00">0</text>
+<polygon fill="none" stroke="black" points="48.75,-545 48.75,-567.5 75.75,-567.5 75.75,-545 48.75,-545"/>
+<text xml:space="preserve" text-anchor="start" x="58.88" y="-551.75" font-family="Times,serif" font-size="14.00">1</text>
+<polygon fill="none" stroke="black" points="75.75,-545 75.75,-567.5 202.5,-567.5 202.5,-545 75.75,-545"/>
+<text xml:space="preserve" text-anchor="start" x="89.62" y="-551.75" font-family="Times,serif" font-size="14.00">u1→PayloadType</text>
+<polygon fill="none" stroke="black" points="202.5,-545 202.5,-567.5 281.25,-567.5 281.25,-545 202.5,-545"/>
+<text xml:space="preserve" text-anchor="start" x="205.5" y="-551.75" font-family="Times,serif" font-size="14.00">type_payload</text>
+<polygon fill="none" stroke="black" points="24,-522.5 24,-545 48.75,-545 48.75,-522.5 24,-522.5"/>
+<text xml:space="preserve" text-anchor="start" x="33" y="-529.25" font-family="Times,serif" font-size="14.00">1</text>
+<polygon fill="none" stroke="black" points="48.75,-522.5 48.75,-545 75.75,-545 75.75,-522.5 48.75,-522.5"/>
+<text xml:space="preserve" text-anchor="start" x="58.88" y="-529.25" font-family="Times,serif" font-size="14.00">2</text>
+<polygon fill="none" stroke="black" points="75.75,-522.5 75.75,-545 202.5,-545 202.5,-522.5 75.75,-522.5"/>
+<text xml:space="preserve" text-anchor="start" x="126" y="-529.25" font-family="Times,serif" font-size="14.00">u2be</text>
+<polygon fill="none" stroke="black" points="202.5,-522.5 202.5,-545 281.25,-545 281.25,-522.5 202.5,-522.5"/>
+<text xml:space="preserve" text-anchor="start" x="208.88" y="-529.25" font-family="Times,serif" font-size="14.00">len_payload</text>
+<polygon fill="none" stroke="black" points="24,-500 24,-522.5 48.75,-522.5 48.75,-500 24,-500"/>
+<text xml:space="preserve" text-anchor="start" x="33" y="-506.75" font-family="Times,serif" font-size="14.00">3</text>
+<polygon fill="none" stroke="black" points="48.75,-500 48.75,-522.5 75.75,-522.5 75.75,-500 48.75,-500"/>
+<text xml:space="preserve" text-anchor="start" x="56.62" y="-506.75" font-family="Times,serif" font-size="14.00">...</text>
+<polygon fill="none" stroke="black" points="75.75,-500 75.75,-522.5 202.5,-522.5 202.5,-500 75.75,-500"/>
+<text xml:space="preserve" text-anchor="start" x="78.75" y="-506.75" font-family="Times,serif" font-size="14.00">switch (type_payload)</text>
+<polygon fill="none" stroke="black" points="202.5,-500 202.5,-522.5 281.25,-522.5 281.25,-500 202.5,-500"/>
+<text xml:space="preserve" text-anchor="start" x="220.5" y="-506.75" font-family="Times,serif" font-size="14.00">payload</text>
</g>
<!-- solec__seq&#45;&gt;solec__seq -->
-<g id="edge7" class="edge">
+<g id="edge8" class="edge">
<title>solec__seq:type_payload_type&#45;&gt;solec__seq:payload_type</title>
-<path fill="none" stroke="#404040" d="M215.97,-469.36C177.97,-490.21 186.61,-514 241.88,-514 294.7,-514 304.92,-463 272.55,-431.55"/>
-<polygon fill="#404040" stroke="#404040" points="275.03,-429.06 265.1,-425.36 270.56,-434.44 275.03,-429.06"/>
+<path fill="none" stroke="#404040" d="M213.52,-567.36C171.94,-588.21 181.39,-612 241.88,-612 299.93,-612 310.97,-560.57 274.99,-529.15"/>
+<polygon fill="#404040" stroke="#404040" points="277.33,-526.52 267.23,-523.3 273.12,-532.12 277.33,-526.52"/>
</g>
<!-- solec__seq_payload_switch -->
<g id="node2" class="node">
<title>solec__seq_payload_switch</title>
-<polygon fill="#f0f2e4" stroke="none" points="333.25,-459 333.25,-481.5 430,-481.5 430,-459 333.25,-459"/>
-<polygon fill="none" stroke="black" points="333.25,-459 333.25,-481.5 430,-481.5 430,-459 333.25,-459"/>
-<text xml:space="preserve" text-anchor="start" x="370" y="-465.75" font-family="Times,serif" font-size="14.00">case</text>
-<polygon fill="#f0f2e4" stroke="none" points="430,-459 430,-481.5 496,-481.5 496,-459 430,-459"/>
-<polygon fill="none" stroke="black" points="430,-459 430,-481.5 496,-481.5 496,-459 430,-459"/>
-<text xml:space="preserve" text-anchor="start" x="451.38" y="-465.75" font-family="Times,serif" font-size="14.00">type</text>
-<polygon fill="none" stroke="black" points="333.25,-436.5 333.25,-459 430,-459 430,-436.5 333.25,-436.5"/>
-<text xml:space="preserve" text-anchor="start" x="336.25" y="-443.25" font-family="Times,serif" font-size="14.00">:type_handshake</text>
-<polygon fill="none" stroke="black" points="430,-436.5 430,-459 496,-459 496,-436.5 430,-436.5"/>
-<text xml:space="preserve" text-anchor="start" x="433" y="-443.25" font-family="Times,serif" font-size="14.00">Handshake</text>
-<polygon fill="none" stroke="black" points="333.25,-414 333.25,-436.5 430,-436.5 430,-414 333.25,-414"/>
-<text xml:space="preserve" text-anchor="start" x="341.5" y="-420.75" font-family="Times,serif" font-size="14.00">:type_message</text>
-<polygon fill="none" stroke="black" points="430,-414 430,-436.5 496,-436.5 496,-414 430,-414"/>
-<text xml:space="preserve" text-anchor="start" x="439" y="-420.75" font-family="Times,serif" font-size="14.00">Message</text>
-<polygon fill="none" stroke="black" points="333.25,-391.5 333.25,-414 430,-414 430,-391.5 333.25,-391.5"/>
-<text xml:space="preserve" text-anchor="start" x="352.75" y="-398.25" font-family="Times,serif" font-size="14.00">:type_ping</text>
-<polygon fill="none" stroke="black" points="430,-391.5 430,-414 496,-414 496,-391.5 430,-391.5"/>
-<text xml:space="preserve" text-anchor="start" x="450.62" y="-398.25" font-family="Times,serif" font-size="14.00">Ping</text>
-<polygon fill="none" stroke="black" points="333.25,-369 333.25,-391.5 430,-391.5 430,-369 333.25,-369"/>
-<text xml:space="preserve" text-anchor="start" x="351.25" y="-375.75" font-family="Times,serif" font-size="14.00">:type_pong</text>
-<polygon fill="none" stroke="black" points="430,-369 430,-391.5 496,-391.5 496,-369 430,-369"/>
-<text xml:space="preserve" text-anchor="start" x="449.12" y="-375.75" font-family="Times,serif" font-size="14.00">Pong</text>
-<polygon fill="none" stroke="black" points="333.25,-346.5 333.25,-369 430,-369 430,-346.5 333.25,-346.5"/>
-<text xml:space="preserve" text-anchor="start" x="355.38" y="-353.25" font-family="Times,serif" font-size="14.00">:type_test</text>
-<polygon fill="none" stroke="black" points="430,-346.5 430,-369 496,-369 496,-346.5 430,-346.5"/>
-<text xml:space="preserve" text-anchor="start" x="451.38" y="-353.25" font-family="Times,serif" font-size="14.00">Test</text>
+<polygon fill="#f0f2e4" stroke="none" points="333.25,-568.25 333.25,-590.75 479.5,-590.75 479.5,-568.25 333.25,-568.25"/>
+<polygon fill="none" stroke="black" points="333.25,-568.25 333.25,-590.75 479.5,-590.75 479.5,-568.25 333.25,-568.25"/>
+<text xml:space="preserve" text-anchor="start" x="394.75" y="-575" font-family="Times,serif" font-size="14.00">case</text>
+<polygon fill="#f0f2e4" stroke="none" points="479.5,-568.25 479.5,-590.75 545.5,-590.75 545.5,-568.25 479.5,-568.25"/>
+<polygon fill="none" stroke="black" points="479.5,-568.25 479.5,-590.75 545.5,-590.75 545.5,-568.25 479.5,-568.25"/>
+<text xml:space="preserve" text-anchor="start" x="500.88" y="-575" font-family="Times,serif" font-size="14.00">type</text>
+<polygon fill="none" stroke="black" points="333.25,-545.75 333.25,-568.25 479.5,-568.25 479.5,-545.75 333.25,-545.75"/>
+<text xml:space="preserve" text-anchor="start" x="353.12" y="-552.5" font-family="Times,serif" font-size="14.00">:payload_type_auth</text>
+<polygon fill="none" stroke="black" points="479.5,-545.75 479.5,-568.25 545.5,-568.25 545.5,-545.75 479.5,-545.75"/>
+<text xml:space="preserve" text-anchor="start" x="499" y="-552.5" font-family="Times,serif" font-size="14.00">Auth</text>
+<polygon fill="none" stroke="black" points="333.25,-523.25 333.25,-545.75 479.5,-545.75 479.5,-523.25 333.25,-523.25"/>
+<text xml:space="preserve" text-anchor="start" x="351.62" y="-530" font-family="Times,serif" font-size="14.00">:payload_type_error</text>
+<polygon fill="none" stroke="black" points="479.5,-523.25 479.5,-545.75 545.5,-545.75 545.5,-523.25 479.5,-523.25"/>
+<text xml:space="preserve" text-anchor="start" x="498.25" y="-530" font-family="Times,serif" font-size="14.00">Error</text>
+<polygon fill="none" stroke="black" points="333.25,-500.75 333.25,-523.25 479.5,-523.25 479.5,-500.75 333.25,-500.75"/>
+<text xml:space="preserve" text-anchor="start" x="336.25" y="-507.5" font-family="Times,serif" font-size="14.00">:payload_type_handshake</text>
+<polygon fill="none" stroke="black" points="479.5,-500.75 479.5,-523.25 545.5,-523.25 545.5,-500.75 479.5,-500.75"/>
+<text xml:space="preserve" text-anchor="start" x="482.5" y="-507.5" font-family="Times,serif" font-size="14.00">Handshake</text>
+<polygon fill="none" stroke="black" points="333.25,-478.25 333.25,-500.75 479.5,-500.75 479.5,-478.25 333.25,-478.25"/>
+<text xml:space="preserve" text-anchor="start" x="341.5" y="-485" font-family="Times,serif" font-size="14.00">:payload_type_message</text>
+<polygon fill="none" stroke="black" points="479.5,-478.25 479.5,-500.75 545.5,-500.75 545.5,-478.25 479.5,-478.25"/>
+<text xml:space="preserve" text-anchor="start" x="488.5" y="-485" font-family="Times,serif" font-size="14.00">Message</text>
+<polygon fill="none" stroke="black" points="333.25,-455.75 333.25,-478.25 479.5,-478.25 479.5,-455.75 333.25,-455.75"/>
+<text xml:space="preserve" text-anchor="start" x="344.5" y="-462.5" font-family="Times,serif" font-size="14.00">:payload_type_success</text>
+<polygon fill="none" stroke="black" points="479.5,-455.75 479.5,-478.25 545.5,-478.25 545.5,-455.75 479.5,-455.75"/>
+<text xml:space="preserve" text-anchor="start" x="491.12" y="-462.5" font-family="Times,serif" font-size="14.00">Success</text>
+<polygon fill="none" stroke="black" points="333.25,-433.25 333.25,-455.75 479.5,-455.75 479.5,-433.25 333.25,-433.25"/>
+<text xml:space="preserve" text-anchor="start" x="355.38" y="-440" font-family="Times,serif" font-size="14.00">:payload_type_test</text>
+<polygon fill="none" stroke="black" points="479.5,-433.25 479.5,-455.75 545.5,-455.75 545.5,-433.25 479.5,-433.25"/>
+<text xml:space="preserve" text-anchor="start" x="500.88" y="-440" font-family="Times,serif" font-size="14.00">Test</text>
</g>
<!-- solec__seq&#45;&gt;solec__seq_payload_switch -->
<g id="edge1" class="edge">
<title>solec__seq:payload_type&#45;&gt;solec__seq_payload_switch</title>
-<path fill="none" stroke="black" stroke-width="2" d="M282.25,-413.25C292.58,-413.25 303.36,-413.27 314.11,-413.31"/>
-<polygon fill="black" stroke="black" stroke-width="2" points="312.25,-416.8 322.26,-413.35 312.28,-409.8 312.25,-416.8"/>
+<path fill="none" stroke="black" stroke-width="2" d="M282.25,-511.25C292.61,-511.25 303.36,-511.27 314.14,-511.3"/>
+<polygon fill="black" stroke="black" stroke-width="2" points="312.35,-514.79 322.36,-511.32 312.37,-507.79 312.35,-514.79"/>
</g>
-<!-- handshake__seq -->
-<g id="node4" class="node">
-<title>handshake__seq</title>
-<polygon fill="#e0ffe0" stroke="none" points="548,-688.25 548,-710.75 572.75,-710.75 572.75,-688.25 548,-688.25"/>
-<polygon fill="none" stroke="black" points="548,-688.25 548,-710.75 572.75,-710.75 572.75,-688.25 548,-688.25"/>
-<text xml:space="preserve" text-anchor="start" x="551" y="-695" font-family="Times,serif" font-size="14.00">pos</text>
-<polygon fill="#e0ffe0" stroke="none" points="572.75,-688.25 572.75,-710.75 599.75,-710.75 599.75,-688.25 572.75,-688.25"/>
-<polygon fill="none" stroke="black" points="572.75,-688.25 572.75,-710.75 599.75,-710.75 599.75,-688.25 572.75,-688.25"/>
-<text xml:space="preserve" text-anchor="start" x="575.75" y="-695" font-family="Times,serif" font-size="14.00">size</text>
-<polygon fill="#e0ffe0" stroke="none" points="599.75,-688.25 599.75,-710.75 629,-710.75 629,-688.25 599.75,-688.25"/>
-<polygon fill="none" stroke="black" points="599.75,-688.25 599.75,-710.75 629,-710.75 629,-688.25 599.75,-688.25"/>
-<text xml:space="preserve" text-anchor="start" x="602.75" y="-695" font-family="Times,serif" font-size="14.00">type</text>
-<polygon fill="#e0ffe0" stroke="none" points="629,-688.25 629,-710.75 727.25,-710.75 727.25,-688.25 629,-688.25"/>
-<polygon fill="none" stroke="black" points="629,-688.25 629,-710.75 727.25,-710.75 727.25,-688.25 629,-688.25"/>
-<text xml:space="preserve" text-anchor="start" x="672.88" y="-695" font-family="Times,serif" font-size="14.00">id</text>
-<polygon fill="none" stroke="black" points="548,-665.75 548,-688.25 572.75,-688.25 572.75,-665.75 548,-665.75"/>
-<text xml:space="preserve" text-anchor="start" x="557" y="-672.5" font-family="Times,serif" font-size="14.00">0</text>
-<polygon fill="none" stroke="black" points="572.75,-665.75 572.75,-688.25 599.75,-688.25 599.75,-665.75 572.75,-665.75"/>
-<text xml:space="preserve" text-anchor="start" x="582.88" y="-672.5" font-family="Times,serif" font-size="14.00">1</text>
-<polygon fill="none" stroke="black" points="599.75,-665.75 599.75,-688.25 629,-688.25 629,-665.75 599.75,-665.75"/>
-<text xml:space="preserve" text-anchor="start" x="607.62" y="-672.5" font-family="Times,serif" font-size="14.00">u1</text>
-<polygon fill="none" stroke="black" points="629,-665.75 629,-688.25 727.25,-688.25 727.25,-665.75 629,-665.75"/>
-<text xml:space="preserve" text-anchor="start" x="632.38" y="-672.5" font-family="Times,serif" font-size="14.00">proto_ver_major</text>
-<polygon fill="none" stroke="black" points="548,-643.25 548,-665.75 572.75,-665.75 572.75,-643.25 548,-643.25"/>
-<text xml:space="preserve" text-anchor="start" x="557" y="-650" font-family="Times,serif" font-size="14.00">1</text>
-<polygon fill="none" stroke="black" points="572.75,-643.25 572.75,-665.75 599.75,-665.75 599.75,-643.25 572.75,-643.25"/>
-<text xml:space="preserve" text-anchor="start" x="582.88" y="-650" font-family="Times,serif" font-size="14.00">1</text>
-<polygon fill="none" stroke="black" points="599.75,-643.25 599.75,-665.75 629,-665.75 629,-643.25 599.75,-643.25"/>
-<text xml:space="preserve" text-anchor="start" x="607.62" y="-650" font-family="Times,serif" font-size="14.00">u1</text>
-<polygon fill="none" stroke="black" points="629,-643.25 629,-665.75 727.25,-665.75 727.25,-643.25 629,-643.25"/>
-<text xml:space="preserve" text-anchor="start" x="632" y="-650" font-family="Times,serif" font-size="14.00">proto_ver_minor</text>
-</g>
-<!-- solec__seq_payload_switch&#45;&gt;handshake__seq -->
+<!-- auth__seq -->
+<g id="node3" class="node">
+<title>auth__seq</title>
+<polygon fill="#e0ffe0" stroke="none" points="637.25,-812.25 637.25,-834.75 662,-834.75 662,-812.25 637.25,-812.25"/>
+<polygon fill="none" stroke="black" points="637.25,-812.25 637.25,-834.75 662,-834.75 662,-812.25 637.25,-812.25"/>
+<text xml:space="preserve" text-anchor="start" x="640.25" y="-819" font-family="Times,serif" font-size="14.00">pos</text>
+<polygon fill="#e0ffe0" stroke="none" points="662,-812.25 662,-834.75 689,-834.75 689,-812.25 662,-812.25"/>
+<polygon fill="none" stroke="black" points="662,-812.25 662,-834.75 689,-834.75 689,-812.25 662,-812.25"/>
+<text xml:space="preserve" text-anchor="start" x="665" y="-819" font-family="Times,serif" font-size="14.00">size</text>
+<polygon fill="#e0ffe0" stroke="none" points="689,-812.25 689,-834.75 728,-834.75 728,-812.25 689,-812.25"/>
+<polygon fill="none" stroke="black" points="689,-812.25 689,-834.75 728,-834.75 728,-812.25 689,-812.25"/>
+<text xml:space="preserve" text-anchor="start" x="696.88" y="-819" font-family="Times,serif" font-size="14.00">type</text>
+<polygon fill="#e0ffe0" stroke="none" points="728,-812.25 728,-834.75 764,-834.75 764,-812.25 728,-812.25"/>
+<polygon fill="none" stroke="black" points="728,-812.25 728,-834.75 764,-834.75 764,-812.25 728,-812.25"/>
+<text xml:space="preserve" text-anchor="start" x="740.75" y="-819" font-family="Times,serif" font-size="14.00">id</text>
+<polygon fill="none" stroke="black" points="637.25,-789.75 637.25,-812.25 662,-812.25 662,-789.75 637.25,-789.75"/>
+<text xml:space="preserve" text-anchor="start" x="646.25" y="-796.5" font-family="Times,serif" font-size="14.00">0</text>
+<polygon fill="none" stroke="black" points="662,-789.75 662,-812.25 689,-812.25 689,-789.75 662,-789.75"/>
+<text xml:space="preserve" text-anchor="start" x="669.88" y="-796.5" font-family="Times,serif" font-size="14.00">...</text>
+<polygon fill="none" stroke="black" points="689,-789.75 689,-812.25 728,-812.25 728,-789.75 689,-789.75"/>
+<text xml:space="preserve" text-anchor="start" x="692" y="-796.5" font-family="Times,serif" font-size="14.00">String</text>
+<polygon fill="none" stroke="black" points="728,-789.75 728,-812.25 764,-812.25 764,-789.75 728,-789.75"/>
+<text xml:space="preserve" text-anchor="start" x="731" y="-796.5" font-family="Times,serif" font-size="14.00">name</text>
+<polygon fill="none" stroke="black" points="637.25,-767.25 637.25,-789.75 662,-789.75 662,-767.25 637.25,-767.25"/>
+<text xml:space="preserve" text-anchor="start" x="644" y="-774" font-family="Times,serif" font-size="14.00">...</text>
+<polygon fill="none" stroke="black" points="662,-767.25 662,-789.75 689,-789.75 689,-767.25 662,-767.25"/>
+<text xml:space="preserve" text-anchor="start" x="669.88" y="-774" font-family="Times,serif" font-size="14.00">...</text>
+<polygon fill="none" stroke="black" points="689,-767.25 689,-789.75 728,-789.75 728,-767.25 689,-767.25"/>
+<text xml:space="preserve" text-anchor="start" x="692" y="-774" font-family="Times,serif" font-size="14.00">String</text>
+<polygon fill="none" stroke="black" points="728,-767.25 728,-789.75 764,-789.75 764,-767.25 728,-767.25"/>
+<text xml:space="preserve" text-anchor="start" x="734.38" y="-774" font-family="Times,serif" font-size="14.00">pass</text>
+</g>
+<!-- solec__seq_payload_switch&#45;&gt;auth__seq -->
<g id="edge2" class="edge">
-<title>solec__seq_payload_switch:case0&#45;&gt;handshake__seq</title>
-<path fill="none" stroke="black" stroke-width="2" d="M497,-447.75C578.17,-447.75 482.3,-562.82 532,-627 533.19,-628.53 534.43,-630.02 535.73,-631.46"/>
-<polygon fill="black" stroke="black" stroke-width="2" points="531.94,-632.65 541.53,-637.15 536.84,-627.65 531.94,-632.65"/>
+<title>solec__seq_payload_switch:case0&#45;&gt;auth__seq</title>
+<path fill="none" stroke="black" stroke-width="2" d="M546.5,-557C590.31,-557 554.14,-716.78 581.5,-751 591.29,-763.25 604.63,-772.54 618.83,-779.58"/>
+<polygon fill="black" stroke="black" stroke-width="2" points="615.97,-782.12 626.52,-783.06 618.86,-775.75 615.97,-782.12"/>
</g>
-<!-- message__seq -->
+<!-- error__seq -->
<g id="node5" class="node">
-<title>message__seq</title>
-<polygon fill="#e0ffe0" stroke="none" points="560.38,-563.75 560.38,-586.25 585.12,-586.25 585.12,-563.75 560.38,-563.75"/>
-<polygon fill="none" stroke="black" points="560.38,-563.75 560.38,-586.25 585.12,-586.25 585.12,-563.75 560.38,-563.75"/>
-<text xml:space="preserve" text-anchor="start" x="563.38" y="-570.5" font-family="Times,serif" font-size="14.00">pos</text>
-<polygon fill="#e0ffe0" stroke="none" points="585.12,-563.75 585.12,-586.25 612.12,-586.25 612.12,-563.75 585.12,-563.75"/>
-<polygon fill="none" stroke="black" points="585.12,-563.75 585.12,-586.25 612.12,-586.25 612.12,-563.75 585.12,-563.75"/>
-<text xml:space="preserve" text-anchor="start" x="588.12" y="-570.5" font-family="Times,serif" font-size="14.00">size</text>
-<polygon fill="#e0ffe0" stroke="none" points="612.12,-563.75 612.12,-586.25 651.12,-586.25 651.12,-563.75 612.12,-563.75"/>
-<polygon fill="none" stroke="black" points="612.12,-563.75 612.12,-586.25 651.12,-586.25 651.12,-563.75 612.12,-563.75"/>
-<text xml:space="preserve" text-anchor="start" x="620" y="-570.5" font-family="Times,serif" font-size="14.00">type</text>
-<polygon fill="#e0ffe0" stroke="none" points="651.12,-563.75 651.12,-586.25 714.88,-586.25 714.88,-563.75 651.12,-563.75"/>
-<polygon fill="none" stroke="black" points="651.12,-563.75 651.12,-586.25 714.88,-586.25 714.88,-563.75 651.12,-563.75"/>
-<text xml:space="preserve" text-anchor="start" x="677.75" y="-570.5" font-family="Times,serif" font-size="14.00">id</text>
-<polygon fill="none" stroke="black" points="560.38,-541.25 560.38,-563.75 585.12,-563.75 585.12,-541.25 560.38,-541.25"/>
-<text xml:space="preserve" text-anchor="start" x="569.38" y="-548" font-family="Times,serif" font-size="14.00">0</text>
-<polygon fill="none" stroke="black" points="585.12,-541.25 585.12,-563.75 612.12,-563.75 612.12,-541.25 585.12,-541.25"/>
-<text xml:space="preserve" text-anchor="start" x="593" y="-548" font-family="Times,serif" font-size="14.00">...</text>
-<polygon fill="none" stroke="black" points="612.12,-541.25 612.12,-563.75 651.12,-563.75 651.12,-541.25 612.12,-541.25"/>
-<text xml:space="preserve" text-anchor="start" x="615.12" y="-548" font-family="Times,serif" font-size="14.00">String</text>
-<polygon fill="none" stroke="black" points="651.12,-541.25 651.12,-563.75 714.88,-563.75 714.88,-541.25 651.12,-541.25"/>
-<text xml:space="preserve" text-anchor="start" x="665.38" y="-548" font-family="Times,serif" font-size="14.00">source</text>
-<polygon fill="none" stroke="black" points="560.38,-518.75 560.38,-541.25 585.12,-541.25 585.12,-518.75 560.38,-518.75"/>
-<text xml:space="preserve" text-anchor="start" x="567.12" y="-525.5" font-family="Times,serif" font-size="14.00">...</text>
-<polygon fill="none" stroke="black" points="585.12,-518.75 585.12,-541.25 612.12,-541.25 612.12,-518.75 585.12,-518.75"/>
-<text xml:space="preserve" text-anchor="start" x="593" y="-525.5" font-family="Times,serif" font-size="14.00">...</text>
-<polygon fill="none" stroke="black" points="612.12,-518.75 612.12,-541.25 651.12,-541.25 651.12,-518.75 612.12,-518.75"/>
-<text xml:space="preserve" text-anchor="start" x="615.12" y="-525.5" font-family="Times,serif" font-size="14.00">String</text>
-<polygon fill="none" stroke="black" points="651.12,-518.75 651.12,-541.25 714.88,-541.25 714.88,-518.75 651.12,-518.75"/>
-<text xml:space="preserve" text-anchor="start" x="667.62" y="-525.5" font-family="Times,serif" font-size="14.00">target</text>
-<polygon fill="none" stroke="black" points="560.38,-496.25 560.38,-518.75 585.12,-518.75 585.12,-496.25 560.38,-496.25"/>
-<text xml:space="preserve" text-anchor="start" x="567.12" y="-503" font-family="Times,serif" font-size="14.00">...</text>
-<polygon fill="none" stroke="black" points="585.12,-496.25 585.12,-518.75 612.12,-518.75 612.12,-496.25 585.12,-496.25"/>
-<text xml:space="preserve" text-anchor="start" x="595.25" y="-503" font-family="Times,serif" font-size="14.00">8</text>
-<polygon fill="none" stroke="black" points="612.12,-496.25 612.12,-518.75 651.12,-518.75 651.12,-496.25 612.12,-496.25"/>
-<text xml:space="preserve" text-anchor="start" x="618.5" y="-503" font-family="Times,serif" font-size="14.00">u8be</text>
-<polygon fill="none" stroke="black" points="651.12,-496.25 651.12,-518.75 714.88,-518.75 714.88,-496.25 651.12,-496.25"/>
-<text xml:space="preserve" text-anchor="start" x="654.12" y="-503" font-family="Times,serif" font-size="14.00">timestamp</text>
-<polygon fill="none" stroke="black" points="560.38,-473.75 560.38,-496.25 585.12,-496.25 585.12,-473.75 560.38,-473.75"/>
-<text xml:space="preserve" text-anchor="start" x="567.12" y="-480.5" font-family="Times,serif" font-size="14.00">...</text>
-<polygon fill="none" stroke="black" points="585.12,-473.75 585.12,-496.25 612.12,-496.25 612.12,-473.75 585.12,-473.75"/>
-<text xml:space="preserve" text-anchor="start" x="593" y="-480.5" font-family="Times,serif" font-size="14.00">...</text>
-<polygon fill="none" stroke="black" points="612.12,-473.75 612.12,-496.25 651.12,-496.25 651.12,-473.75 612.12,-473.75"/>
-<text xml:space="preserve" text-anchor="start" x="615.12" y="-480.5" font-family="Times,serif" font-size="14.00">String</text>
-<polygon fill="none" stroke="black" points="651.12,-473.75 651.12,-496.25 714.88,-496.25 714.88,-473.75 651.12,-473.75"/>
-<text xml:space="preserve" text-anchor="start" x="663.12" y="-480.5" font-family="Times,serif" font-size="14.00">content</text>
-</g>
-<!-- solec__seq_payload_switch&#45;&gt;message__seq -->
+<title>error__seq</title>
+<polygon fill="#e0ffe0" stroke="none" points="597.5,-688 597.5,-710.5 622.25,-710.5 622.25,-688 597.5,-688"/>
+<polygon fill="none" stroke="black" points="597.5,-688 597.5,-710.5 622.25,-710.5 622.25,-688 597.5,-688"/>
+<text xml:space="preserve" text-anchor="start" x="600.5" y="-694.75" font-family="Times,serif" font-size="14.00">pos</text>
+<polygon fill="#e0ffe0" stroke="none" points="622.25,-688 622.25,-710.5 649.25,-710.5 649.25,-688 622.25,-688"/>
+<polygon fill="none" stroke="black" points="622.25,-688 622.25,-710.5 649.25,-710.5 649.25,-688 622.25,-688"/>
+<text xml:space="preserve" text-anchor="start" x="625.25" y="-694.75" font-family="Times,serif" font-size="14.00">size</text>
+<polygon fill="#e0ffe0" stroke="none" points="649.25,-688 649.25,-710.5 739.25,-710.5 739.25,-688 649.25,-688"/>
+<polygon fill="none" stroke="black" points="649.25,-688 649.25,-710.5 739.25,-710.5 739.25,-688 649.25,-688"/>
+<text xml:space="preserve" text-anchor="start" x="682.62" y="-694.75" font-family="Times,serif" font-size="14.00">type</text>
+<polygon fill="#e0ffe0" stroke="none" points="739.25,-688 739.25,-710.5 803.75,-710.5 803.75,-688 739.25,-688"/>
+<polygon fill="none" stroke="black" points="739.25,-688 739.25,-710.5 803.75,-710.5 803.75,-688 739.25,-688"/>
+<text xml:space="preserve" text-anchor="start" x="766.25" y="-694.75" font-family="Times,serif" font-size="14.00">id</text>
+<polygon fill="none" stroke="black" points="597.5,-665.5 597.5,-688 622.25,-688 622.25,-665.5 597.5,-665.5"/>
+<text xml:space="preserve" text-anchor="start" x="606.5" y="-672.25" font-family="Times,serif" font-size="14.00">0</text>
+<polygon fill="none" stroke="black" points="622.25,-665.5 622.25,-688 649.25,-688 649.25,-665.5 622.25,-665.5"/>
+<text xml:space="preserve" text-anchor="start" x="632.38" y="-672.25" font-family="Times,serif" font-size="14.00">1</text>
+<polygon fill="none" stroke="black" points="649.25,-665.5 649.25,-688 739.25,-688 739.25,-665.5 649.25,-665.5"/>
+<text xml:space="preserve" text-anchor="start" x="652.25" y="-672.25" font-family="Times,serif" font-size="14.00">u1→ErrorType</text>
+<polygon fill="none" stroke="black" points="739.25,-665.5 739.25,-688 803.75,-688 803.75,-665.5 739.25,-665.5"/>
+<text xml:space="preserve" text-anchor="start" x="742.25" y="-672.25" font-family="Times,serif" font-size="14.00">error_code</text>
+</g>
+<!-- solec__seq_payload_switch&#45;&gt;error__seq -->
<g id="edge3" class="edge">
-<title>solec__seq_payload_switch:case1&#45;&gt;message__seq</title>
-<path fill="none" stroke="black" stroke-width="2" d="M497,-425.25C518.3,-425.25 515.4,-444.65 532,-458 535.67,-460.95 539.46,-463.92 543.32,-466.87"/>
-<polygon fill="black" stroke="black" stroke-width="2" points="539.92,-468.69 550.01,-471.9 544.12,-463.09 539.92,-468.69"/>
+<title>solec__seq_payload_switch:case1&#45;&gt;error__seq</title>
+<path fill="none" stroke="black" stroke-width="2" d="M546.5,-534.5C599.71,-534.5 544.29,-610.96 581.5,-649 583.55,-651.09 585.71,-653.08 587.97,-654.95"/>
+<polygon fill="black" stroke="black" stroke-width="2" points="584.55,-656.78 594.68,-659.88 588.69,-651.14 584.55,-656.78"/>
</g>
-<!-- ping__seq -->
+<!-- handshake__seq -->
<g id="node6" class="node">
-<title>ping__seq</title>
-<polygon fill="#e0ffe0" stroke="none" points="588.88,-391.75 588.88,-414.25 613.62,-414.25 613.62,-391.75 588.88,-391.75"/>
-<polygon fill="none" stroke="black" points="588.88,-391.75 588.88,-414.25 613.62,-414.25 613.62,-391.75 588.88,-391.75"/>
-<text xml:space="preserve" text-anchor="start" x="591.88" y="-398.5" font-family="Times,serif" font-size="14.00">pos</text>
-<polygon fill="#e0ffe0" stroke="none" points="613.62,-391.75 613.62,-414.25 640.62,-414.25 640.62,-391.75 613.62,-391.75"/>
-<polygon fill="none" stroke="black" points="613.62,-391.75 613.62,-414.25 640.62,-414.25 640.62,-391.75 613.62,-391.75"/>
-<text xml:space="preserve" text-anchor="start" x="616.62" y="-398.5" font-family="Times,serif" font-size="14.00">size</text>
-<polygon fill="#e0ffe0" stroke="none" points="640.62,-391.75 640.62,-414.25 669.88,-414.25 669.88,-391.75 640.62,-391.75"/>
-<polygon fill="none" stroke="black" points="640.62,-391.75 640.62,-414.25 669.88,-414.25 669.88,-391.75 640.62,-391.75"/>
-<text xml:space="preserve" text-anchor="start" x="643.62" y="-398.5" font-family="Times,serif" font-size="14.00">type</text>
-<polygon fill="#e0ffe0" stroke="none" points="669.88,-391.75 669.88,-414.25 686.38,-414.25 686.38,-391.75 669.88,-391.75"/>
-<polygon fill="none" stroke="black" points="669.88,-391.75 669.88,-414.25 686.38,-414.25 686.38,-391.75 669.88,-391.75"/>
-<text xml:space="preserve" text-anchor="start" x="672.88" y="-398.5" font-family="Times,serif" font-size="14.00">id</text>
-</g>
-<!-- solec__seq_payload_switch&#45;&gt;ping__seq -->
+<title>handshake__seq</title>
+<polygon fill="#e0ffe0" stroke="none" points="611,-586.25 611,-608.75 635.75,-608.75 635.75,-586.25 611,-586.25"/>
+<polygon fill="none" stroke="black" points="611,-586.25 611,-608.75 635.75,-608.75 635.75,-586.25 611,-586.25"/>
+<text xml:space="preserve" text-anchor="start" x="614" y="-593" font-family="Times,serif" font-size="14.00">pos</text>
+<polygon fill="#e0ffe0" stroke="none" points="635.75,-586.25 635.75,-608.75 662.75,-608.75 662.75,-586.25 635.75,-586.25"/>
+<polygon fill="none" stroke="black" points="635.75,-586.25 635.75,-608.75 662.75,-608.75 662.75,-586.25 635.75,-586.25"/>
+<text xml:space="preserve" text-anchor="start" x="638.75" y="-593" font-family="Times,serif" font-size="14.00">size</text>
+<polygon fill="#e0ffe0" stroke="none" points="662.75,-586.25 662.75,-608.75 692,-608.75 692,-586.25 662.75,-586.25"/>
+<polygon fill="none" stroke="black" points="662.75,-586.25 662.75,-608.75 692,-608.75 692,-586.25 662.75,-586.25"/>
+<text xml:space="preserve" text-anchor="start" x="665.75" y="-593" font-family="Times,serif" font-size="14.00">type</text>
+<polygon fill="#e0ffe0" stroke="none" points="692,-586.25 692,-608.75 790.25,-608.75 790.25,-586.25 692,-586.25"/>
+<polygon fill="none" stroke="black" points="692,-586.25 692,-608.75 790.25,-608.75 790.25,-586.25 692,-586.25"/>
+<text xml:space="preserve" text-anchor="start" x="735.88" y="-593" font-family="Times,serif" font-size="14.00">id</text>
+<polygon fill="none" stroke="black" points="611,-563.75 611,-586.25 635.75,-586.25 635.75,-563.75 611,-563.75"/>
+<text xml:space="preserve" text-anchor="start" x="620" y="-570.5" font-family="Times,serif" font-size="14.00">0</text>
+<polygon fill="none" stroke="black" points="635.75,-563.75 635.75,-586.25 662.75,-586.25 662.75,-563.75 635.75,-563.75"/>
+<text xml:space="preserve" text-anchor="start" x="645.88" y="-570.5" font-family="Times,serif" font-size="14.00">1</text>
+<polygon fill="none" stroke="black" points="662.75,-563.75 662.75,-586.25 692,-586.25 692,-563.75 662.75,-563.75"/>
+<text xml:space="preserve" text-anchor="start" x="670.62" y="-570.5" font-family="Times,serif" font-size="14.00">u1</text>
+<polygon fill="none" stroke="black" points="692,-563.75 692,-586.25 790.25,-586.25 790.25,-563.75 692,-563.75"/>
+<text xml:space="preserve" text-anchor="start" x="695.38" y="-570.5" font-family="Times,serif" font-size="14.00">proto_ver_major</text>
+<polygon fill="none" stroke="black" points="611,-541.25 611,-563.75 635.75,-563.75 635.75,-541.25 611,-541.25"/>
+<text xml:space="preserve" text-anchor="start" x="620" y="-548" font-family="Times,serif" font-size="14.00">1</text>
+<polygon fill="none" stroke="black" points="635.75,-541.25 635.75,-563.75 662.75,-563.75 662.75,-541.25 635.75,-541.25"/>
+<text xml:space="preserve" text-anchor="start" x="645.88" y="-548" font-family="Times,serif" font-size="14.00">1</text>
+<polygon fill="none" stroke="black" points="662.75,-541.25 662.75,-563.75 692,-563.75 692,-541.25 662.75,-541.25"/>
+<text xml:space="preserve" text-anchor="start" x="670.62" y="-548" font-family="Times,serif" font-size="14.00">u1</text>
+<polygon fill="none" stroke="black" points="692,-541.25 692,-563.75 790.25,-563.75 790.25,-541.25 692,-541.25"/>
+<text xml:space="preserve" text-anchor="start" x="695" y="-548" font-family="Times,serif" font-size="14.00">proto_ver_minor</text>
+</g>
+<!-- solec__seq_payload_switch&#45;&gt;handshake__seq -->
<g id="edge4" class="edge">
-<title>solec__seq_payload_switch:case2&#45;&gt;ping__seq</title>
-<path fill="none" stroke="black" stroke-width="2" d="M497,-402.75C520.64,-402.75 546.53,-402.79 569.53,-402.83"/>
-<polygon fill="black" stroke="black" stroke-width="2" points="567.88,-406.33 577.88,-402.85 567.89,-399.33 567.88,-406.33"/>
+<title>solec__seq_payload_switch:case2&#45;&gt;handshake__seq</title>
+<path fill="none" stroke="black" stroke-width="2" d="M546.5,-512C548.28,-512 571.52,-521.39 599.38,-532.93"/>
+<polygon fill="black" stroke="black" stroke-width="2" points="596.45,-535.5 607.02,-536.1 599.13,-529.04 596.45,-535.5"/>
</g>
-<!-- pong__seq -->
+<!-- message__seq -->
<g id="node7" class="node">
-<title>pong__seq</title>
-<polygon fill="#e0ffe0" stroke="none" points="563.75,-310 563.75,-332.5 588.5,-332.5 588.5,-310 563.75,-310"/>
-<polygon fill="none" stroke="black" points="563.75,-310 563.75,-332.5 588.5,-332.5 588.5,-310 563.75,-310"/>
-<text xml:space="preserve" text-anchor="start" x="566.75" y="-316.75" font-family="Times,serif" font-size="14.00">pos</text>
-<polygon fill="#e0ffe0" stroke="none" points="588.5,-310 588.5,-332.5 615.5,-332.5 615.5,-310 588.5,-310"/>
-<polygon fill="none" stroke="black" points="588.5,-310 588.5,-332.5 615.5,-332.5 615.5,-310 588.5,-310"/>
-<text xml:space="preserve" text-anchor="start" x="591.5" y="-316.75" font-family="Times,serif" font-size="14.00">size</text>
-<polygon fill="#e0ffe0" stroke="none" points="615.5,-310 615.5,-332.5 647.75,-332.5 647.75,-310 615.5,-310"/>
-<polygon fill="none" stroke="black" points="615.5,-310 615.5,-332.5 647.75,-332.5 647.75,-310 615.5,-310"/>
-<text xml:space="preserve" text-anchor="start" x="620" y="-316.75" font-family="Times,serif" font-size="14.00">type</text>
-<polygon fill="#e0ffe0" stroke="none" points="647.75,-310 647.75,-332.5 711.5,-332.5 711.5,-310 647.75,-310"/>
-<polygon fill="none" stroke="black" points="647.75,-310 647.75,-332.5 711.5,-332.5 711.5,-310 647.75,-310"/>
-<text xml:space="preserve" text-anchor="start" x="674.38" y="-316.75" font-family="Times,serif" font-size="14.00">id</text>
-<polygon fill="none" stroke="black" points="563.75,-287.5 563.75,-310 588.5,-310 588.5,-287.5 563.75,-287.5"/>
-<text xml:space="preserve" text-anchor="start" x="572.75" y="-294.25" font-family="Times,serif" font-size="14.00">0</text>
-<polygon fill="none" stroke="black" points="588.5,-287.5 588.5,-310 615.5,-310 615.5,-287.5 588.5,-287.5"/>
-<text xml:space="preserve" text-anchor="start" x="598.62" y="-294.25" font-family="Times,serif" font-size="14.00">8</text>
-<polygon fill="none" stroke="black" points="615.5,-287.5 615.5,-310 647.75,-310 647.75,-287.5 615.5,-287.5"/>
-<text xml:space="preserve" text-anchor="start" x="618.5" y="-294.25" font-family="Times,serif" font-size="14.00">u8be</text>
-<polygon fill="none" stroke="black" points="647.75,-287.5 647.75,-310 711.5,-310 711.5,-287.5 647.75,-287.5"/>
-<text xml:space="preserve" text-anchor="start" x="650.75" y="-294.25" font-family="Times,serif" font-size="14.00">timestamp</text>
-</g>
-<!-- solec__seq_payload_switch&#45;&gt;pong__seq -->
+<title>message__seq</title>
+<polygon fill="#e0ffe0" stroke="none" points="623.38,-461.75 623.38,-484.25 648.12,-484.25 648.12,-461.75 623.38,-461.75"/>
+<polygon fill="none" stroke="black" points="623.38,-461.75 623.38,-484.25 648.12,-484.25 648.12,-461.75 623.38,-461.75"/>
+<text xml:space="preserve" text-anchor="start" x="626.38" y="-468.5" font-family="Times,serif" font-size="14.00">pos</text>
+<polygon fill="#e0ffe0" stroke="none" points="648.12,-461.75 648.12,-484.25 675.12,-484.25 675.12,-461.75 648.12,-461.75"/>
+<polygon fill="none" stroke="black" points="648.12,-461.75 648.12,-484.25 675.12,-484.25 675.12,-461.75 648.12,-461.75"/>
+<text xml:space="preserve" text-anchor="start" x="651.12" y="-468.5" font-family="Times,serif" font-size="14.00">size</text>
+<polygon fill="#e0ffe0" stroke="none" points="675.12,-461.75 675.12,-484.25 714.12,-484.25 714.12,-461.75 675.12,-461.75"/>
+<polygon fill="none" stroke="black" points="675.12,-461.75 675.12,-484.25 714.12,-484.25 714.12,-461.75 675.12,-461.75"/>
+<text xml:space="preserve" text-anchor="start" x="683" y="-468.5" font-family="Times,serif" font-size="14.00">type</text>
+<polygon fill="#e0ffe0" stroke="none" points="714.12,-461.75 714.12,-484.25 777.88,-484.25 777.88,-461.75 714.12,-461.75"/>
+<polygon fill="none" stroke="black" points="714.12,-461.75 714.12,-484.25 777.88,-484.25 777.88,-461.75 714.12,-461.75"/>
+<text xml:space="preserve" text-anchor="start" x="740.75" y="-468.5" font-family="Times,serif" font-size="14.00">id</text>
+<polygon fill="none" stroke="black" points="623.38,-439.25 623.38,-461.75 648.12,-461.75 648.12,-439.25 623.38,-439.25"/>
+<text xml:space="preserve" text-anchor="start" x="632.38" y="-446" font-family="Times,serif" font-size="14.00">0</text>
+<polygon fill="none" stroke="black" points="648.12,-439.25 648.12,-461.75 675.12,-461.75 675.12,-439.25 648.12,-439.25"/>
+<text xml:space="preserve" text-anchor="start" x="656" y="-446" font-family="Times,serif" font-size="14.00">...</text>
+<polygon fill="none" stroke="black" points="675.12,-439.25 675.12,-461.75 714.12,-461.75 714.12,-439.25 675.12,-439.25"/>
+<text xml:space="preserve" text-anchor="start" x="678.12" y="-446" font-family="Times,serif" font-size="14.00">String</text>
+<polygon fill="none" stroke="black" points="714.12,-439.25 714.12,-461.75 777.88,-461.75 777.88,-439.25 714.12,-439.25"/>
+<text xml:space="preserve" text-anchor="start" x="728.38" y="-446" font-family="Times,serif" font-size="14.00">source</text>
+<polygon fill="none" stroke="black" points="623.38,-416.75 623.38,-439.25 648.12,-439.25 648.12,-416.75 623.38,-416.75"/>
+<text xml:space="preserve" text-anchor="start" x="630.12" y="-423.5" font-family="Times,serif" font-size="14.00">...</text>
+<polygon fill="none" stroke="black" points="648.12,-416.75 648.12,-439.25 675.12,-439.25 675.12,-416.75 648.12,-416.75"/>
+<text xml:space="preserve" text-anchor="start" x="656" y="-423.5" font-family="Times,serif" font-size="14.00">...</text>
+<polygon fill="none" stroke="black" points="675.12,-416.75 675.12,-439.25 714.12,-439.25 714.12,-416.75 675.12,-416.75"/>
+<text xml:space="preserve" text-anchor="start" x="678.12" y="-423.5" font-family="Times,serif" font-size="14.00">String</text>
+<polygon fill="none" stroke="black" points="714.12,-416.75 714.12,-439.25 777.88,-439.25 777.88,-416.75 714.12,-416.75"/>
+<text xml:space="preserve" text-anchor="start" x="730.62" y="-423.5" font-family="Times,serif" font-size="14.00">target</text>
+<polygon fill="none" stroke="black" points="623.38,-394.25 623.38,-416.75 648.12,-416.75 648.12,-394.25 623.38,-394.25"/>
+<text xml:space="preserve" text-anchor="start" x="630.12" y="-401" font-family="Times,serif" font-size="14.00">...</text>
+<polygon fill="none" stroke="black" points="648.12,-394.25 648.12,-416.75 675.12,-416.75 675.12,-394.25 648.12,-394.25"/>
+<text xml:space="preserve" text-anchor="start" x="658.25" y="-401" font-family="Times,serif" font-size="14.00">8</text>
+<polygon fill="none" stroke="black" points="675.12,-394.25 675.12,-416.75 714.12,-416.75 714.12,-394.25 675.12,-394.25"/>
+<text xml:space="preserve" text-anchor="start" x="681.5" y="-401" font-family="Times,serif" font-size="14.00">u8be</text>
+<polygon fill="none" stroke="black" points="714.12,-394.25 714.12,-416.75 777.88,-416.75 777.88,-394.25 714.12,-394.25"/>
+<text xml:space="preserve" text-anchor="start" x="717.12" y="-401" font-family="Times,serif" font-size="14.00">timestamp</text>
+<polygon fill="none" stroke="black" points="623.38,-371.75 623.38,-394.25 648.12,-394.25 648.12,-371.75 623.38,-371.75"/>
+<text xml:space="preserve" text-anchor="start" x="630.12" y="-378.5" font-family="Times,serif" font-size="14.00">...</text>
+<polygon fill="none" stroke="black" points="648.12,-371.75 648.12,-394.25 675.12,-394.25 675.12,-371.75 648.12,-371.75"/>
+<text xml:space="preserve" text-anchor="start" x="656" y="-378.5" font-family="Times,serif" font-size="14.00">...</text>
+<polygon fill="none" stroke="black" points="675.12,-371.75 675.12,-394.25 714.12,-394.25 714.12,-371.75 675.12,-371.75"/>
+<text xml:space="preserve" text-anchor="start" x="678.12" y="-378.5" font-family="Times,serif" font-size="14.00">String</text>
+<polygon fill="none" stroke="black" points="714.12,-371.75 714.12,-394.25 777.88,-394.25 777.88,-371.75 714.12,-371.75"/>
+<text xml:space="preserve" text-anchor="start" x="726.12" y="-378.5" font-family="Times,serif" font-size="14.00">content</text>
+</g>
+<!-- solec__seq_payload_switch&#45;&gt;message__seq -->
<g id="edge5" class="edge">
-<title>solec__seq_payload_switch:case3&#45;&gt;pong__seq</title>
-<path fill="none" stroke="black" stroke-width="2" d="M497,-380.25C515.38,-380.25 553.42,-360.57 585.15,-342.05"/>
-<polygon fill="black" stroke="black" stroke-width="2" points="585.34,-346 592.16,-337.9 581.77,-339.98 585.34,-346"/>
+<title>solec__seq_payload_switch:case3&#45;&gt;message__seq</title>
+<path fill="none" stroke="black" stroke-width="2" d="M546.5,-489.5C566.11,-489.5 586.18,-485.1 605.06,-478.66"/>
+<polygon fill="black" stroke="black" stroke-width="2" points="604.69,-482.52 612.88,-475.81 602.29,-475.95 604.69,-482.52"/>
</g>
-<!-- test__seq -->
+<!-- success__seq -->
<g id="node9" class="node">
+<title>success__seq</title>
+<polygon fill="#e0ffe0" stroke="none" points="651.88,-289.75 651.88,-312.25 676.62,-312.25 676.62,-289.75 651.88,-289.75"/>
+<polygon fill="none" stroke="black" points="651.88,-289.75 651.88,-312.25 676.62,-312.25 676.62,-289.75 651.88,-289.75"/>
+<text xml:space="preserve" text-anchor="start" x="654.88" y="-296.5" font-family="Times,serif" font-size="14.00">pos</text>
+<polygon fill="#e0ffe0" stroke="none" points="676.62,-289.75 676.62,-312.25 703.62,-312.25 703.62,-289.75 676.62,-289.75"/>
+<polygon fill="none" stroke="black" points="676.62,-289.75 676.62,-312.25 703.62,-312.25 703.62,-289.75 676.62,-289.75"/>
+<text xml:space="preserve" text-anchor="start" x="679.62" y="-296.5" font-family="Times,serif" font-size="14.00">size</text>
+<polygon fill="#e0ffe0" stroke="none" points="703.62,-289.75 703.62,-312.25 732.88,-312.25 732.88,-289.75 703.62,-289.75"/>
+<polygon fill="none" stroke="black" points="703.62,-289.75 703.62,-312.25 732.88,-312.25 732.88,-289.75 703.62,-289.75"/>
+<text xml:space="preserve" text-anchor="start" x="706.62" y="-296.5" font-family="Times,serif" font-size="14.00">type</text>
+<polygon fill="#e0ffe0" stroke="none" points="732.88,-289.75 732.88,-312.25 749.38,-312.25 749.38,-289.75 732.88,-289.75"/>
+<polygon fill="none" stroke="black" points="732.88,-289.75 732.88,-312.25 749.38,-312.25 749.38,-289.75 732.88,-289.75"/>
+<text xml:space="preserve" text-anchor="start" x="735.88" y="-296.5" font-family="Times,serif" font-size="14.00">id</text>
+</g>
+<!-- solec__seq_payload_switch&#45;&gt;success__seq -->
+<g id="edge6" class="edge">
+<title>solec__seq_payload_switch:case4&#45;&gt;success__seq</title>
+<path fill="none" stroke="black" stroke-width="2" d="M546.5,-467C598.23,-467 547.38,-394.88 581.5,-356 595.29,-340.29 614.51,-328.76 633.44,-320.43"/>
+<polygon fill="black" stroke="black" stroke-width="2" points="633.18,-324.32 641.1,-317.28 630.52,-317.85 633.18,-324.32"/>
+</g>
+<!-- test__seq -->
+<g id="node10" class="node">
<title>test__seq</title>
-<polygon fill="#e0ffe0" stroke="none" points="571.62,-207.75 571.62,-230.25 596.38,-230.25 596.38,-207.75 571.62,-207.75"/>
-<polygon fill="none" stroke="black" points="571.62,-207.75 571.62,-230.25 596.38,-230.25 596.38,-207.75 571.62,-207.75"/>
-<text xml:space="preserve" text-anchor="start" x="574.62" y="-214.5" font-family="Times,serif" font-size="14.00">pos</text>
-<polygon fill="#e0ffe0" stroke="none" points="596.38,-207.75 596.38,-230.25 623.38,-230.25 623.38,-207.75 596.38,-207.75"/>
-<polygon fill="none" stroke="black" points="596.38,-207.75 596.38,-230.25 623.38,-230.25 623.38,-207.75 596.38,-207.75"/>
-<text xml:space="preserve" text-anchor="start" x="599.38" y="-214.5" font-family="Times,serif" font-size="14.00">size</text>
-<polygon fill="#e0ffe0" stroke="none" points="623.38,-207.75 623.38,-230.25 666.12,-230.25 666.12,-207.75 623.38,-207.75"/>
-<polygon fill="none" stroke="black" points="623.38,-207.75 623.38,-230.25 666.12,-230.25 666.12,-207.75 623.38,-207.75"/>
-<text xml:space="preserve" text-anchor="start" x="633.12" y="-214.5" font-family="Times,serif" font-size="14.00">type</text>
-<polygon fill="#e0ffe0" stroke="none" points="666.12,-207.75 666.12,-230.25 703.62,-230.25 703.62,-207.75 666.12,-207.75"/>
-<polygon fill="none" stroke="black" points="666.12,-207.75 666.12,-230.25 703.62,-230.25 703.62,-207.75 666.12,-207.75"/>
-<text xml:space="preserve" text-anchor="start" x="679.62" y="-214.5" font-family="Times,serif" font-size="14.00">id</text>
-<polygon fill="none" stroke="black" points="571.62,-185.25 571.62,-207.75 596.38,-207.75 596.38,-185.25 571.62,-185.25"/>
-<text xml:space="preserve" text-anchor="start" x="580.62" y="-192" font-family="Times,serif" font-size="14.00">0</text>
-<polygon fill="none" stroke="black" points="596.38,-185.25 596.38,-207.75 623.38,-207.75 623.38,-185.25 596.38,-185.25"/>
-<text xml:space="preserve" text-anchor="start" x="606.5" y="-192" font-family="Times,serif" font-size="14.00">1</text>
-<polygon fill="none" stroke="black" points="623.38,-185.25 623.38,-207.75 666.12,-207.75 666.12,-185.25 623.38,-185.25"/>
-<text xml:space="preserve" text-anchor="start" x="638" y="-192" font-family="Times,serif" font-size="14.00">u1</text>
-<polygon fill="none" stroke="black" points="666.12,-185.25 666.12,-207.75 703.62,-207.75 703.62,-185.25 666.12,-185.25"/>
-<text xml:space="preserve" text-anchor="start" x="669.12" y="-192" font-family="Times,serif" font-size="14.00">num1</text>
-<polygon fill="none" stroke="black" points="571.62,-162.75 571.62,-185.25 596.38,-185.25 596.38,-162.75 571.62,-162.75"/>
-<text xml:space="preserve" text-anchor="start" x="580.62" y="-169.5" font-family="Times,serif" font-size="14.00">1</text>
-<polygon fill="none" stroke="black" points="596.38,-162.75 596.38,-185.25 623.38,-185.25 623.38,-162.75 596.38,-162.75"/>
-<text xml:space="preserve" text-anchor="start" x="606.5" y="-169.5" font-family="Times,serif" font-size="14.00">8</text>
-<polygon fill="none" stroke="black" points="623.38,-162.75 623.38,-185.25 666.12,-185.25 666.12,-162.75 623.38,-162.75"/>
-<text xml:space="preserve" text-anchor="start" x="631.62" y="-169.5" font-family="Times,serif" font-size="14.00">u8be</text>
-<polygon fill="none" stroke="black" points="666.12,-162.75 666.12,-185.25 703.62,-185.25 703.62,-162.75 666.12,-162.75"/>
-<text xml:space="preserve" text-anchor="start" x="669.12" y="-169.5" font-family="Times,serif" font-size="14.00">time1</text>
-<polygon fill="none" stroke="black" points="571.62,-140.25 571.62,-162.75 596.38,-162.75 596.38,-140.25 571.62,-140.25"/>
-<text xml:space="preserve" text-anchor="start" x="580.62" y="-147" font-family="Times,serif" font-size="14.00">9</text>
-<polygon fill="none" stroke="black" points="596.38,-140.25 596.38,-162.75 623.38,-162.75 623.38,-140.25 596.38,-140.25"/>
-<text xml:space="preserve" text-anchor="start" x="604.25" y="-147" font-family="Times,serif" font-size="14.00">...</text>
-<polygon fill="none" stroke="black" points="623.38,-140.25 623.38,-162.75 666.12,-162.75 666.12,-140.25 623.38,-140.25"/>
-<text xml:space="preserve" text-anchor="start" x="628.25" y="-147" font-family="Times,serif" font-size="14.00">String</text>
-<polygon fill="none" stroke="black" points="666.12,-140.25 666.12,-162.75 703.62,-162.75 703.62,-140.25 666.12,-140.25"/>
-<text xml:space="preserve" text-anchor="start" x="674.75" y="-147" font-family="Times,serif" font-size="14.00">str1</text>
-<polygon fill="none" stroke="black" points="571.62,-117.75 571.62,-140.25 596.38,-140.25 596.38,-117.75 571.62,-117.75"/>
-<text xml:space="preserve" text-anchor="start" x="578.38" y="-124.5" font-family="Times,serif" font-size="14.00">...</text>
-<polygon fill="none" stroke="black" points="596.38,-117.75 596.38,-140.25 623.38,-140.25 623.38,-117.75 596.38,-117.75"/>
-<text xml:space="preserve" text-anchor="start" x="606.5" y="-124.5" font-family="Times,serif" font-size="14.00">2</text>
-<polygon fill="none" stroke="black" points="623.38,-117.75 623.38,-140.25 666.12,-140.25 666.12,-117.75 623.38,-117.75"/>
-<text xml:space="preserve" text-anchor="start" x="631.62" y="-124.5" font-family="Times,serif" font-size="14.00">u2be</text>
-<polygon fill="none" stroke="black" points="666.12,-117.75 666.12,-140.25 703.62,-140.25 703.62,-117.75 666.12,-117.75"/>
-<text xml:space="preserve" text-anchor="start" x="669.12" y="-124.5" font-family="Times,serif" font-size="14.00">num2</text>
-<polygon fill="none" stroke="black" points="571.62,-95.25 571.62,-117.75 596.38,-117.75 596.38,-95.25 571.62,-95.25"/>
-<text xml:space="preserve" text-anchor="start" x="578.38" y="-102" font-family="Times,serif" font-size="14.00">...</text>
-<polygon fill="none" stroke="black" points="596.38,-95.25 596.38,-117.75 623.38,-117.75 623.38,-95.25 596.38,-95.25"/>
-<text xml:space="preserve" text-anchor="start" x="604.25" y="-102" font-family="Times,serif" font-size="14.00">...</text>
-<polygon fill="none" stroke="black" points="623.38,-95.25 623.38,-117.75 666.12,-117.75 666.12,-95.25 623.38,-95.25"/>
-<text xml:space="preserve" text-anchor="start" x="626.38" y="-102" font-family="Times,serif" font-size="14.00">Binary</text>
-<polygon fill="none" stroke="black" points="666.12,-95.25 666.12,-117.75 703.62,-117.75 703.62,-95.25 666.12,-95.25"/>
-<text xml:space="preserve" text-anchor="start" x="672.88" y="-102" font-family="Times,serif" font-size="14.00">bin1</text>
-<polygon fill="none" stroke="black" points="571.62,-72.75 571.62,-95.25 596.38,-95.25 596.38,-72.75 571.62,-72.75"/>
-<text xml:space="preserve" text-anchor="start" x="578.38" y="-79.5" font-family="Times,serif" font-size="14.00">...</text>
-<polygon fill="none" stroke="black" points="596.38,-72.75 596.38,-95.25 623.38,-95.25 623.38,-72.75 596.38,-72.75"/>
-<text xml:space="preserve" text-anchor="start" x="606.5" y="-79.5" font-family="Times,serif" font-size="14.00">4</text>
-<polygon fill="none" stroke="black" points="623.38,-72.75 623.38,-95.25 666.12,-95.25 666.12,-72.75 623.38,-72.75"/>
-<text xml:space="preserve" text-anchor="start" x="631.62" y="-79.5" font-family="Times,serif" font-size="14.00">u4be</text>
-<polygon fill="none" stroke="black" points="666.12,-72.75 666.12,-95.25 703.62,-95.25 703.62,-72.75 666.12,-72.75"/>
-<text xml:space="preserve" text-anchor="start" x="669.12" y="-79.5" font-family="Times,serif" font-size="14.00">num3</text>
-<polygon fill="none" stroke="black" points="571.62,-50.25 571.62,-72.75 596.38,-72.75 596.38,-50.25 571.62,-50.25"/>
-<text xml:space="preserve" text-anchor="start" x="578.38" y="-57" font-family="Times,serif" font-size="14.00">...</text>
-<polygon fill="none" stroke="black" points="596.38,-50.25 596.38,-72.75 623.38,-72.75 623.38,-50.25 596.38,-50.25"/>
-<text xml:space="preserve" text-anchor="start" x="604.25" y="-57" font-family="Times,serif" font-size="14.00">...</text>
-<polygon fill="none" stroke="black" points="623.38,-50.25 623.38,-72.75 666.12,-72.75 666.12,-50.25 623.38,-50.25"/>
-<text xml:space="preserve" text-anchor="start" x="628.25" y="-57" font-family="Times,serif" font-size="14.00">String</text>
-<polygon fill="none" stroke="black" points="666.12,-50.25 666.12,-72.75 703.62,-72.75 703.62,-50.25 666.12,-50.25"/>
-<text xml:space="preserve" text-anchor="start" x="674.75" y="-57" font-family="Times,serif" font-size="14.00">str2</text>
-<polygon fill="none" stroke="black" points="571.62,-27.75 571.62,-50.25 596.38,-50.25 596.38,-27.75 571.62,-27.75"/>
-<text xml:space="preserve" text-anchor="start" x="578.38" y="-34.5" font-family="Times,serif" font-size="14.00">...</text>
-<polygon fill="none" stroke="black" points="596.38,-27.75 596.38,-50.25 623.38,-50.25 623.38,-27.75 596.38,-27.75"/>
-<text xml:space="preserve" text-anchor="start" x="606.5" y="-34.5" font-family="Times,serif" font-size="14.00">8</text>
-<polygon fill="none" stroke="black" points="623.38,-27.75 623.38,-50.25 666.12,-50.25 666.12,-27.75 623.38,-27.75"/>
-<text xml:space="preserve" text-anchor="start" x="631.62" y="-34.5" font-family="Times,serif" font-size="14.00">u8be</text>
-<polygon fill="none" stroke="black" points="666.12,-27.75 666.12,-50.25 703.62,-50.25 703.62,-27.75 666.12,-27.75"/>
-<text xml:space="preserve" text-anchor="start" x="669.12" y="-34.5" font-family="Times,serif" font-size="14.00">num4</text>
+<polygon fill="#e0ffe0" stroke="none" points="634.62,-207.75 634.62,-230.25 659.38,-230.25 659.38,-207.75 634.62,-207.75"/>
+<polygon fill="none" stroke="black" points="634.62,-207.75 634.62,-230.25 659.38,-230.25 659.38,-207.75 634.62,-207.75"/>
+<text xml:space="preserve" text-anchor="start" x="637.62" y="-214.5" font-family="Times,serif" font-size="14.00">pos</text>
+<polygon fill="#e0ffe0" stroke="none" points="659.38,-207.75 659.38,-230.25 686.38,-230.25 686.38,-207.75 659.38,-207.75"/>
+<polygon fill="none" stroke="black" points="659.38,-207.75 659.38,-230.25 686.38,-230.25 686.38,-207.75 659.38,-207.75"/>
+<text xml:space="preserve" text-anchor="start" x="662.38" y="-214.5" font-family="Times,serif" font-size="14.00">size</text>
+<polygon fill="#e0ffe0" stroke="none" points="686.38,-207.75 686.38,-230.25 729.12,-230.25 729.12,-207.75 686.38,-207.75"/>
+<polygon fill="none" stroke="black" points="686.38,-207.75 686.38,-230.25 729.12,-230.25 729.12,-207.75 686.38,-207.75"/>
+<text xml:space="preserve" text-anchor="start" x="696.12" y="-214.5" font-family="Times,serif" font-size="14.00">type</text>
+<polygon fill="#e0ffe0" stroke="none" points="729.12,-207.75 729.12,-230.25 766.62,-230.25 766.62,-207.75 729.12,-207.75"/>
+<polygon fill="none" stroke="black" points="729.12,-207.75 729.12,-230.25 766.62,-230.25 766.62,-207.75 729.12,-207.75"/>
+<text xml:space="preserve" text-anchor="start" x="742.62" y="-214.5" font-family="Times,serif" font-size="14.00">id</text>
+<polygon fill="none" stroke="black" points="634.62,-185.25 634.62,-207.75 659.38,-207.75 659.38,-185.25 634.62,-185.25"/>
+<text xml:space="preserve" text-anchor="start" x="643.62" y="-192" font-family="Times,serif" font-size="14.00">0</text>
+<polygon fill="none" stroke="black" points="659.38,-185.25 659.38,-207.75 686.38,-207.75 686.38,-185.25 659.38,-185.25"/>
+<text xml:space="preserve" text-anchor="start" x="669.5" y="-192" font-family="Times,serif" font-size="14.00">1</text>
+<polygon fill="none" stroke="black" points="686.38,-185.25 686.38,-207.75 729.12,-207.75 729.12,-185.25 686.38,-185.25"/>
+<text xml:space="preserve" text-anchor="start" x="701" y="-192" font-family="Times,serif" font-size="14.00">u1</text>
+<polygon fill="none" stroke="black" points="729.12,-185.25 729.12,-207.75 766.62,-207.75 766.62,-185.25 729.12,-185.25"/>
+<text xml:space="preserve" text-anchor="start" x="732.12" y="-192" font-family="Times,serif" font-size="14.00">num1</text>
+<polygon fill="none" stroke="black" points="634.62,-162.75 634.62,-185.25 659.38,-185.25 659.38,-162.75 634.62,-162.75"/>
+<text xml:space="preserve" text-anchor="start" x="643.62" y="-169.5" font-family="Times,serif" font-size="14.00">1</text>
+<polygon fill="none" stroke="black" points="659.38,-162.75 659.38,-185.25 686.38,-185.25 686.38,-162.75 659.38,-162.75"/>
+<text xml:space="preserve" text-anchor="start" x="669.5" y="-169.5" font-family="Times,serif" font-size="14.00">8</text>
+<polygon fill="none" stroke="black" points="686.38,-162.75 686.38,-185.25 729.12,-185.25 729.12,-162.75 686.38,-162.75"/>
+<text xml:space="preserve" text-anchor="start" x="694.62" y="-169.5" font-family="Times,serif" font-size="14.00">u8be</text>
+<polygon fill="none" stroke="black" points="729.12,-162.75 729.12,-185.25 766.62,-185.25 766.62,-162.75 729.12,-162.75"/>
+<text xml:space="preserve" text-anchor="start" x="732.12" y="-169.5" font-family="Times,serif" font-size="14.00">time1</text>
+<polygon fill="none" stroke="black" points="634.62,-140.25 634.62,-162.75 659.38,-162.75 659.38,-140.25 634.62,-140.25"/>
+<text xml:space="preserve" text-anchor="start" x="643.62" y="-147" font-family="Times,serif" font-size="14.00">9</text>
+<polygon fill="none" stroke="black" points="659.38,-140.25 659.38,-162.75 686.38,-162.75 686.38,-140.25 659.38,-140.25"/>
+<text xml:space="preserve" text-anchor="start" x="667.25" y="-147" font-family="Times,serif" font-size="14.00">...</text>
+<polygon fill="none" stroke="black" points="686.38,-140.25 686.38,-162.75 729.12,-162.75 729.12,-140.25 686.38,-140.25"/>
+<text xml:space="preserve" text-anchor="start" x="691.25" y="-147" font-family="Times,serif" font-size="14.00">String</text>
+<polygon fill="none" stroke="black" points="729.12,-140.25 729.12,-162.75 766.62,-162.75 766.62,-140.25 729.12,-140.25"/>
+<text xml:space="preserve" text-anchor="start" x="737.75" y="-147" font-family="Times,serif" font-size="14.00">str1</text>
+<polygon fill="none" stroke="black" points="634.62,-117.75 634.62,-140.25 659.38,-140.25 659.38,-117.75 634.62,-117.75"/>
+<text xml:space="preserve" text-anchor="start" x="641.38" y="-124.5" font-family="Times,serif" font-size="14.00">...</text>
+<polygon fill="none" stroke="black" points="659.38,-117.75 659.38,-140.25 686.38,-140.25 686.38,-117.75 659.38,-117.75"/>
+<text xml:space="preserve" text-anchor="start" x="669.5" y="-124.5" font-family="Times,serif" font-size="14.00">2</text>
+<polygon fill="none" stroke="black" points="686.38,-117.75 686.38,-140.25 729.12,-140.25 729.12,-117.75 686.38,-117.75"/>
+<text xml:space="preserve" text-anchor="start" x="694.62" y="-124.5" font-family="Times,serif" font-size="14.00">u2be</text>
+<polygon fill="none" stroke="black" points="729.12,-117.75 729.12,-140.25 766.62,-140.25 766.62,-117.75 729.12,-117.75"/>
+<text xml:space="preserve" text-anchor="start" x="732.12" y="-124.5" font-family="Times,serif" font-size="14.00">num2</text>
+<polygon fill="none" stroke="black" points="634.62,-95.25 634.62,-117.75 659.38,-117.75 659.38,-95.25 634.62,-95.25"/>
+<text xml:space="preserve" text-anchor="start" x="641.38" y="-102" font-family="Times,serif" font-size="14.00">...</text>
+<polygon fill="none" stroke="black" points="659.38,-95.25 659.38,-117.75 686.38,-117.75 686.38,-95.25 659.38,-95.25"/>
+<text xml:space="preserve" text-anchor="start" x="667.25" y="-102" font-family="Times,serif" font-size="14.00">...</text>
+<polygon fill="none" stroke="black" points="686.38,-95.25 686.38,-117.75 729.12,-117.75 729.12,-95.25 686.38,-95.25"/>
+<text xml:space="preserve" text-anchor="start" x="689.38" y="-102" font-family="Times,serif" font-size="14.00">Binary</text>
+<polygon fill="none" stroke="black" points="729.12,-95.25 729.12,-117.75 766.62,-117.75 766.62,-95.25 729.12,-95.25"/>
+<text xml:space="preserve" text-anchor="start" x="735.88" y="-102" font-family="Times,serif" font-size="14.00">bin1</text>
+<polygon fill="none" stroke="black" points="634.62,-72.75 634.62,-95.25 659.38,-95.25 659.38,-72.75 634.62,-72.75"/>
+<text xml:space="preserve" text-anchor="start" x="641.38" y="-79.5" font-family="Times,serif" font-size="14.00">...</text>
+<polygon fill="none" stroke="black" points="659.38,-72.75 659.38,-95.25 686.38,-95.25 686.38,-72.75 659.38,-72.75"/>
+<text xml:space="preserve" text-anchor="start" x="669.5" y="-79.5" font-family="Times,serif" font-size="14.00">4</text>
+<polygon fill="none" stroke="black" points="686.38,-72.75 686.38,-95.25 729.12,-95.25 729.12,-72.75 686.38,-72.75"/>
+<text xml:space="preserve" text-anchor="start" x="694.62" y="-79.5" font-family="Times,serif" font-size="14.00">u4be</text>
+<polygon fill="none" stroke="black" points="729.12,-72.75 729.12,-95.25 766.62,-95.25 766.62,-72.75 729.12,-72.75"/>
+<text xml:space="preserve" text-anchor="start" x="732.12" y="-79.5" font-family="Times,serif" font-size="14.00">num3</text>
+<polygon fill="none" stroke="black" points="634.62,-50.25 634.62,-72.75 659.38,-72.75 659.38,-50.25 634.62,-50.25"/>
+<text xml:space="preserve" text-anchor="start" x="641.38" y="-57" font-family="Times,serif" font-size="14.00">...</text>
+<polygon fill="none" stroke="black" points="659.38,-50.25 659.38,-72.75 686.38,-72.75 686.38,-50.25 659.38,-50.25"/>
+<text xml:space="preserve" text-anchor="start" x="667.25" y="-57" font-family="Times,serif" font-size="14.00">...</text>
+<polygon fill="none" stroke="black" points="686.38,-50.25 686.38,-72.75 729.12,-72.75 729.12,-50.25 686.38,-50.25"/>
+<text xml:space="preserve" text-anchor="start" x="691.25" y="-57" font-family="Times,serif" font-size="14.00">String</text>
+<polygon fill="none" stroke="black" points="729.12,-50.25 729.12,-72.75 766.62,-72.75 766.62,-50.25 729.12,-50.25"/>
+<text xml:space="preserve" text-anchor="start" x="737.75" y="-57" font-family="Times,serif" font-size="14.00">str2</text>
+<polygon fill="none" stroke="black" points="634.62,-27.75 634.62,-50.25 659.38,-50.25 659.38,-27.75 634.62,-27.75"/>
+<text xml:space="preserve" text-anchor="start" x="641.38" y="-34.5" font-family="Times,serif" font-size="14.00">...</text>
+<polygon fill="none" stroke="black" points="659.38,-27.75 659.38,-50.25 686.38,-50.25 686.38,-27.75 659.38,-27.75"/>
+<text xml:space="preserve" text-anchor="start" x="669.5" y="-34.5" font-family="Times,serif" font-size="14.00">8</text>
+<polygon fill="none" stroke="black" points="686.38,-27.75 686.38,-50.25 729.12,-50.25 729.12,-27.75 686.38,-27.75"/>
+<text xml:space="preserve" text-anchor="start" x="694.62" y="-34.5" font-family="Times,serif" font-size="14.00">u8be</text>
+<polygon fill="none" stroke="black" points="729.12,-27.75 729.12,-50.25 766.62,-50.25 766.62,-27.75 729.12,-27.75"/>
+<text xml:space="preserve" text-anchor="start" x="732.12" y="-34.5" font-family="Times,serif" font-size="14.00">num4</text>
</g>
<!-- solec__seq_payload_switch&#45;&gt;test__seq -->
-<g id="edge6" class="edge">
-<title>solec__seq_payload_switch:case4&#45;&gt;test__seq</title>
-<path fill="none" stroke="black" stroke-width="2" d="M497,-357.75C538.58,-357.75 511.73,-307.3 532,-271 539.58,-257.42 548.27,-243.64 557.33,-230.28"/>
-<polygon fill="black" stroke="black" stroke-width="2" points="559.15,-233.81 561.94,-223.59 553.38,-229.84 559.15,-233.81"/>
+<g id="edge7" class="edge">
+<title>solec__seq_payload_switch:case5&#45;&gt;test__seq</title>
+<path fill="none" stroke="black" stroke-width="2" d="M546.5,-444.5C585.83,-444.5 564.52,-306.48 581.5,-271 591.44,-250.24 605.08,-229.97 619.58,-211.53"/>
+<polygon fill="black" stroke="black" stroke-width="2" points="621.3,-214.97 624.85,-204.99 615.85,-210.58 621.3,-214.97"/>
+</g>
+<!-- string__seq -->
+<g id="node8" class="node">
+<title>string__seq</title>
+<polygon fill="#e0ffe0" stroke="none" points="855.75,-439.25 855.75,-461.75 880.5,-461.75 880.5,-439.25 855.75,-439.25"/>
+<polygon fill="none" stroke="black" points="855.75,-439.25 855.75,-461.75 880.5,-461.75 880.5,-439.25 855.75,-439.25"/>
+<text xml:space="preserve" text-anchor="start" x="858.75" y="-446" font-family="Times,serif" font-size="14.00">pos</text>
+<polygon fill="#e0ffe0" stroke="none" points="880.5,-439.25 880.5,-461.75 952.5,-461.75 952.5,-439.25 880.5,-439.25"/>
+<polygon fill="none" stroke="black" points="880.5,-439.25 880.5,-461.75 952.5,-461.75 952.5,-439.25 880.5,-439.25"/>
+<text xml:space="preserve" text-anchor="start" x="906" y="-446" font-family="Times,serif" font-size="14.00">size</text>
+<polygon fill="#e0ffe0" stroke="none" points="952.5,-439.25 952.5,-461.75 1017.75,-461.75 1017.75,-439.25 952.5,-439.25"/>
+<polygon fill="none" stroke="black" points="952.5,-439.25 952.5,-461.75 1017.75,-461.75 1017.75,-439.25 952.5,-439.25"/>
+<text xml:space="preserve" text-anchor="start" x="973.5" y="-446" font-family="Times,serif" font-size="14.00">type</text>
+<polygon fill="#e0ffe0" stroke="none" points="1017.75,-439.25 1017.75,-461.75 1089.75,-461.75 1089.75,-439.25 1017.75,-439.25"/>
+<polygon fill="none" stroke="black" points="1017.75,-439.25 1017.75,-461.75 1089.75,-461.75 1089.75,-439.25 1017.75,-439.25"/>
+<text xml:space="preserve" text-anchor="start" x="1048.5" y="-446" font-family="Times,serif" font-size="14.00">id</text>
+<polygon fill="none" stroke="black" points="855.75,-416.75 855.75,-439.25 880.5,-439.25 880.5,-416.75 855.75,-416.75"/>
+<text xml:space="preserve" text-anchor="start" x="864.75" y="-423.5" font-family="Times,serif" font-size="14.00">0</text>
+<polygon fill="none" stroke="black" points="880.5,-416.75 880.5,-439.25 952.5,-439.25 952.5,-416.75 880.5,-416.75"/>
+<text xml:space="preserve" text-anchor="start" x="913.12" y="-423.5" font-family="Times,serif" font-size="14.00">2</text>
+<polygon fill="none" stroke="black" points="952.5,-416.75 952.5,-439.25 1017.75,-439.25 1017.75,-416.75 952.5,-416.75"/>
+<text xml:space="preserve" text-anchor="start" x="972" y="-423.5" font-family="Times,serif" font-size="14.00">u2be</text>
+<polygon fill="none" stroke="black" points="1017.75,-416.75 1017.75,-439.25 1089.75,-439.25 1089.75,-416.75 1017.75,-416.75"/>
+<text xml:space="preserve" text-anchor="start" x="1020.75" y="-423.5" font-family="Times,serif" font-size="14.00">len_payload</text>
+<polygon fill="none" stroke="black" points="855.75,-394.25 855.75,-416.75 880.5,-416.75 880.5,-394.25 855.75,-394.25"/>
+<text xml:space="preserve" text-anchor="start" x="864.75" y="-401" font-family="Times,serif" font-size="14.00">2</text>
+<polygon fill="none" stroke="black" points="880.5,-394.25 880.5,-416.75 952.5,-416.75 952.5,-394.25 880.5,-394.25"/>
+<text xml:space="preserve" text-anchor="start" x="883.5" y="-401" font-family="Times,serif" font-size="14.00">len_payload</text>
+<polygon fill="none" stroke="black" points="952.5,-394.25 952.5,-416.75 1017.75,-416.75 1017.75,-394.25 952.5,-394.25"/>
+<text xml:space="preserve" text-anchor="start" x="955.5" y="-401" font-family="Times,serif" font-size="14.00">str(UTF&#45;8)</text>
+<polygon fill="none" stroke="black" points="1017.75,-394.25 1017.75,-416.75 1089.75,-416.75 1089.75,-394.25 1017.75,-394.25"/>
+<text xml:space="preserve" text-anchor="start" x="1032.38" y="-401" font-family="Times,serif" font-size="14.00">payload</text>
+</g>
+<!-- auth__seq&#45;&gt;string__seq -->
+<g id="edge9" class="edge">
+<title>auth__seq:name_type&#45;&gt;string__seq</title>
+<path fill="none" stroke="black" stroke-width="2" d="M765,-801C911.53,-801 955.07,-578.06 967.28,-476.9"/>
+<polygon fill="black" stroke="black" stroke-width="2" points="970.58,-478.81 968.24,-468.48 963.63,-478.02 970.58,-478.81"/>
+</g>
+<!-- auth__seq&#45;&gt;string__seq -->
+<g id="edge10" class="edge">
+<title>auth__seq:pass_type&#45;&gt;string__seq</title>
+<path fill="none" stroke="black" stroke-width="2" d="M765,-778.5C903.49,-778.5 951.12,-572.98 965.83,-476.69"/>
+<polygon fill="black" stroke="black" stroke-width="2" points="969.04,-478.91 967.03,-468.5 962.12,-477.89 969.04,-478.91"/>
</g>
<!-- binary__seq -->
-<g id="node3" class="node">
+<g id="node4" class="node">
<title>binary__seq</title>
-<polygon fill="#e0ffe0" stroke="none" points="795.75,-118.25 795.75,-140.75 820.5,-140.75 820.5,-118.25 795.75,-118.25"/>
-<polygon fill="none" stroke="black" points="795.75,-118.25 795.75,-140.75 820.5,-140.75 820.5,-118.25 795.75,-118.25"/>
-<text xml:space="preserve" text-anchor="start" x="798.75" y="-125" font-family="Times,serif" font-size="14.00">pos</text>
-<polygon fill="#e0ffe0" stroke="none" points="820.5,-118.25 820.5,-140.75 892.5,-140.75 892.5,-118.25 820.5,-118.25"/>
-<polygon fill="none" stroke="black" points="820.5,-118.25 820.5,-140.75 892.5,-140.75 892.5,-118.25 820.5,-118.25"/>
-<text xml:space="preserve" text-anchor="start" x="846" y="-125" font-family="Times,serif" font-size="14.00">size</text>
-<polygon fill="#e0ffe0" stroke="none" points="892.5,-118.25 892.5,-140.75 924.75,-140.75 924.75,-118.25 892.5,-118.25"/>
-<polygon fill="none" stroke="black" points="892.5,-118.25 892.5,-140.75 924.75,-140.75 924.75,-118.25 892.5,-118.25"/>
-<text xml:space="preserve" text-anchor="start" x="897" y="-125" font-family="Times,serif" font-size="14.00">type</text>
-<polygon fill="#e0ffe0" stroke="none" points="924.75,-118.25 924.75,-140.75 996.75,-140.75 996.75,-118.25 924.75,-118.25"/>
-<polygon fill="none" stroke="black" points="924.75,-118.25 924.75,-140.75 996.75,-140.75 996.75,-118.25 924.75,-118.25"/>
-<text xml:space="preserve" text-anchor="start" x="955.5" y="-125" font-family="Times,serif" font-size="14.00">id</text>
-<polygon fill="none" stroke="black" points="795.75,-95.75 795.75,-118.25 820.5,-118.25 820.5,-95.75 795.75,-95.75"/>
-<text xml:space="preserve" text-anchor="start" x="804.75" y="-102.5" font-family="Times,serif" font-size="14.00">0</text>
-<polygon fill="none" stroke="black" points="820.5,-95.75 820.5,-118.25 892.5,-118.25 892.5,-95.75 820.5,-95.75"/>
-<text xml:space="preserve" text-anchor="start" x="853.12" y="-102.5" font-family="Times,serif" font-size="14.00">2</text>
-<polygon fill="none" stroke="black" points="892.5,-95.75 892.5,-118.25 924.75,-118.25 924.75,-95.75 892.5,-95.75"/>
-<text xml:space="preserve" text-anchor="start" x="895.5" y="-102.5" font-family="Times,serif" font-size="14.00">u2be</text>
-<polygon fill="none" stroke="black" points="924.75,-95.75 924.75,-118.25 996.75,-118.25 996.75,-95.75 924.75,-95.75"/>
-<text xml:space="preserve" text-anchor="start" x="927.75" y="-102.5" font-family="Times,serif" font-size="14.00">len_payload</text>
-<polygon fill="none" stroke="black" points="795.75,-73.25 795.75,-95.75 820.5,-95.75 820.5,-73.25 795.75,-73.25"/>
-<text xml:space="preserve" text-anchor="start" x="804.75" y="-80" font-family="Times,serif" font-size="14.00">2</text>
-<polygon fill="none" stroke="black" points="820.5,-73.25 820.5,-95.75 892.5,-95.75 892.5,-73.25 820.5,-73.25"/>
-<text xml:space="preserve" text-anchor="start" x="823.5" y="-80" font-family="Times,serif" font-size="14.00">len_payload</text>
-<polygon fill="none" stroke="black" points="892.5,-73.25 892.5,-95.75 924.75,-95.75 924.75,-73.25 892.5,-73.25"/>
-<polygon fill="none" stroke="black" points="924.75,-73.25 924.75,-95.75 996.75,-95.75 996.75,-73.25 924.75,-73.25"/>
-<text xml:space="preserve" text-anchor="start" x="939.38" y="-80" font-family="Times,serif" font-size="14.00">payload</text>
+<polygon fill="#e0ffe0" stroke="none" points="872.25,-118.25 872.25,-140.75 897,-140.75 897,-118.25 872.25,-118.25"/>
+<polygon fill="none" stroke="black" points="872.25,-118.25 872.25,-140.75 897,-140.75 897,-118.25 872.25,-118.25"/>
+<text xml:space="preserve" text-anchor="start" x="875.25" y="-125" font-family="Times,serif" font-size="14.00">pos</text>
+<polygon fill="#e0ffe0" stroke="none" points="897,-118.25 897,-140.75 969,-140.75 969,-118.25 897,-118.25"/>
+<polygon fill="none" stroke="black" points="897,-118.25 897,-140.75 969,-140.75 969,-118.25 897,-118.25"/>
+<text xml:space="preserve" text-anchor="start" x="922.5" y="-125" font-family="Times,serif" font-size="14.00">size</text>
+<polygon fill="#e0ffe0" stroke="none" points="969,-118.25 969,-140.75 1001.25,-140.75 1001.25,-118.25 969,-118.25"/>
+<polygon fill="none" stroke="black" points="969,-118.25 969,-140.75 1001.25,-140.75 1001.25,-118.25 969,-118.25"/>
+<text xml:space="preserve" text-anchor="start" x="973.5" y="-125" font-family="Times,serif" font-size="14.00">type</text>
+<polygon fill="#e0ffe0" stroke="none" points="1001.25,-118.25 1001.25,-140.75 1073.25,-140.75 1073.25,-118.25 1001.25,-118.25"/>
+<polygon fill="none" stroke="black" points="1001.25,-118.25 1001.25,-140.75 1073.25,-140.75 1073.25,-118.25 1001.25,-118.25"/>
+<text xml:space="preserve" text-anchor="start" x="1032" y="-125" font-family="Times,serif" font-size="14.00">id</text>
+<polygon fill="none" stroke="black" points="872.25,-95.75 872.25,-118.25 897,-118.25 897,-95.75 872.25,-95.75"/>
+<text xml:space="preserve" text-anchor="start" x="881.25" y="-102.5" font-family="Times,serif" font-size="14.00">0</text>
+<polygon fill="none" stroke="black" points="897,-95.75 897,-118.25 969,-118.25 969,-95.75 897,-95.75"/>
+<text xml:space="preserve" text-anchor="start" x="929.62" y="-102.5" font-family="Times,serif" font-size="14.00">2</text>
+<polygon fill="none" stroke="black" points="969,-95.75 969,-118.25 1001.25,-118.25 1001.25,-95.75 969,-95.75"/>
+<text xml:space="preserve" text-anchor="start" x="972" y="-102.5" font-family="Times,serif" font-size="14.00">u2be</text>
+<polygon fill="none" stroke="black" points="1001.25,-95.75 1001.25,-118.25 1073.25,-118.25 1073.25,-95.75 1001.25,-95.75"/>
+<text xml:space="preserve" text-anchor="start" x="1004.25" y="-102.5" font-family="Times,serif" font-size="14.00">len_payload</text>
+<polygon fill="none" stroke="black" points="872.25,-73.25 872.25,-95.75 897,-95.75 897,-73.25 872.25,-73.25"/>
+<text xml:space="preserve" text-anchor="start" x="881.25" y="-80" font-family="Times,serif" font-size="14.00">2</text>
+<polygon fill="none" stroke="black" points="897,-73.25 897,-95.75 969,-95.75 969,-73.25 897,-73.25"/>
+<text xml:space="preserve" text-anchor="start" x="900" y="-80" font-family="Times,serif" font-size="14.00">len_payload</text>
+<polygon fill="none" stroke="black" points="969,-73.25 969,-95.75 1001.25,-95.75 1001.25,-73.25 969,-73.25"/>
+<polygon fill="none" stroke="black" points="1001.25,-73.25 1001.25,-95.75 1073.25,-95.75 1073.25,-73.25 1001.25,-73.25"/>
+<text xml:space="preserve" text-anchor="start" x="1015.88" y="-80" font-family="Times,serif" font-size="14.00">payload</text>
</g>
<!-- binary__seq&#45;&gt;binary__seq -->
-<g id="edge8" class="edge">
+<g id="edge11" class="edge">
<title>binary__seq:len_payload_type&#45;&gt;binary__seq:payload_size</title>
-<path fill="none" stroke="#404040" d="M988.57,-118.22C1021.8,-137.5 1004.88,-162.75 908.62,-162.75 818.74,-162.75 798.04,-127.4 822.76,-102.64"/>
-<polygon fill="#404040" stroke="#404040" points="824.63,-105.63 830.2,-96.62 820.23,-100.19 824.63,-105.63"/>
-</g>
-<!-- string__seq -->
-<g id="node8" class="node">
-<title>string__seq</title>
-<polygon fill="#e0ffe0" stroke="none" points="779.25,-496.25 779.25,-518.75 804,-518.75 804,-496.25 779.25,-496.25"/>
-<polygon fill="none" stroke="black" points="779.25,-496.25 779.25,-518.75 804,-518.75 804,-496.25 779.25,-496.25"/>
-<text xml:space="preserve" text-anchor="start" x="782.25" y="-503" font-family="Times,serif" font-size="14.00">pos</text>
-<polygon fill="#e0ffe0" stroke="none" points="804,-496.25 804,-518.75 876,-518.75 876,-496.25 804,-496.25"/>
-<polygon fill="none" stroke="black" points="804,-496.25 804,-518.75 876,-518.75 876,-496.25 804,-496.25"/>
-<text xml:space="preserve" text-anchor="start" x="829.5" y="-503" font-family="Times,serif" font-size="14.00">size</text>
-<polygon fill="#e0ffe0" stroke="none" points="876,-496.25 876,-518.75 941.25,-518.75 941.25,-496.25 876,-496.25"/>
-<polygon fill="none" stroke="black" points="876,-496.25 876,-518.75 941.25,-518.75 941.25,-496.25 876,-496.25"/>
-<text xml:space="preserve" text-anchor="start" x="897" y="-503" font-family="Times,serif" font-size="14.00">type</text>
-<polygon fill="#e0ffe0" stroke="none" points="941.25,-496.25 941.25,-518.75 1013.25,-518.75 1013.25,-496.25 941.25,-496.25"/>
-<polygon fill="none" stroke="black" points="941.25,-496.25 941.25,-518.75 1013.25,-518.75 1013.25,-496.25 941.25,-496.25"/>
-<text xml:space="preserve" text-anchor="start" x="972" y="-503" font-family="Times,serif" font-size="14.00">id</text>
-<polygon fill="none" stroke="black" points="779.25,-473.75 779.25,-496.25 804,-496.25 804,-473.75 779.25,-473.75"/>
-<text xml:space="preserve" text-anchor="start" x="788.25" y="-480.5" font-family="Times,serif" font-size="14.00">0</text>
-<polygon fill="none" stroke="black" points="804,-473.75 804,-496.25 876,-496.25 876,-473.75 804,-473.75"/>
-<text xml:space="preserve" text-anchor="start" x="836.62" y="-480.5" font-family="Times,serif" font-size="14.00">2</text>
-<polygon fill="none" stroke="black" points="876,-473.75 876,-496.25 941.25,-496.25 941.25,-473.75 876,-473.75"/>
-<text xml:space="preserve" text-anchor="start" x="895.5" y="-480.5" font-family="Times,serif" font-size="14.00">u2be</text>
-<polygon fill="none" stroke="black" points="941.25,-473.75 941.25,-496.25 1013.25,-496.25 1013.25,-473.75 941.25,-473.75"/>
-<text xml:space="preserve" text-anchor="start" x="944.25" y="-480.5" font-family="Times,serif" font-size="14.00">len_payload</text>
-<polygon fill="none" stroke="black" points="779.25,-451.25 779.25,-473.75 804,-473.75 804,-451.25 779.25,-451.25"/>
-<text xml:space="preserve" text-anchor="start" x="788.25" y="-458" font-family="Times,serif" font-size="14.00">2</text>
-<polygon fill="none" stroke="black" points="804,-451.25 804,-473.75 876,-473.75 876,-451.25 804,-451.25"/>
-<text xml:space="preserve" text-anchor="start" x="807" y="-458" font-family="Times,serif" font-size="14.00">len_payload</text>
-<polygon fill="none" stroke="black" points="876,-451.25 876,-473.75 941.25,-473.75 941.25,-451.25 876,-451.25"/>
-<text xml:space="preserve" text-anchor="start" x="879" y="-458" font-family="Times,serif" font-size="14.00">str(UTF&#45;8)</text>
-<polygon fill="none" stroke="black" points="941.25,-451.25 941.25,-473.75 1013.25,-473.75 1013.25,-451.25 941.25,-451.25"/>
-<text xml:space="preserve" text-anchor="start" x="955.88" y="-458" font-family="Times,serif" font-size="14.00">payload</text>
+<path fill="none" stroke="#404040" d="M1066.54,-118.22C1101.57,-137.5 1084.16,-162.75 985.12,-162.75 892.64,-162.75 871.34,-127.4 897.46,-102.64"/>
+<polygon fill="#404040" stroke="#404040" points="899.55,-105.45 905.36,-96.59 895.29,-99.9 899.55,-105.45"/>
</g>
<!-- message__seq&#45;&gt;string__seq -->
-<g id="edge9" class="edge">
+<g id="edge12" class="edge">
<title>message__seq:source_type&#45;&gt;string__seq</title>
-<path fill="none" stroke="black" stroke-width="2" d="M715.88,-552.5C751.15,-552.5 787.97,-540.92 819.01,-527.36"/>
-<polygon fill="black" stroke="black" stroke-width="2" points="818.88,-531.26 826.54,-523.95 815.99,-524.88 818.88,-531.26"/>
+<path fill="none" stroke="black" stroke-width="2" d="M778.88,-450.5C797.55,-450.5 817.16,-449.45 836.45,-447.8"/>
+<polygon fill="black" stroke="black" stroke-width="2" points="835.1,-451.44 844.74,-447.04 834.46,-444.46 835.1,-451.44"/>
</g>
<!-- message__seq&#45;&gt;string__seq -->
-<g id="edge10" class="edge">
+<g id="edge13" class="edge">
<title>message__seq:target_type&#45;&gt;string__seq</title>
-<path fill="none" stroke="black" stroke-width="2" d="M715.88,-530C733.21,-530 751.21,-528 768.82,-524.84"/>
-<polygon fill="black" stroke="black" stroke-width="2" points="767.91,-528.58 777.06,-523.25 766.57,-521.71 767.91,-528.58"/>
+<path fill="none" stroke="black" stroke-width="2" d="M778.88,-428C797.49,-428 817.11,-428 836.43,-428"/>
+<polygon fill="black" stroke="black" stroke-width="2" points="834.74,-431.5 844.74,-428 834.74,-424.5 834.74,-431.5"/>
</g>
<!-- message__seq&#45;&gt;string__seq -->
-<g id="edge11" class="edge">
+<g id="edge14" class="edge">
<title>message__seq:content_type&#45;&gt;string__seq</title>
-<path fill="none" stroke="black" stroke-width="2" d="M715.88,-485C730.14,-485 745.05,-485 759.91,-485"/>
-<polygon fill="black" stroke="black" stroke-width="2" points="758.23,-488.5 768.23,-485 758.23,-481.5 758.23,-488.5"/>
+<path fill="none" stroke="black" stroke-width="2" d="M778.88,-383C797.77,-383 817.45,-385.07 836.69,-388.33"/>
+<polygon fill="black" stroke="black" stroke-width="2" points="834.52,-391.5 844.99,-389.84 835.78,-384.61 834.52,-391.5"/>
</g>
<!-- string__seq&#45;&gt;string__seq -->
-<g id="edge12" class="edge">
+<g id="edge15" class="edge">
<title>string__seq:len_payload_type&#45;&gt;string__seq:payload_size</title>
-<path fill="none" stroke="#404040" d="M1004.98,-496.22C1037.79,-515.5 1018.48,-540.75 908.62,-540.75 806.48,-540.75 782.62,-505.7 806.15,-480.96"/>
-<polygon fill="#404040" stroke="#404040" points="808.32,-483.71 813.78,-474.63 803.85,-478.33 808.32,-483.71"/>
+<path fill="none" stroke="#404040" d="M1082.95,-439.22C1117.56,-458.5 1097.76,-483.75 985.12,-483.75 879.94,-483.75 855.72,-448.4 881.16,-423.64"/>
+<polygon fill="#404040" stroke="#404040" points="883.19,-426.5 888.93,-417.6 878.89,-420.98 883.19,-426.5"/>
</g>
<!-- test__seq&#45;&gt;binary__seq -->
-<g id="edge14" class="edge">
+<g id="edge17" class="edge">
<title>test__seq:bin1_type&#45;&gt;binary__seq</title>
-<path fill="none" stroke="black" stroke-width="2" d="M704.62,-106.5C727.91,-106.5 752.79,-106.54 776.64,-106.59"/>
-<polygon fill="black" stroke="black" stroke-width="2" points="774.85,-110.09 784.85,-106.61 774.86,-103.09 774.85,-110.09"/>
+<path fill="none" stroke="black" stroke-width="2" d="M767.62,-106.5C795.27,-106.5 825.02,-106.55 853.02,-106.61"/>
+<polygon fill="black" stroke="black" stroke-width="2" points="851.45,-110.11 861.46,-106.63 851.47,-103.11 851.45,-110.11"/>
</g>
<!-- test__seq&#45;&gt;string__seq -->
-<g id="edge13" class="edge">
+<g id="edge16" class="edge">
<title>test__seq:str1_type&#45;&gt;string__seq</title>
-<path fill="none" stroke="black" stroke-width="2" d="M704.62,-151.5C737.13,-151.5 830.71,-344.97 873.47,-437.2"/>
-<polygon fill="black" stroke="black" stroke-width="2" points="869.54,-437.03 876.91,-444.64 875.89,-434.1 869.54,-437.03"/>
+<path fill="none" stroke="black" stroke-width="2" d="M767.62,-151.5C823.8,-151.5 907.77,-301.09 948.26,-380.21"/>
+<polygon fill="black" stroke="black" stroke-width="2" points="944.42,-380.39 952.07,-387.72 950.67,-377.22 944.42,-380.39"/>
</g>
<!-- test__seq&#45;&gt;string__seq -->
-<g id="edge15" class="edge">
+<g id="edge18" class="edge">
<title>test__seq:str2_type&#45;&gt;string__seq</title>
-<path fill="none" stroke="black" stroke-width="2" d="M704.62,-61.5C771.06,-61.5 736.3,-138.28 763.25,-199 800.74,-283.46 846.25,-381.04 872.86,-437.61"/>
-<polygon fill="black" stroke="black" stroke-width="2" points="868.89,-437.39 876.31,-444.94 875.22,-434.4 868.89,-437.39"/>
+<path fill="none" stroke="black" stroke-width="2" d="M767.62,-61.5C836.63,-61.5 806.48,-138.54 839.75,-199 874.68,-262.49 916.74,-334.79 943.85,-380.87"/>
+<polygon fill="black" stroke="black" stroke-width="2" points="939.94,-381.13 948.03,-387.97 945.97,-377.57 939.94,-381.13"/>
</g>
</g>
</svg>
diff --git a/build_spec.sh b/tools/build_spec.sh
index dfebbd2..dfebbd2 100755
--- a/build_spec.sh
+++ b/tools/build_spec.sh
diff --git a/tools/run.sh b/tools/run.sh
new file mode 100755
index 0000000..dbe0bf0
--- /dev/null
+++ b/tools/run.sh
@@ -0,0 +1,8 @@
+#!/bin/sh
+
+tmux \
+ new-session "go run cmd/daemon/main.go; read" \; \
+ split-window "sleep 0.5; go run cmd/client/main.go -u user1; read" \; \
+ split-window "sleep 0.5; go run cmd/client/main.go -u user2; read" \; \
+ split-window "sleep 0.5; go run cmd/client/main.go -u user3; read" \; \
+ select-layout tiled; \ No newline at end of file