diff --git a/.idea/dictionaries/pavel.xml b/.idea/dictionaries/pavel.xml
index de347ad..2872d26 100644
--- a/.idea/dictionaries/pavel.xml
+++ b/.idea/dictionaries/pavel.xml
@@ -189,6 +189,7 @@
pizdec
pizdets
pkgutil
+ plotjuggler
popen
powershell
pppwm
diff --git a/README.md b/README.md
index 0a1f7c0..d9fe89b 100644
--- a/README.md
+++ b/README.md
@@ -29,7 +29,11 @@ Installation & configuration screencasts are available for [Windows](https://for
Since Yakut heavily relies on YAML/JSON documents exchanged via stdin/stdout, [**`jq`**](https://stedolan.github.io/jq/) is often needed for any non-trivial usage of the tool, so consider installing it as well. Users of GNU/Linux will likely find it in the default software repositories (`pacman -S jq`, `apt install jq`, etc.).
-- Cyphal/CAN on GNU/Linux: [`can-utils`](https://github.com/linux-can/can-utils)
+[PlotJuggler](https://plotjuggler.io) is occasionally useful for real-time data visualization. Offline data analysis may be better addressed with Jupyter+Plotly+Pandas or whatever stack you prefer.
+
+Transport layer inspection tools:
+
+- Cyphal/CAN on GNU/Linux (candump, canbusload, etc.): [`can-utils`](https://github.com/linux-can/can-utils)
- Cyphal/UDP or Cyphal/CAN: [Wireshark](https://www.wireshark.org/)
(n.b.: Wireshark might label Cyphal captures as UAVCAN due to rebranding)
@@ -204,6 +208,18 @@ y --tsvh sub 1252 1255 --sync > ~/out.tsv
+#### Real-time visualization
+
+Being a CLI application, Yakut comes without built-in visualization facilities, but it can be easily combined with 3rd-party solutions.
+
+[PlotJuggler](https://plotjuggler.io) can accept JSON streamed from Yakut via its UDP server. To use that, start an instance of PlotJuggler, enable the UDP streaming server in JSON mode, and then pipe the output of `yakut subscribe` to the UDP server via netcat like so:
+
+```bash
+y sub 33:uavcan.si.unit.angle.scalar 1250 --sync | nc -u localhost 9870 # 9870 is the UDP port set in PlotJuggler
+```
+
+
+
### Publishing messages
Publishing a message twice (you can use a subscriber as explained earlier to see it on the bus):
diff --git a/docs/plotjuggler_plots.png b/docs/plotjuggler_plots.png
new file mode 100644
index 0000000..23c28b9
Binary files /dev/null and b/docs/plotjuggler_plots.png differ
diff --git a/yakut/VERSION b/yakut/VERSION
index d9df1bb..af88ba8 100644
--- a/yakut/VERSION
+++ b/yakut/VERSION
@@ -1 +1 @@
-0.11.0
+0.11.1
diff --git a/yakut/cmd/compile.py b/yakut/cmd/compile.py
index aefa089..40d9481 100644
--- a/yakut/cmd/compile.py
+++ b/yakut/cmd/compile.py
@@ -2,6 +2,7 @@
# This software is distributed under the terms of the MIT License.
# Author: Pavel Kirienko
+import re
import http
import typing
import zipfile
@@ -154,7 +155,10 @@ def _fetch_archive_dirs(archive_uri: str) -> typing.List[Path]:
(inner,) = [d for d in Path(arch_dir).iterdir() if d.is_dir()] # Strip the outer layer, we don't need it
assert isinstance(inner, Path)
- return [d for d in inner.iterdir() if d.is_dir()]
+ return [d for d in inner.iterdir() if d.is_dir() and _RE_VALID_ROOT_NAMESPACE_NAME.match(d.name)]
+
+
+_RE_VALID_ROOT_NAMESPACE_NAME = re.compile(r"[a-zA-Z_]\w*")
def _generate_dsdl_packages(