summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorbt <bt@rctt.net>2026-03-10 14:11:01 +0100
committerbt <bt@rctt.net>2026-03-10 14:11:01 +0100
commite5644d24c51634c0e263a758bd57b797d5949c9c (patch)
tree5f6f33ebb064df45693fc75e0d454f0f11ce4654
parent6dcbb66fcafce3da6d7c00d9679946b77f6f6186 (diff)
downloadsolec-e5644d24c51634c0e263a758bd57b797d5949c9c.tar.gz
solec-e5644d24c51634c0e263a758bd57b797d5949c9c.zip
Use Kaitai to describe protocol spec, autogenerate Wireshark plugin and diagram
-rw-r--r--README.md8
-rwxr-xr-xbuild_spec.sh22
-rwxr-xr-xrun.sh2
-rw-r--r--solec.ksy59
-rw-r--r--solec.lua179
-rw-r--r--solec.svg277
6 files changed, 515 insertions, 32 deletions
diff --git a/README.md b/README.md
index 39f7571..24cb6c3 100644
--- a/README.md
+++ b/README.md
@@ -10,6 +10,14 @@ cd solecd
go run cmd/daemon/main.go
```
+## 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
+it into Wireshark plugins directory.
+
## TODO
- Protocol
diff --git a/build_spec.sh b/build_spec.sh
new file mode 100755
index 0000000..ae78b81
--- /dev/null
+++ b/build_spec.sh
@@ -0,0 +1,22 @@
+#!/bin/sh
+
+if [[ "$OSTYPE" == "darwin"* ]]; then
+ SED=gsed
+else
+ SED=sed
+fi
+
+kaitai-struct-compiler -t graphviz solec.ksy
+dot -Tsvg solec.dot > solec.svg
+rm solec.dot
+
+~/bin/kaitai-struct-compiler-ws/bin/kaitai-struct-compiler -t wireshark --read-pos solec.ksy
+
+${SED} -i -e '5s/.*/package.path = "kaitai_struct_lua_runtime\/?.lua" .. package.path/' solec.lua
+${SED} -i -e 's/, self.payload_type//' solec.lua
+
+cat <<EOT >> solec.lua
+local tcp_port = DissectorTable.get("tcp.port")
+tcp_port:add(9999, proto)
+EOT
+
diff --git a/run.sh b/run.sh
index 4f4d96f..a33fad9 100755
--- a/run.sh
+++ b/run.sh
@@ -2,5 +2,5 @@
tmux \
new-session "go run cmd/daemon/main.go; read" \; \
- split-window "go run cmd/client/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/solec.ksy b/solec.ksy
new file mode 100644
index 0000000..01c7481
--- /dev/null
+++ b/solec.ksy
@@ -0,0 +1,59 @@
+meta:
+ id: solec
+ file-extension: hex
+ endian: be
+
+enums:
+ type:
+ 0x01: handshake
+ 0x02: ping
+ 0x03: pong
+ 0x04: message
+ 0xFF: test
+
+seq:
+ - id: payload_type
+ type: u1
+ enum: type
+ - id: payload_length
+ type: u2
+ - id: payload
+ type:
+ switch-on: payload_type
+ cases:
+ 'type::test': test
+
+types:
+ string:
+ seq:
+ - id: len_payload
+ type: u2
+ - id: payload
+ type: str
+ size: len_payload
+ encoding: UTF-8
+ binary:
+ seq:
+ - id: len_payload
+ type: u2
+ - id: payload
+ size: len_payload
+ test:
+ seq:
+ - id: num1
+ type: u1
+ - id: time1
+ type: u8
+ - id: str1
+ type: string
+ - id: num2
+ type: u2
+ - id: bin1
+ type: binary
+ - id: num3
+ type: u4
+ - id: str2
+ type: string
+ - id: num4
+ type: u8
+
diff --git a/solec.lua b/solec.lua
index a367358..f48831b 100644
--- a/solec.lua
+++ b/solec.lua
@@ -1,43 +1,160 @@
--- Wireshark plugin
--- Use following filter: _ws.col.protocol == "SOLEC"
+-- This is a generated file! Please edit source .ksy file and use kaitai-struct-compiler to rebuild
+--
+-- This file is compatible with Lua 5.3
-solec = Proto("SOLEC", "SOLEC Protocol")
+package.path = "kaitai_struct_lua_runtime/?.lua" .. package.path
+local class = require("class")
+require("tvbstream")
+require("kaitaistruct")
+local proto = Proto('solec', 'Solec')
+proto.fields = {}
+local enum = require("enum")
+local Solec_payload_type = ProtoField.new('payload_type', 'Solec.payload_type', ftypes.BYTES)
+table.insert(proto.fields, Solec_payload_type)
+local Solec_payload_length = ProtoField.new('payload_length', 'Solec.payload_length', ftypes.UINT32)
+table.insert(proto.fields, Solec_payload_length)
+local Solec_String_len_payload = ProtoField.new('len_payload', 'Solec.String.len_payload', ftypes.UINT32)
+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_Binary_len_payload = ProtoField.new('len_payload', 'Solec.Binary.len_payload', ftypes.UINT32)
+table.insert(proto.fields, Solec_Binary_len_payload)
+local Solec_Binary_payload = ProtoField.new('payload', 'Solec.Binary.payload', ftypes.BYTES)
+table.insert(proto.fields, Solec_Binary_payload)
+local Solec_Test_num1 = ProtoField.new('num1', 'Solec.Test.num1', ftypes.UINT8)
+table.insert(proto.fields, Solec_Test_num1)
+local Solec_Test_time1 = ProtoField.new('time1', 'Solec.Test.time1', ftypes.UINT32)
+table.insert(proto.fields, Solec_Test_time1)
+local Solec_Test_num2 = ProtoField.new('num2', 'Solec.Test.num2', ftypes.UINT32)
+table.insert(proto.fields, Solec_Test_num2)
+local Solec_Test_num3 = ProtoField.new('num3', 'Solec.Test.num3', ftypes.UINT32)
+table.insert(proto.fields, Solec_Test_num3)
+local Solec_Test_num4 = ProtoField.new('num4', 'Solec.Test.num4', ftypes.UINT32)
+table.insert(proto.fields, Solec_Test_num4)
-s_datatype = ProtoField.uint8("solec.datatype", "Datatype", base.HEX, {
- [0x01] = "handshake",
- [0x02] = "ping",
- [0x03] = "pong",
- [0x04] = "message",
- [0xFF] = "test",
-})
+function proto.dissector(tvb, pinfo, root)
+ pinfo.cols.protocol = 'Solec'
+ local tree = root:add(proto, tvb(), 'Solec')
+ local io = KaitaiStream(TVBStream(tvb))
+ local obj = Solec(io, tree)
+end
+
+Solec = class.class(KaitaiStruct)
+
+Solec.Type = enum.Enum {
+ handshake = 1,
+ ping = 2,
+ pong = 3,
+ message = 4,
+ test = 255,
+}
+
+function Solec:_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:_read()
+ local _offset = self._io:pos()
+ self.payload_type = Solec.Type(self._io:read_u1())
+ self._tree:add(Solec_payload_type, self._io._io.tvb(_offset, self._io:pos() - _offset))
+ local _offset = self._io:pos()
+ self.payload_length = self._io:read_u2be()
+ self._tree:add(Solec_payload_length, self._io._io.tvb(_offset, self._io:pos() - _offset), self.payload_length)
+ local _offset = self._io:pos()
+ local _on = self.payload_type
+ if _on == Solec.Type.test then
+ local _tree = self._tree:add(self._io._io.tvb(_offset, 0), 'payload')
+ self.payload = Solec.Test(self._io, _tree, self, self._root)
+ _tree:set_len(self._io:pos() - _offset)
+ end
+end
+
+
+Solec.String = class.class(KaitaiStruct)
-s_handshake_version = ProtoField.uint8("solec.handshake.version", "Protocol version", base.HEX)
-s_pong_timestamp = ProtoField.uint64("solec.pong.timestamp", "Timestamp", base.DEC)
+function Solec.String:_init(io, tree, parent, root)
+ KaitaiStruct._init(self, io)
+ self._parent = parent
+ self._root = root or self
+ self._tree = tree
+ self:_read()
+end
-solec.fields = { s_datatype, s_handshake_version, s_pong_timestamp }
+function Solec.String:_read()
+ local _offset = self._io:pos()
+ self.len_payload = self._io:read_u2be()
+ self._tree:add(Solec_String_len_payload, self._io._io.tvb(_offset, self._io:pos() - _offset), self.len_payload)
+ local _offset = self._io:pos()
+ self.payload = str_decode.decode(self._io:read_bytes(self.len_payload), "UTF-8")
+ self._tree:add(Solec_String_payload, self._io._io.tvb(_offset, self._io:pos() - _offset), self.payload)
+end
-function solec.dissector(buffer, pinfo, tree)
- length = buffer:len()
- if length == 0 then
- return
- end
- pinfo.cols.protocol = solec.name
+Solec.Binary = class.class(KaitaiStruct)
- local subtree = tree:add(solec, buffer(), "SOLEC Protocol Data")
- local dtype = buffer(0,1):uint()
+function Solec.Binary:_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.Binary:_read()
+ local _offset = self._io:pos()
+ self.len_payload = self._io:read_u2be()
+ self._tree:add(Solec_Binary_len_payload, self._io._io.tvb(_offset, self._io:pos() - _offset), self.len_payload)
+ local _offset = self._io:pos()
+ self.payload = self._io:read_bytes(self.len_payload)
+ self._tree:add(Solec_Binary_payload, self._io._io.tvb(_offset, self._io:pos() - _offset), self.payload)
+end
- subtree:add_le(s_datatype, dtype)
- if dtype == 01 then
- local subtree = tree:add(solec, buffer(), "Handshake")
- subtree:add_le(s_handshake_version, buffer(1, 1):uint())
- elseif dtype == 0x03 then
- local subtree = tree:add(solec, buffer(), "Pong")
- local timestamp = buffer(1, 8):uint64()
- subtree:add(s_pong_timestamp, timestamp):append_text(" (" .. os.date('%Y/%m/%d %X', tonumber(timestamp)) .. ")")
- end
+Solec.Test = class.class(KaitaiStruct)
+
+function Solec.Test:_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.Test:_read()
+ local _offset = self._io:pos()
+ self.num1 = self._io:read_u1()
+ self._tree:add(Solec_Test_num1, self._io._io.tvb(_offset, self._io:pos() - _offset), self.num1)
+ local _offset = self._io:pos()
+ self.time1 = self._io:read_u8be()
+ self._tree:add(Solec_Test_time1, self._io._io.tvb(_offset, self._io:pos() - _offset), self.time1)
+ local _offset = self._io:pos()
+ local _tree = self._tree:add(self._io._io.tvb(_offset, 0), 'str1')
+ self.str1 = Solec.String(self._io, _tree, self, self._root)
+ _tree:set_len(self._io:pos() - _offset)
+ local _offset = self._io:pos()
+ self.num2 = self._io:read_u2be()
+ self._tree:add(Solec_Test_num2, self._io._io.tvb(_offset, self._io:pos() - _offset), self.num2)
+ local _offset = self._io:pos()
+ local _tree = self._tree:add(self._io._io.tvb(_offset, 0), 'bin1')
+ self.bin1 = Solec.Binary(self._io, _tree, self, self._root)
+ _tree:set_len(self._io:pos() - _offset)
+ local _offset = self._io:pos()
+ self.num3 = self._io:read_u4be()
+ self._tree:add(Solec_Test_num3, self._io._io.tvb(_offset, self._io:pos() - _offset), self.num3)
+ local _offset = self._io:pos()
+ local _tree = self._tree:add(self._io._io.tvb(_offset, 0), 'str2')
+ self.str2 = Solec.String(self._io, _tree, self, self._root)
+ _tree:set_len(self._io:pos() - _offset)
+ local _offset = self._io:pos()
+ self.num4 = self._io:read_u8be()
+ self._tree:add(Solec_Test_num4, self._io._io.tvb(_offset, self._io:pos() - _offset), self.num4)
end
+
local tcp_port = DissectorTable.get("tcp.port")
-tcp_port:add(9999, solec)
+tcp_port:add(9999, proto)
diff --git a/solec.svg b/solec.svg
new file mode 100644
index 0000000..30b2ba8
--- /dev/null
+++ b/solec.svg
@@ -0,0 +1,277 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
+ "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<!-- Generated by graphviz version 14.1.3 (20260303.0454)
+ -->
+<!-- Pages: 1 -->
+<svg width="942pt" height="341pt"
+ viewBox="0.00 0.00 942.00 341.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 337)">
+<polygon fill="white" stroke="none" points="-4,4 -4,-337 937.5,-337 937.5,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,-325 925.5,-325 925.5,-8 8,-8"/>
+<text xml:space="preserve" text-anchor="middle" x="466.75" y="-307.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="668,-16 668,-150 901,-150 901,-16 668,-16"/>
+<text xml:space="preserve" text-anchor="middle" x="784.5" y="-132.7" font-family="Times,serif" font-size="14.00">Solec::Binary</text>
+</g>
+<g id="clust3" class="cluster">
+<title>cluster__string</title>
+<polygon fill="none" stroke="black" stroke-dasharray="1,5" points="651.5,-158 651.5,-292 917.5,-292 917.5,-158 651.5,-158"/>
+<text xml:space="preserve" text-anchor="middle" x="784.5" y="-274.7" font-family="Times,serif" font-size="14.00">Solec::String</text>
+</g>
+<g id="clust4" class="cluster">
+<title>cluster__test</title>
+<polygon fill="none" stroke="black" stroke-dasharray="1,5" points="467.5,-41 467.5,-292 631.5,-292 631.5,-41 467.5,-41"/>
+<text xml:space="preserve" text-anchor="middle" x="549.5" y="-274.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,-220.5 24,-243 48.75,-243 48.75,-220.5 24,-220.5"/>
+<polygon fill="none" stroke="black" points="24,-220.5 24,-243 48.75,-243 48.75,-220.5 24,-220.5"/>
+<text xml:space="preserve" text-anchor="start" x="27" y="-227.25" font-family="Times,serif" font-size="14.00">pos</text>
+<polygon fill="#e0ffe0" stroke="none" points="48.75,-220.5 48.75,-243 75.75,-243 75.75,-220.5 48.75,-220.5"/>
+<polygon fill="none" stroke="black" points="48.75,-220.5 48.75,-243 75.75,-243 75.75,-220.5 48.75,-220.5"/>
+<text xml:space="preserve" text-anchor="start" x="51.75" y="-227.25" font-family="Times,serif" font-size="14.00">size</text>
+<polygon fill="#e0ffe0" stroke="none" points="75.75,-220.5 75.75,-243 202.5,-243 202.5,-220.5 75.75,-220.5"/>
+<polygon fill="none" stroke="black" points="75.75,-220.5 75.75,-243 202.5,-243 202.5,-220.5 75.75,-220.5"/>
+<text xml:space="preserve" text-anchor="start" x="127.5" y="-227.25" font-family="Times,serif" font-size="14.00">type</text>
+<polygon fill="#e0ffe0" stroke="none" points="202.5,-220.5 202.5,-243 291.75,-243 291.75,-220.5 202.5,-220.5"/>
+<polygon fill="none" stroke="black" points="202.5,-220.5 202.5,-243 291.75,-243 291.75,-220.5 202.5,-220.5"/>
+<text xml:space="preserve" text-anchor="start" x="241.88" y="-227.25" font-family="Times,serif" font-size="14.00">id</text>
+<polygon fill="none" stroke="black" points="24,-198 24,-220.5 48.75,-220.5 48.75,-198 24,-198"/>
+<text xml:space="preserve" text-anchor="start" x="33" y="-204.75" font-family="Times,serif" font-size="14.00">0</text>
+<polygon fill="none" stroke="black" points="48.75,-198 48.75,-220.5 75.75,-220.5 75.75,-198 48.75,-198"/>
+<text xml:space="preserve" text-anchor="start" x="58.88" y="-204.75" font-family="Times,serif" font-size="14.00">1</text>
+<polygon fill="none" stroke="black" points="75.75,-198 75.75,-220.5 202.5,-220.5 202.5,-198 75.75,-198"/>
+<text xml:space="preserve" text-anchor="start" x="111.38" y="-204.75" font-family="Times,serif" font-size="14.00">u1→Type</text>
+<polygon fill="none" stroke="black" points="202.5,-198 202.5,-220.5 291.75,-220.5 291.75,-198 202.5,-198"/>
+<text xml:space="preserve" text-anchor="start" x="210.75" y="-204.75" font-family="Times,serif" font-size="14.00">payload_type</text>
+<polygon fill="none" stroke="black" points="24,-175.5 24,-198 48.75,-198 48.75,-175.5 24,-175.5"/>
+<text xml:space="preserve" text-anchor="start" x="33" y="-182.25" font-family="Times,serif" font-size="14.00">1</text>
+<polygon fill="none" stroke="black" points="48.75,-175.5 48.75,-198 75.75,-198 75.75,-175.5 48.75,-175.5"/>
+<text xml:space="preserve" text-anchor="start" x="58.88" y="-182.25" font-family="Times,serif" font-size="14.00">2</text>
+<polygon fill="none" stroke="black" points="75.75,-175.5 75.75,-198 202.5,-198 202.5,-175.5 75.75,-175.5"/>
+<text xml:space="preserve" text-anchor="start" x="126" y="-182.25" font-family="Times,serif" font-size="14.00">u2be</text>
+<polygon fill="none" stroke="black" points="202.5,-175.5 202.5,-198 291.75,-198 291.75,-175.5 202.5,-175.5"/>
+<text xml:space="preserve" text-anchor="start" x="205.5" y="-182.25" font-family="Times,serif" font-size="14.00">payload_length</text>
+<polygon fill="none" stroke="black" points="24,-153 24,-175.5 48.75,-175.5 48.75,-153 24,-153"/>
+<text xml:space="preserve" text-anchor="start" x="33" y="-159.75" font-family="Times,serif" font-size="14.00">3</text>
+<polygon fill="none" stroke="black" points="48.75,-153 48.75,-175.5 75.75,-175.5 75.75,-153 48.75,-153"/>
+<text xml:space="preserve" text-anchor="start" x="56.62" y="-159.75" font-family="Times,serif" font-size="14.00">...</text>
+<polygon fill="none" stroke="black" points="75.75,-153 75.75,-175.5 202.5,-175.5 202.5,-153 75.75,-153"/>
+<text xml:space="preserve" text-anchor="start" x="78.75" y="-159.75" font-family="Times,serif" font-size="14.00">switch (payload_type)</text>
+<polygon fill="none" stroke="black" points="202.5,-153 202.5,-175.5 291.75,-175.5 291.75,-153 202.5,-153"/>
+<text xml:space="preserve" text-anchor="start" x="225.75" y="-159.75" font-family="Times,serif" font-size="14.00">payload</text>
+</g>
+<!-- solec__seq&#45;&gt;solec__seq -->
+<g id="edge3" class="edge">
+<title>solec__seq:payload_type_type&#45;&gt;solec__seq:payload_type</title>
+<path fill="none" stroke="#404040" d="M224.41,-220.36C191.09,-241.21 198.66,-265 247.12,-265 293.05,-265 302.26,-214.86 274.73,-183.35"/>
+<polygon fill="#404040" stroke="#404040" points="277.2,-180.86 267.56,-176.44 272.34,-185.9 277.2,-180.86"/>
+</g>
+<!-- solec__seq_payload_switch -->
+<g id="node2" class="node">
+<title>solec__seq_payload_switch</title>
+<polygon fill="#f0f2e4" stroke="none" points="343.75,-165 343.75,-187.5 402.25,-187.5 402.25,-165 343.75,-165"/>
+<polygon fill="none" stroke="black" points="343.75,-165 343.75,-187.5 402.25,-187.5 402.25,-165 343.75,-165"/>
+<text xml:space="preserve" text-anchor="start" x="361.38" y="-171.75" font-family="Times,serif" font-size="14.00">case</text>
+<polygon fill="#f0f2e4" stroke="none" points="402.25,-165 402.25,-187.5 431.5,-187.5 431.5,-165 402.25,-165"/>
+<polygon fill="none" stroke="black" points="402.25,-165 402.25,-187.5 431.5,-187.5 431.5,-165 402.25,-165"/>
+<text xml:space="preserve" text-anchor="start" x="405.25" y="-171.75" font-family="Times,serif" font-size="14.00">type</text>
+<polygon fill="none" stroke="black" points="343.75,-142.5 343.75,-165 402.25,-165 402.25,-142.5 343.75,-142.5"/>
+<text xml:space="preserve" text-anchor="start" x="346.75" y="-149.25" font-family="Times,serif" font-size="14.00">:type_test</text>
+<polygon fill="none" stroke="black" points="402.25,-142.5 402.25,-165 431.5,-165 431.5,-142.5 402.25,-142.5"/>
+<text xml:space="preserve" text-anchor="start" x="405.25" y="-149.25" 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="M292.75,-164.25C303.04,-164.25 313.97,-164.3 324.59,-164.36"/>
+<polygon fill="black" stroke="black" stroke-width="2" points="322.91,-167.85 332.93,-164.43 322.96,-160.85 322.91,-167.85"/>
+</g>
+<!-- test__seq -->
+<g id="node5" class="node">
+<title>test__seq</title>
+<polygon fill="#e0ffe0" stroke="none" points="483.5,-232.75 483.5,-255.25 508.25,-255.25 508.25,-232.75 483.5,-232.75"/>
+<polygon fill="none" stroke="black" points="483.5,-232.75 483.5,-255.25 508.25,-255.25 508.25,-232.75 483.5,-232.75"/>
+<text xml:space="preserve" text-anchor="start" x="486.5" y="-239.5" font-family="Times,serif" font-size="14.00">pos</text>
+<polygon fill="#e0ffe0" stroke="none" points="508.25,-232.75 508.25,-255.25 535.25,-255.25 535.25,-232.75 508.25,-232.75"/>
+<polygon fill="none" stroke="black" points="508.25,-232.75 508.25,-255.25 535.25,-255.25 535.25,-232.75 508.25,-232.75"/>
+<text xml:space="preserve" text-anchor="start" x="511.25" y="-239.5" font-family="Times,serif" font-size="14.00">size</text>
+<polygon fill="#e0ffe0" stroke="none" points="535.25,-232.75 535.25,-255.25 578,-255.25 578,-232.75 535.25,-232.75"/>
+<polygon fill="none" stroke="black" points="535.25,-232.75 535.25,-255.25 578,-255.25 578,-232.75 535.25,-232.75"/>
+<text xml:space="preserve" text-anchor="start" x="545" y="-239.5" font-family="Times,serif" font-size="14.00">type</text>
+<polygon fill="#e0ffe0" stroke="none" points="578,-232.75 578,-255.25 615.5,-255.25 615.5,-232.75 578,-232.75"/>
+<polygon fill="none" stroke="black" points="578,-232.75 578,-255.25 615.5,-255.25 615.5,-232.75 578,-232.75"/>
+<text xml:space="preserve" text-anchor="start" x="591.5" y="-239.5" font-family="Times,serif" font-size="14.00">id</text>
+<polygon fill="none" stroke="black" points="483.5,-210.25 483.5,-232.75 508.25,-232.75 508.25,-210.25 483.5,-210.25"/>
+<text xml:space="preserve" text-anchor="start" x="492.5" y="-217" font-family="Times,serif" font-size="14.00">0</text>
+<polygon fill="none" stroke="black" points="508.25,-210.25 508.25,-232.75 535.25,-232.75 535.25,-210.25 508.25,-210.25"/>
+<text xml:space="preserve" text-anchor="start" x="518.38" y="-217" font-family="Times,serif" font-size="14.00">1</text>
+<polygon fill="none" stroke="black" points="535.25,-210.25 535.25,-232.75 578,-232.75 578,-210.25 535.25,-210.25"/>
+<text xml:space="preserve" text-anchor="start" x="549.88" y="-217" font-family="Times,serif" font-size="14.00">u1</text>
+<polygon fill="none" stroke="black" points="578,-210.25 578,-232.75 615.5,-232.75 615.5,-210.25 578,-210.25"/>
+<text xml:space="preserve" text-anchor="start" x="581" y="-217" font-family="Times,serif" font-size="14.00">num1</text>
+<polygon fill="none" stroke="black" points="483.5,-187.75 483.5,-210.25 508.25,-210.25 508.25,-187.75 483.5,-187.75"/>
+<text xml:space="preserve" text-anchor="start" x="492.5" y="-194.5" font-family="Times,serif" font-size="14.00">1</text>
+<polygon fill="none" stroke="black" points="508.25,-187.75 508.25,-210.25 535.25,-210.25 535.25,-187.75 508.25,-187.75"/>
+<text xml:space="preserve" text-anchor="start" x="518.38" y="-194.5" font-family="Times,serif" font-size="14.00">8</text>
+<polygon fill="none" stroke="black" points="535.25,-187.75 535.25,-210.25 578,-210.25 578,-187.75 535.25,-187.75"/>
+<text xml:space="preserve" text-anchor="start" x="543.5" y="-194.5" font-family="Times,serif" font-size="14.00">u8be</text>
+<polygon fill="none" stroke="black" points="578,-187.75 578,-210.25 615.5,-210.25 615.5,-187.75 578,-187.75"/>
+<text xml:space="preserve" text-anchor="start" x="581" y="-194.5" font-family="Times,serif" font-size="14.00">time1</text>
+<polygon fill="none" stroke="black" points="483.5,-165.25 483.5,-187.75 508.25,-187.75 508.25,-165.25 483.5,-165.25"/>
+<text xml:space="preserve" text-anchor="start" x="492.5" y="-172" font-family="Times,serif" font-size="14.00">9</text>
+<polygon fill="none" stroke="black" points="508.25,-165.25 508.25,-187.75 535.25,-187.75 535.25,-165.25 508.25,-165.25"/>
+<text xml:space="preserve" text-anchor="start" x="516.12" y="-172" font-family="Times,serif" font-size="14.00">...</text>
+<polygon fill="none" stroke="black" points="535.25,-165.25 535.25,-187.75 578,-187.75 578,-165.25 535.25,-165.25"/>
+<text xml:space="preserve" text-anchor="start" x="540.12" y="-172" font-family="Times,serif" font-size="14.00">String</text>
+<polygon fill="none" stroke="black" points="578,-165.25 578,-187.75 615.5,-187.75 615.5,-165.25 578,-165.25"/>
+<text xml:space="preserve" text-anchor="start" x="586.62" y="-172" font-family="Times,serif" font-size="14.00">str1</text>
+<polygon fill="none" stroke="black" points="483.5,-142.75 483.5,-165.25 508.25,-165.25 508.25,-142.75 483.5,-142.75"/>
+<text xml:space="preserve" text-anchor="start" x="490.25" y="-149.5" font-family="Times,serif" font-size="14.00">...</text>
+<polygon fill="none" stroke="black" points="508.25,-142.75 508.25,-165.25 535.25,-165.25 535.25,-142.75 508.25,-142.75"/>
+<text xml:space="preserve" text-anchor="start" x="518.38" y="-149.5" font-family="Times,serif" font-size="14.00">2</text>
+<polygon fill="none" stroke="black" points="535.25,-142.75 535.25,-165.25 578,-165.25 578,-142.75 535.25,-142.75"/>
+<text xml:space="preserve" text-anchor="start" x="543.5" y="-149.5" font-family="Times,serif" font-size="14.00">u2be</text>
+<polygon fill="none" stroke="black" points="578,-142.75 578,-165.25 615.5,-165.25 615.5,-142.75 578,-142.75"/>
+<text xml:space="preserve" text-anchor="start" x="581" y="-149.5" font-family="Times,serif" font-size="14.00">num2</text>
+<polygon fill="none" stroke="black" points="483.5,-120.25 483.5,-142.75 508.25,-142.75 508.25,-120.25 483.5,-120.25"/>
+<text xml:space="preserve" text-anchor="start" x="490.25" y="-127" font-family="Times,serif" font-size="14.00">...</text>
+<polygon fill="none" stroke="black" points="508.25,-120.25 508.25,-142.75 535.25,-142.75 535.25,-120.25 508.25,-120.25"/>
+<text xml:space="preserve" text-anchor="start" x="516.12" y="-127" font-family="Times,serif" font-size="14.00">...</text>
+<polygon fill="none" stroke="black" points="535.25,-120.25 535.25,-142.75 578,-142.75 578,-120.25 535.25,-120.25"/>
+<text xml:space="preserve" text-anchor="start" x="538.25" y="-127" font-family="Times,serif" font-size="14.00">Binary</text>
+<polygon fill="none" stroke="black" points="578,-120.25 578,-142.75 615.5,-142.75 615.5,-120.25 578,-120.25"/>
+<text xml:space="preserve" text-anchor="start" x="584.75" y="-127" font-family="Times,serif" font-size="14.00">bin1</text>
+<polygon fill="none" stroke="black" points="483.5,-97.75 483.5,-120.25 508.25,-120.25 508.25,-97.75 483.5,-97.75"/>
+<text xml:space="preserve" text-anchor="start" x="490.25" y="-104.5" font-family="Times,serif" font-size="14.00">...</text>
+<polygon fill="none" stroke="black" points="508.25,-97.75 508.25,-120.25 535.25,-120.25 535.25,-97.75 508.25,-97.75"/>
+<text xml:space="preserve" text-anchor="start" x="518.38" y="-104.5" font-family="Times,serif" font-size="14.00">4</text>
+<polygon fill="none" stroke="black" points="535.25,-97.75 535.25,-120.25 578,-120.25 578,-97.75 535.25,-97.75"/>
+<text xml:space="preserve" text-anchor="start" x="543.5" y="-104.5" font-family="Times,serif" font-size="14.00">u4be</text>
+<polygon fill="none" stroke="black" points="578,-97.75 578,-120.25 615.5,-120.25 615.5,-97.75 578,-97.75"/>
+<text xml:space="preserve" text-anchor="start" x="581" y="-104.5" font-family="Times,serif" font-size="14.00">num3</text>
+<polygon fill="none" stroke="black" points="483.5,-75.25 483.5,-97.75 508.25,-97.75 508.25,-75.25 483.5,-75.25"/>
+<text xml:space="preserve" text-anchor="start" x="490.25" y="-82" font-family="Times,serif" font-size="14.00">...</text>
+<polygon fill="none" stroke="black" points="508.25,-75.25 508.25,-97.75 535.25,-97.75 535.25,-75.25 508.25,-75.25"/>
+<text xml:space="preserve" text-anchor="start" x="516.12" y="-82" font-family="Times,serif" font-size="14.00">...</text>
+<polygon fill="none" stroke="black" points="535.25,-75.25 535.25,-97.75 578,-97.75 578,-75.25 535.25,-75.25"/>
+<text xml:space="preserve" text-anchor="start" x="540.12" y="-82" font-family="Times,serif" font-size="14.00">String</text>
+<polygon fill="none" stroke="black" points="578,-75.25 578,-97.75 615.5,-97.75 615.5,-75.25 578,-75.25"/>
+<text xml:space="preserve" text-anchor="start" x="586.62" y="-82" font-family="Times,serif" font-size="14.00">str2</text>
+<polygon fill="none" stroke="black" points="483.5,-52.75 483.5,-75.25 508.25,-75.25 508.25,-52.75 483.5,-52.75"/>
+<text xml:space="preserve" text-anchor="start" x="490.25" y="-59.5" font-family="Times,serif" font-size="14.00">...</text>
+<polygon fill="none" stroke="black" points="508.25,-52.75 508.25,-75.25 535.25,-75.25 535.25,-52.75 508.25,-52.75"/>
+<text xml:space="preserve" text-anchor="start" x="518.38" y="-59.5" font-family="Times,serif" font-size="14.00">8</text>
+<polygon fill="none" stroke="black" points="535.25,-52.75 535.25,-75.25 578,-75.25 578,-52.75 535.25,-52.75"/>
+<text xml:space="preserve" text-anchor="start" x="543.5" y="-59.5" font-family="Times,serif" font-size="14.00">u8be</text>
+<polygon fill="none" stroke="black" points="578,-52.75 578,-75.25 615.5,-75.25 615.5,-52.75 578,-52.75"/>
+<text xml:space="preserve" text-anchor="start" x="581" y="-59.5" font-family="Times,serif" font-size="14.00">num4</text>
+</g>
+<!-- solec__seq_payload_switch&#45;&gt;test__seq -->
+<g id="edge2" class="edge">
+<title>solec__seq_payload_switch:case0&#45;&gt;test__seq</title>
+<path fill="none" stroke="black" stroke-width="2" d="M432.5,-153.75C442.89,-153.75 453.8,-153.76 464.6,-153.78"/>
+<polygon fill="black" stroke="black" stroke-width="2" points="462.76,-157.27 472.77,-153.79 462.77,-150.27 462.76,-157.27"/>
+</g>
+<!-- binary__seq -->
+<g id="node3" class="node">
+<title>binary__seq</title>
+<polygon fill="#e0ffe0" stroke="none" points="684,-73.25 684,-95.75 708.75,-95.75 708.75,-73.25 684,-73.25"/>
+<polygon fill="none" stroke="black" points="684,-73.25 684,-95.75 708.75,-95.75 708.75,-73.25 684,-73.25"/>
+<text xml:space="preserve" text-anchor="start" x="687" y="-80" font-family="Times,serif" font-size="14.00">pos</text>
+<polygon fill="#e0ffe0" stroke="none" points="708.75,-73.25 708.75,-95.75 780.75,-95.75 780.75,-73.25 708.75,-73.25"/>
+<polygon fill="none" stroke="black" points="708.75,-73.25 708.75,-95.75 780.75,-95.75 780.75,-73.25 708.75,-73.25"/>
+<text xml:space="preserve" text-anchor="start" x="734.25" y="-80" font-family="Times,serif" font-size="14.00">size</text>
+<polygon fill="#e0ffe0" stroke="none" points="780.75,-73.25 780.75,-95.75 813,-95.75 813,-73.25 780.75,-73.25"/>
+<polygon fill="none" stroke="black" points="780.75,-73.25 780.75,-95.75 813,-95.75 813,-73.25 780.75,-73.25"/>
+<text xml:space="preserve" text-anchor="start" x="785.25" y="-80" font-family="Times,serif" font-size="14.00">type</text>
+<polygon fill="#e0ffe0" stroke="none" points="813,-73.25 813,-95.75 885,-95.75 885,-73.25 813,-73.25"/>
+<polygon fill="none" stroke="black" points="813,-73.25 813,-95.75 885,-95.75 885,-73.25 813,-73.25"/>
+<text xml:space="preserve" text-anchor="start" x="843.75" y="-80" font-family="Times,serif" font-size="14.00">id</text>
+<polygon fill="none" stroke="black" points="684,-50.75 684,-73.25 708.75,-73.25 708.75,-50.75 684,-50.75"/>
+<text xml:space="preserve" text-anchor="start" x="693" y="-57.5" font-family="Times,serif" font-size="14.00">0</text>
+<polygon fill="none" stroke="black" points="708.75,-50.75 708.75,-73.25 780.75,-73.25 780.75,-50.75 708.75,-50.75"/>
+<text xml:space="preserve" text-anchor="start" x="741.38" y="-57.5" font-family="Times,serif" font-size="14.00">2</text>
+<polygon fill="none" stroke="black" points="780.75,-50.75 780.75,-73.25 813,-73.25 813,-50.75 780.75,-50.75"/>
+<text xml:space="preserve" text-anchor="start" x="783.75" y="-57.5" font-family="Times,serif" font-size="14.00">u2be</text>
+<polygon fill="none" stroke="black" points="813,-50.75 813,-73.25 885,-73.25 885,-50.75 813,-50.75"/>
+<text xml:space="preserve" text-anchor="start" x="816" y="-57.5" font-family="Times,serif" font-size="14.00">len_payload</text>
+<polygon fill="none" stroke="black" points="684,-28.25 684,-50.75 708.75,-50.75 708.75,-28.25 684,-28.25"/>
+<text xml:space="preserve" text-anchor="start" x="693" y="-35" font-family="Times,serif" font-size="14.00">2</text>
+<polygon fill="none" stroke="black" points="708.75,-28.25 708.75,-50.75 780.75,-50.75 780.75,-28.25 708.75,-28.25"/>
+<text xml:space="preserve" text-anchor="start" x="711.75" y="-35" font-family="Times,serif" font-size="14.00">len_payload</text>
+<polygon fill="none" stroke="black" points="780.75,-28.25 780.75,-50.75 813,-50.75 813,-28.25 780.75,-28.25"/>
+<polygon fill="none" stroke="black" points="813,-28.25 813,-50.75 885,-50.75 885,-28.25 813,-28.25"/>
+<text xml:space="preserve" text-anchor="start" x="827.62" y="-35" font-family="Times,serif" font-size="14.00">payload</text>
+</g>
+<!-- binary__seq&#45;&gt;binary__seq -->
+<g id="edge4" class="edge">
+<title>binary__seq:len_payload_type&#45;&gt;binary__seq:payload_size</title>
+<path fill="none" stroke="#404040" d="M874.25,-73.22C904.32,-92.5 888.26,-117.75 796.88,-117.75 712.07,-117.75 692.13,-82.84 713.73,-58.11"/>
+<polygon fill="#404040" stroke="#404040" points="715.97,-60.81 721.05,-51.51 711.28,-55.61 715.97,-60.81"/>
+</g>
+<!-- string__seq -->
+<g id="node4" class="node">
+<title>string__seq</title>
+<polygon fill="#e0ffe0" stroke="none" points="667.5,-215.25 667.5,-237.75 692.25,-237.75 692.25,-215.25 667.5,-215.25"/>
+<polygon fill="none" stroke="black" points="667.5,-215.25 667.5,-237.75 692.25,-237.75 692.25,-215.25 667.5,-215.25"/>
+<text xml:space="preserve" text-anchor="start" x="670.5" y="-222" font-family="Times,serif" font-size="14.00">pos</text>
+<polygon fill="#e0ffe0" stroke="none" points="692.25,-215.25 692.25,-237.75 764.25,-237.75 764.25,-215.25 692.25,-215.25"/>
+<polygon fill="none" stroke="black" points="692.25,-215.25 692.25,-237.75 764.25,-237.75 764.25,-215.25 692.25,-215.25"/>
+<text xml:space="preserve" text-anchor="start" x="717.75" y="-222" font-family="Times,serif" font-size="14.00">size</text>
+<polygon fill="#e0ffe0" stroke="none" points="764.25,-215.25 764.25,-237.75 829.5,-237.75 829.5,-215.25 764.25,-215.25"/>
+<polygon fill="none" stroke="black" points="764.25,-215.25 764.25,-237.75 829.5,-237.75 829.5,-215.25 764.25,-215.25"/>
+<text xml:space="preserve" text-anchor="start" x="785.25" y="-222" font-family="Times,serif" font-size="14.00">type</text>
+<polygon fill="#e0ffe0" stroke="none" points="829.5,-215.25 829.5,-237.75 901.5,-237.75 901.5,-215.25 829.5,-215.25"/>
+<polygon fill="none" stroke="black" points="829.5,-215.25 829.5,-237.75 901.5,-237.75 901.5,-215.25 829.5,-215.25"/>
+<text xml:space="preserve" text-anchor="start" x="860.25" y="-222" font-family="Times,serif" font-size="14.00">id</text>
+<polygon fill="none" stroke="black" points="667.5,-192.75 667.5,-215.25 692.25,-215.25 692.25,-192.75 667.5,-192.75"/>
+<text xml:space="preserve" text-anchor="start" x="676.5" y="-199.5" font-family="Times,serif" font-size="14.00">0</text>
+<polygon fill="none" stroke="black" points="692.25,-192.75 692.25,-215.25 764.25,-215.25 764.25,-192.75 692.25,-192.75"/>
+<text xml:space="preserve" text-anchor="start" x="724.88" y="-199.5" font-family="Times,serif" font-size="14.00">2</text>
+<polygon fill="none" stroke="black" points="764.25,-192.75 764.25,-215.25 829.5,-215.25 829.5,-192.75 764.25,-192.75"/>
+<text xml:space="preserve" text-anchor="start" x="783.75" y="-199.5" font-family="Times,serif" font-size="14.00">u2be</text>
+<polygon fill="none" stroke="black" points="829.5,-192.75 829.5,-215.25 901.5,-215.25 901.5,-192.75 829.5,-192.75"/>
+<text xml:space="preserve" text-anchor="start" x="832.5" y="-199.5" font-family="Times,serif" font-size="14.00">len_payload</text>
+<polygon fill="none" stroke="black" points="667.5,-170.25 667.5,-192.75 692.25,-192.75 692.25,-170.25 667.5,-170.25"/>
+<text xml:space="preserve" text-anchor="start" x="676.5" y="-177" font-family="Times,serif" font-size="14.00">2</text>
+<polygon fill="none" stroke="black" points="692.25,-170.25 692.25,-192.75 764.25,-192.75 764.25,-170.25 692.25,-170.25"/>
+<text xml:space="preserve" text-anchor="start" x="695.25" y="-177" font-family="Times,serif" font-size="14.00">len_payload</text>
+<polygon fill="none" stroke="black" points="764.25,-170.25 764.25,-192.75 829.5,-192.75 829.5,-170.25 764.25,-170.25"/>
+<text xml:space="preserve" text-anchor="start" x="767.25" y="-177" font-family="Times,serif" font-size="14.00">str(UTF&#45;8)</text>
+<polygon fill="none" stroke="black" points="829.5,-170.25 829.5,-192.75 901.5,-192.75 901.5,-170.25 829.5,-170.25"/>
+<text xml:space="preserve" text-anchor="start" x="844.12" y="-177" font-family="Times,serif" font-size="14.00">payload</text>
+</g>
+<!-- string__seq&#45;&gt;string__seq -->
+<g id="edge5" class="edge">
+<title>string__seq:len_payload_type&#45;&gt;string__seq:payload_size</title>
+<path fill="none" stroke="#404040" d="M890.66,-215.22C920.31,-234.5 901.86,-259.75 796.88,-259.75 699.45,-259.75 676.54,-224.84 697.45,-200.11"/>
+<polygon fill="#404040" stroke="#404040" points="699.62,-202.86 704.62,-193.52 694.89,-197.71 699.62,-202.86"/>
+</g>
+<!-- test__seq&#45;&gt;binary__seq -->
+<g id="edge7" class="edge">
+<title>test__seq:bin1_type&#45;&gt;binary__seq</title>
+<path fill="none" stroke="black" stroke-width="2" d="M616.5,-131.5C650.49,-131.5 685.59,-119.08 714.79,-104.73"/>
+<polygon fill="black" stroke="black" stroke-width="2" points="714.84,-108.63 722.16,-100.97 711.66,-102.4 714.84,-108.63"/>
+</g>
+<!-- test__seq&#45;&gt;string__seq -->
+<g id="edge6" class="edge">
+<title>test__seq:str1_type&#45;&gt;string__seq</title>
+<path fill="none" stroke="black" stroke-width="2" d="M616.5,-176.5C626.97,-176.5 637.76,-177.03 648.57,-177.95"/>
+<polygon fill="black" stroke="black" stroke-width="2" points="646.54,-181.27 656.83,-178.75 647.21,-174.3 646.54,-181.27"/>
+</g>
+<!-- test__seq&#45;&gt;string__seq -->
+<g id="edge8" class="edge">
+<title>test__seq:str2_type&#45;&gt;string__seq</title>
+<path fill="none" stroke="black" stroke-width="2" d="M616.5,-86.5C650.29,-86.5 626.26,-131.53 651.5,-154 653.78,-156.03 656.15,-157.98 658.6,-159.86"/>
+<polygon fill="black" stroke="black" stroke-width="2" points="655.11,-161.68 665.3,-164.57 659.14,-155.95 655.11,-161.68"/>
+</g>
+</g>
+</svg>