Skip to content

Commit f02b750

Browse files
networking docs page
1 parent bd06684 commit f02b750

File tree

388 files changed

+3429
-1644
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

388 files changed

+3429
-1644
lines changed

docpages/basic-language-reference/INDEX.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ For real-world examples of programs in the operating system, see the [os/program
3232
* \subpage variables
3333
* \subpage keywords
3434
* \subpage builtin-functions
35+
* \subpage networking
3536
* \subpage libraries
3637
* \subpage tasks
3738
* \subpage basic-intdev
Lines changed: 313 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,313 @@
1+
\page networking BASIC Networking
2+
3+
[TOC]
4+
5+
### Introduction to Sockets
6+
7+
Retro Rocket BASIC is not limited to files, graphics, and local input/output.
8+
It also has direct **network and Internet access**, built into the language itself.
9+
This is provided through **sockets**.
10+
11+
A socket is a numbered channel that lets your program send and receive data across the network. With sockets you can:
12+
13+
* **Build clients** that connect to remote services such as web servers, APIs, or other Retro Rocket programs.
14+
* **Build servers** that listen for incoming connections from other machines, whether on your local network or the wider Internet.
15+
* **Exchange data directly** between two programs on the same computer without using files.
16+
17+
Sockets are deliberately designed to be simple in Retro Rocket BASIC. You do not need to know about retries, buffers, or low-level networking details. A few straightforward keywords are enough to open a connection, send and receive data, and close it again.
18+
19+
This section of the manual introduces sockets, shows how to create both clients and servers, and explains the two kinds of socket Retro Rocket provides:
20+
21+
* **TCP sockets** for reliable, ordered conversations.
22+
* **UDP sockets** for quick, lightweight messages.
23+
24+
Once you understand these, you can write networked applications such as web servers, chat clients, multiplayer games, and telemetry systems - all in BASIC, with the same clarity and brevity as printing text to the screen.
25+
26+
---
27+
28+
### Understanding Sockets (Phone Calls vs Parcels)
29+
30+
Networking in Retro Rocket BASIC uses **sockets**: simple handles (just numbers) that let programs talk over the network. There are two flavours with very different “feel”:
31+
32+
* **TCP** - like a **phone call**: a live conversation with guaranteed order and delivery.
33+
* **UDP** - like posting a **parcel**: each item is sent on its own; most arrive, some may not.
34+
35+
You don’t need to learn object systems, callbacks, or frameworks. The flow is linear: **connect/listen → read/write → flush (if needed) → close**.
36+
37+
---
38+
39+
#### TCP - Like a Phone Call (reliable conversation)
40+
41+
TCP aims to feel like you’ve got a dedicated line once connected.
42+
43+
* \ref CONNECT "CONNECT" - dial the other side. Their phone “rings”.
44+
* \ref SOCKLISTEN "SOCKLISTEN" - keep your phone on, ready to receive calls on a number (port).
45+
* \ref SOCKACCEPT "SOCKACCEPT" - swipe to answer when someone calls. Each accepted call gets a **new** socket handle (a new line).
46+
* \ref SOCKWRITE "SOCKWRITE" - speak; your words are queued exactly as you said them.
47+
* \ref SOCKFLUSH "SOCKFLUSH" - pause for the “**uh-huh**”: make sure what you said is pushed out and acknowledged before carrying on.
48+
* \ref SOCKREAD "SOCKREAD" - listen; you receive complete values (string / integer / real) in the right order.
49+
* \ref SOCKCLOSE "SOCKCLOSE" - hang up; the line is gone.
50+
51+
**What you get with TCP**
52+
53+
* **No missing words**: bytes aren’t lost.
54+
* **Correct order**: bytes arrive exactly as sent.
55+
* **Simple flow**: write → flush → read → close; no retries, no partial-send faff.
56+
57+
**Use TCP for** web pages, chat, control channels, file transfer-anything where every byte matters.
58+
59+
---
60+
61+
#### UDP - Like Sending a Parcel (quick, independent messages)
62+
63+
UDP is fire-and-forget. Each message is its own parcel.
64+
65+
* \ref UDPBIND "UDPBIND" - write your return address on the box and open your doorstep (port). Both sides should **bind** so they have a clear return address and a place to receive.
66+
* \ref UDPWRITE "UDPWRITE" - pack a parcel and drop it at the post office. It **leaves immediately**. There’s no built-in receipt or guarantee.
67+
* \ref UDPREAD "UDPREAD$" - open the door and pick up the **next** parcel on your doorstep.
68+
* \ref UDPLASTIP "UDPLASTIP$" / \ref UDPLASTSOURCEPORT "UDPLASTSOURCEPORT" - read the sender label (who posted this parcel and from which port) **for the parcel you just picked up**.
69+
70+
**What you get with UDP**
71+
72+
* **Speed & simplicity**: no call setup, no flush.
73+
* **Independence**: each message stands alone; send one or many.
74+
* **No guarantees**: a parcel can be delayed, arrive out of order, or never turn up.
75+
76+
**Use UDP for** quick updates, game ticks, “is-alive” beacons, mouse/keyboard telemetry-cases where losing the odd packet doesn’t hurt.
77+
78+
---
79+
80+
### Side-by-side: Phone Call vs Parcel
81+
82+
| Aspect | **TCP (Phone Call)** | **UDP (Parcel Post)** |
83+
| ------------- | ---------------------------------------------------------------- | ------------------------------------------------------------------------------------------------- |
84+
| How you start | `CONNECT` to call; server `SOCKLISTEN` + `SOCKACCEPT` to answer. | Both sides `UDPBIND` a port (their doorstep). No call setup. |
85+
| Identity | Each accepted TCP socket is a known line between two ends. | Each parcel carries its own label; use `UDPLASTIP$` / `UDPLASTSOURCEPORT` after `UDPREAD$`. |
86+
| Sending | `SOCKWRITE` queues words; `SOCKFLUSH` waits for “uh-huh”. | `UDPSEND`/`UDPWRITE` posts a parcel immediately. No flush. |
87+
| Receiving | `SOCKREAD` waits for complete data; order guaranteed. | `UDPREAD$` pops **one** parcel from the doorstep queue; order not guaranteed. |
88+
| Delivery | Guaranteed and ordered. | Best-effort; may be delayed, re-ordered, or lost. |
89+
| Ending | `SOCKCLOSE` hangs up the line. | `SOCKCLOSE`/`UDPUNBIND` stops using that doorstep. |
90+
91+
---
92+
93+
### UDP “Doorstep Queue” (how incoming messages are stored)
94+
95+
When your program `UDPBIND`s a port, Retro Rocket keeps an **in-memory queue** of incoming UDP packets for that port-think **parcels on your doorstep**:
96+
97+
* Every new packet is placed at the **back** of the queue for that port.
98+
* Each call to \ref UDPREAD "UDPREAD$ pops **one** packet from the **front** of the queue and returns its contents as a string.
99+
* After a successful \ref UDPREAD "UDPREAD$ the “label” values for that packet are available via:
100+
101+
* \ref UDPLASTIP "UDPLASTIP$" - sender’s address (the return address).
102+
* \ref UDPLASTSOURCEPORT "UDPLASTSOURCEPORT" - sender’s source port (their posting office counter).
103+
These **do not take parameters**: they always refer to the **most recently read** packet.
104+
105+
This model is simple, predictable, and maps perfectly to the “parcel on the doorstep” intuition.
106+
107+
---
108+
109+
### Worked UDP Example - Mouse Telemetry
110+
111+
Below is your exact module, which binds a per-process port and polls a local mouse server. It showcases `UDPBIND`, `UDPWRITE`, `UDPREAD$`, and consuming one packet at a time:
112+
113+
```basic
114+
DEF PROCmouse
115+
__MOUSE_X = GRAPHICS_WIDTH / 2
116+
__MOUSE_Y = GRAPHICS_HEIGHT / 2
117+
__MOUSE_LMB = FALSE
118+
__MOUSE_RMB = FALSE
119+
__MOUSE_MMB = FALSE
120+
UDPBIND "127.0.0.1", 14502 + PID
121+
ENDPROC
122+
123+
DEF PROCmouse_done
124+
UDPUNBIND "127.0.0.1", 14502 + PID
125+
ENDPROC
126+
127+
DEF PROCfetch_mouse
128+
UDPWRITE "127.0.0.1", 14502 + PID, 14501, "GET"
129+
PACKET$ = UDPREAD$(14502 + PID)
130+
IF PACKET$ <> "" THEN
131+
X$ = TOKENIZE$(PACKET$, " ")
132+
Y$ = TOKENIZE$(PACKET$, " ")
133+
M$ = TOKENIZE$(PACKET$, " ")
134+
__MOUSE_X = VAL(X$)
135+
__MOUSE_Y = VAL(Y$)
136+
__MOUSE_BUTTONS = VAL(M$)
137+
__MOUSE_LMB = BITAND(__MOUSE_BUTTONS, 1)
138+
__MOUSE_RMB = BITSHR(BITAND(__MOUSE_BUTTONS, 2), 1)
139+
__MOUSE_MMB = BITSHR(BITAND(__MOUSE_BUTTONS, 4), 2)
140+
ENDIF
141+
ENDPROC
142+
143+
DEF FNmouse_x
144+
=__MOUSE_X
145+
146+
DEF FNmouse_y
147+
=__MOUSE_Y
148+
149+
DEF FNmouse_lmb
150+
=__MOUSE_LMB
151+
152+
DEF FNmouse_rmb
153+
=__MOUSE_RMB
154+
155+
DEF FNmouse_mmb
156+
=__MOUSE_MMB
157+
```
158+
159+
**What’s happening here (in parcel terms):**
160+
161+
* `UDPBIND "127.0.0.1", 14502 + PID` opens **your doorstep** (unique port per process).
162+
* `UDPWRITE "127.0.0.1", 14502 + PID, 14501, "GET"` posts a **parcel** to the mouse server’s port **14501**, marking your doorstep **14502+PID** as the return address.
163+
* `UDPREAD$(14502 + PID)` **picks up the next parcel** that arrived for you. If none is present, it returns `""` and you carry on.
164+
* The packet encodes `x y buttons` separated by spaces; you slice those out and update state.
165+
* `UDPUNBIND` closes the doorstep when you’re done.
166+
167+
Because each UDP packet is independent, you can lose one with negligible impact-the next packet will replace it a tick later, keeping the mouse fluid.
168+
169+
---
170+
171+
### Practical Tips (UDP)
172+
173+
* **Bind both sides**: have a predictable return address and a consistent inbox.
174+
* **Keep messages small**: fit comfortably within your UDP payload limit to avoid IP fragmentation.
175+
* **Design for loss**: treat every packet as optional; never rely on “the last one must have arrived”.
176+
* **Use the labels**: read `UDPLASTIP$` / `UDPLASTSOURCEPORT` **immediately after** `UDPREAD$` if you plan to reply.
177+
178+
---
179+
180+
Right - good catch. For new users, we need to introduce the idea from first principles, **without starting with “DNS”**. Here’s a plain-English version that leads into the concept and only then names it:
181+
182+
---
183+
184+
### Names and Addresses
185+
186+
Every computer on the Internet has a unique **address number**, called an **IP address**. It looks like this:
187+
188+
```
189+
93.184.216.34
190+
```
191+
192+
These numbers are what sockets really use. But numbers are hard to remember. People prefer names, like:
193+
194+
```
195+
example.org
196+
```
197+
198+
There is a worldwide system that matches names to numbers, just like your phone’s contact list matches a friend’s name to their phone number. On the Internet this system is called the **Domain Name System**, usually shortened to **DNS**.
199+
200+
* When you type a name, DNS looks up the matching number.
201+
* Once you have the number, you can connect your socket to it.
202+
* The result is stored in a local cache, so asking for the same name again is instant.
203+
204+
---
205+
206+
### The DNS$ Function
207+
208+
Retro Rocket BASIC makes this simple with a single function:
209+
210+
```basic
211+
ip$ = DNS$("example.org")
212+
```
213+
214+
* Returns the IP address as a string, e.g. `"93.184.216.34"`.
215+
* Returns `""` if the name cannot be looked up.
216+
* Uses caching automatically; you don’t need to worry about retries or speed.
217+
218+
---
219+
220+
### Quick Examples
221+
222+
#### TCP Client
223+
224+
```basic
225+
' Connect to a web server
226+
sock = CONNECT("93.184.216.34", 80)
227+
SOCKWRITE sock, "GET / HTTP/1.0" + CHR$(13) + CHR$(10) + CHR$(13) + CHR$(10)
228+
SOCKFLUSH sock
229+
230+
' Read the response line
231+
SOCKREAD sock, line$
232+
PRINT line$
233+
234+
SOCKCLOSE sock
235+
```
236+
237+
---
238+
239+
#### TCP Server
240+
241+
```basic
242+
' Listen on port 8080
243+
server = SOCKLISTEN("0.0.0.0", 8080, 5)
244+
PRINT "Server running on port 8080"
245+
246+
REPEAT
247+
client = SOCKACCEPT(server)
248+
IF client >= 0 THEN
249+
SOCKWRITE client, "Hello from Retro Rocket!"
250+
SOCKFLUSH client
251+
SOCKCLOSE client
252+
ENDIF
253+
UNTIL INKEY$ <> ""
254+
255+
SOCKCLOSE server
256+
```
257+
258+
---
259+
260+
#### UDP Example
261+
262+
```basic
263+
' Bind to port 5001
264+
udp = UDPBIND("0.0.0.0", 5001)
265+
266+
' Send a packet to localhost:5001
267+
UDPSEND udp, "127.0.0.1", 5001, "Ping"
268+
269+
' Read the next packet from the queue
270+
msg$ = UDPREAD$(5001)
271+
IF msg$ <> "" THEN
272+
PRINT "Got packet: "; msg$
273+
PRINT "From: "; UDPLASTIP$; " Port: "; UDPLASTSOURCEPORT
274+
ENDIF
275+
276+
SOCKCLOSE udp
277+
```
278+
279+
#### Connecting by Name
280+
281+
```basic
282+
ip$ = DNS$("example.org")
283+
IF ip$ <> "" THEN
284+
sock = CONNECT(ip$, 80)
285+
SOCKWRITE sock, "GET / HTTP/1.0" + CHR$(13) + CHR$(10) + CHR$(13) + CHR$(10)
286+
SOCKFLUSH sock
287+
SOCKREAD sock, reply$
288+
PRINT reply$
289+
SOCKCLOSE sock
290+
ELSE
291+
PRINT "Could not look up that name"
292+
ENDIF
293+
```
294+
295+
---
296+
297+
### Socket Keywords
298+
299+
* \ref CONNECT
300+
* \ref DNS "DNS$"
301+
* \ref SOCKLISTEN
302+
* \ref SOCKACCEPT
303+
* \ref SOCKWRITE
304+
* \ref SOCKFLUSH
305+
* \ref SOCKREAD
306+
* \ref SOCKCLOSE
307+
* \ref UDPBIND
308+
* \ref UDPSEND
309+
* \ref UDPWRITE
310+
* \ref UDPREAD "UDPREAD$""
311+
* \ref UDPLASTIP "UDPLASTIP$"
312+
* \ref UDPLASTSOURCEPORT
313+
* \ref UDPUNBIND

docs/ABS.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ <h3><a class="anchor" id="autotoc_md63"></a>
128128
<div id="nav-path" class="navpath"><!-- id is needed for treeview function! -->
129129
<ul>
130130
<li class="navelem"><a class="el" href="index.html">index</a></li><li class="navelem"><a class="el" href="basic-ref.html">BASIC Language Reference</a></li><li class="navelem"><a class="el" href="builtin-functions.html">Built-In Functions</a></li><li class="navelem"><a class="el" href="int-funcs.html">Integer Functions</a></li>
131-
<li class="footer">Generated on Sun Sep 14 2025 15:48:58 for Retro Rocket OS by <a href="https://www.doxygen.org/index.html"><img class="footer" src="doxygen.svg" width="104" height="31" alt="doxygen"/></a> 1.9.1 </li>
131+
<li class="footer">Generated on Sun Sep 14 2025 22:09:33 for Retro Rocket OS by <a href="https://www.doxygen.org/index.html"><img class="footer" src="doxygen.svg" width="104" height="31" alt="doxygen"/></a> 1.9.1 </li>
132132
</ul>
133133
</div>
134134
</body>

docs/ACS.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ <h3><a class="anchor" id="autotoc_md440"></a>
126126
<div id="nav-path" class="navpath"><!-- id is needed for treeview function! -->
127127
<ul>
128128
<li class="navelem"><a class="el" href="index.html">index</a></li><li class="navelem"><a class="el" href="basic-ref.html">BASIC Language Reference</a></li><li class="navelem"><a class="el" href="builtin-functions.html">Built-In Functions</a></li><li class="navelem"><a class="el" href="real-funcs.html">Real Functions</a></li>
129-
<li class="footer">Generated on Sun Sep 14 2025 15:48:58 for Retro Rocket OS by <a href="https://www.doxygen.org/index.html"><img class="footer" src="doxygen.svg" width="104" height="31" alt="doxygen"/></a> 1.9.1 </li>
129+
<li class="footer">Generated on Sun Sep 14 2025 22:09:33 for Retro Rocket OS by <a href="https://www.doxygen.org/index.html"><img class="footer" src="doxygen.svg" width="104" height="31" alt="doxygen"/></a> 1.9.1 </li>
130130
</ul>
131131
</div>
132132
</body>

docs/ASC.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ <h3><a class="anchor" id="autotoc_md68"></a>
122122
<div id="nav-path" class="navpath"><!-- id is needed for treeview function! -->
123123
<ul>
124124
<li class="navelem"><a class="el" href="index.html">index</a></li><li class="navelem"><a class="el" href="basic-ref.html">BASIC Language Reference</a></li><li class="navelem"><a class="el" href="builtin-functions.html">Built-In Functions</a></li><li class="navelem"><a class="el" href="int-funcs.html">Integer Functions</a></li>
125-
<li class="footer">Generated on Sun Sep 14 2025 15:48:58 for Retro Rocket OS by <a href="https://www.doxygen.org/index.html"><img class="footer" src="doxygen.svg" width="104" height="31" alt="doxygen"/></a> 1.9.1 </li>
125+
<li class="footer">Generated on Sun Sep 14 2025 22:09:33 for Retro Rocket OS by <a href="https://www.doxygen.org/index.html"><img class="footer" src="doxygen.svg" width="104" height="31" alt="doxygen"/></a> 1.9.1 </li>
126126
</ul>
127127
</div>
128128
</body>

docs/ASN.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ <h3><a class="anchor" id="autotoc_md445"></a>
126126
<div id="nav-path" class="navpath"><!-- id is needed for treeview function! -->
127127
<ul>
128128
<li class="navelem"><a class="el" href="index.html">index</a></li><li class="navelem"><a class="el" href="basic-ref.html">BASIC Language Reference</a></li><li class="navelem"><a class="el" href="builtin-functions.html">Built-In Functions</a></li><li class="navelem"><a class="el" href="real-funcs.html">Real Functions</a></li>
129-
<li class="footer">Generated on Sun Sep 14 2025 15:48:58 for Retro Rocket OS by <a href="https://www.doxygen.org/index.html"><img class="footer" src="doxygen.svg" width="104" height="31" alt="doxygen"/></a> 1.9.1 </li>
129+
<li class="footer">Generated on Sun Sep 14 2025 22:09:33 for Retro Rocket OS by <a href="https://www.doxygen.org/index.html"><img class="footer" src="doxygen.svg" width="104" height="31" alt="doxygen"/></a> 1.9.1 </li>
130130
</ul>
131131
</div>
132132
</body>

docs/ATAN.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ <h3><a class="anchor" id="autotoc_md450"></a>
123123
<div id="nav-path" class="navpath"><!-- id is needed for treeview function! -->
124124
<ul>
125125
<li class="navelem"><a class="el" href="index.html">index</a></li><li class="navelem"><a class="el" href="basic-ref.html">BASIC Language Reference</a></li><li class="navelem"><a class="el" href="builtin-functions.html">Built-In Functions</a></li><li class="navelem"><a class="el" href="real-funcs.html">Real Functions</a></li>
126-
<li class="footer">Generated on Sun Sep 14 2025 15:48:58 for Retro Rocket OS by <a href="https://www.doxygen.org/index.html"><img class="footer" src="doxygen.svg" width="104" height="31" alt="doxygen"/></a> 1.9.1 </li>
126+
<li class="footer">Generated on Sun Sep 14 2025 22:09:33 for Retro Rocket OS by <a href="https://www.doxygen.org/index.html"><img class="footer" src="doxygen.svg" width="104" height="31" alt="doxygen"/></a> 1.9.1 </li>
127127
</ul>
128128
</div>
129129
</body>

docs/ATAN2.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ <h3><a class="anchor" id="autotoc_md455"></a>
125125
<div id="nav-path" class="navpath"><!-- id is needed for treeview function! -->
126126
<ul>
127127
<li class="navelem"><a class="el" href="index.html">index</a></li><li class="navelem"><a class="el" href="basic-ref.html">BASIC Language Reference</a></li><li class="navelem"><a class="el" href="builtin-functions.html">Built-In Functions</a></li><li class="navelem"><a class="el" href="real-funcs.html">Real Functions</a></li>
128-
<li class="footer">Generated on Sun Sep 14 2025 15:48:58 for Retro Rocket OS by <a href="https://www.doxygen.org/index.html"><img class="footer" src="doxygen.svg" width="104" height="31" alt="doxygen"/></a> 1.9.1 </li>
128+
<li class="footer">Generated on Sun Sep 14 2025 22:09:33 for Retro Rocket OS by <a href="https://www.doxygen.org/index.html"><img class="footer" src="doxygen.svg" width="104" height="31" alt="doxygen"/></a> 1.9.1 </li>
129129
</ul>
130130
</div>
131131
</body>

docs/AUTOFLIP.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@
102102
<div id="nav-path" class="navpath"><!-- id is needed for treeview function! -->
103103
<ul>
104104
<li class="navelem"><a class="el" href="index.html">index</a></li><li class="navelem"><a class="el" href="basic-ref.html">BASIC Language Reference</a></li><li class="navelem"><a class="el" href="keywords.html">Keywords</a></li>
105-
<li class="footer">Generated on Sun Sep 14 2025 15:48:58 for Retro Rocket OS by <a href="https://www.doxygen.org/index.html"><img class="footer" src="doxygen.svg" width="104" height="31" alt="doxygen"/></a> 1.9.1 </li>
105+
<li class="footer">Generated on Sun Sep 14 2025 22:09:34 for Retro Rocket OS by <a href="https://www.doxygen.org/index.html"><img class="footer" src="doxygen.svg" width="104" height="31" alt="doxygen"/></a> 1.9.1 </li>
106106
</ul>
107107
</div>
108108
</body>

docs/BACKGROUND.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,7 @@ <h5>Notes</h5>
155155
<div id="nav-path" class="navpath"><!-- id is needed for treeview function! -->
156156
<ul>
157157
<li class="navelem"><a class="el" href="index.html">index</a></li><li class="navelem"><a class="el" href="basic-ref.html">BASIC Language Reference</a></li><li class="navelem"><a class="el" href="keywords.html">Keywords</a></li>
158-
<li class="footer">Generated on Sun Sep 14 2025 15:48:58 for Retro Rocket OS by <a href="https://www.doxygen.org/index.html"><img class="footer" src="doxygen.svg" width="104" height="31" alt="doxygen"/></a> 1.9.1 </li>
158+
<li class="footer">Generated on Sun Sep 14 2025 22:09:34 for Retro Rocket OS by <a href="https://www.doxygen.org/index.html"><img class="footer" src="doxygen.svg" width="104" height="31" alt="doxygen"/></a> 1.9.1 </li>
159159
</ul>
160160
</div>
161161
</body>

0 commit comments

Comments
 (0)