mirror of
https://github.com/markqvist/Reticulum.git
synced 2025-05-02 06:36:14 -04:00
Updated documentation
This commit is contained in:
parent
c79811e040
commit
ac7c36029b
32 changed files with 1282 additions and 87 deletions
|
@ -103,16 +103,16 @@ With Reticulum, you only need to configure what interfaces you want to communica
|
|||
over. There is no need to configure address spaces, subnets, routing tables,
|
||||
or other things you might be used to from other network types.
|
||||
|
||||
Once Reticulums knows which interfaces it should use, it will automatically
|
||||
Once Reticulum knows which interfaces it should use, it will automatically
|
||||
discover topography and configure transport of data to any destinations it
|
||||
knows about.
|
||||
|
||||
In situations where you already have an established WiFi or ethernet network, and
|
||||
many devices that want to utilise the same external Reticulum network (for example over
|
||||
many devices that want to utilise the same external Reticulum network paths (for example over
|
||||
LoRa), it will often be sufficient to let one system act as a Reticulum gateway, by
|
||||
adding any external interfaces to this systems configuration, and enabling transport. Any
|
||||
adding any external interfaces to the configuration of this system, and then enabling transport on it. Any
|
||||
other device on your local WiFi will then be able to connect to this wider Reticulum
|
||||
network just using the default interface configuration.
|
||||
network just using the default (:ref:`AutoInterface<interfaces-auto>`) configuration.
|
||||
|
||||
Possibly, the examples in the config file are enough to get you started. If
|
||||
you want more information, you can read the :ref:`Building Networks<networks-main>`
|
||||
|
@ -137,7 +137,7 @@ Hosting a publicly reachable instance over TCP also requires a publicly reachabl
|
|||
which most Internet connections don't offer anymore.
|
||||
|
||||
The ``I2PInterface`` routes messages through the `Invisible Internet Protocol
|
||||
(I2P) <https://geti2p.net/en/>`_. To properly use this interface, users must also run an I2P daemon in
|
||||
(I2P) <https://geti2p.net/en/>`_. To use this interface, users must also run an I2P daemon in
|
||||
parallel to ``rnsd``. For always-on I2P nodes it is recommended to use `i2pd <https://i2pd.website/>`_.
|
||||
|
||||
By default, I2P will encrypt and mix all traffic sent over the Internet, and
|
||||
|
@ -146,12 +146,13 @@ will also relay other I2P user's encrypted packets, which will use extra
|
|||
bandwidth and compute power, but also makes timing attacks and other forms of
|
||||
deep-packet-inspection much more difficult.
|
||||
|
||||
I2P also allows users to host globally available Reticulum instances from non-public IPs and behind firewalls.
|
||||
I2P also allows users to host globally available Reticulum instances from non-public IPs and behind firewalls and NAT.
|
||||
|
||||
In general it is recommended to use an I2P node if you want to host a publically accessible
|
||||
instance, while preserving anonymity. If you care more about performance, and a slightly
|
||||
easier setup, use TCP.
|
||||
|
||||
|
||||
Connect to the Public Testnet
|
||||
===========================================
|
||||
|
||||
|
@ -180,6 +181,36 @@ via other entry points if you know them. There is absolutely no control over the
|
|||
topography, usage or what types of instances connect. It will also occasionally be used
|
||||
to test various failure scenarios, and there are no availability or service guarantees.
|
||||
|
||||
|
||||
Adding Radio Interfaces
|
||||
==============================================
|
||||
Once you have Reticulum installed and working, you can add radio interfaces with
|
||||
any compatible hardware you have available. Reticulum supports a wide range of radio
|
||||
hardware, and if you already have any available, it is very likely that it will
|
||||
work with Reticulum. For information on how to configure this, see the
|
||||
:ref:`Interfaces<interfaces-main>` section of this manual.
|
||||
|
||||
If you do not already have transceiver hardware available, you can easily and
|
||||
cheaply build an :ref:`RNode<rnode-main>`, which is a general-purpose long-range
|
||||
digital radio transceiver, that integrates easily with Reticulum.
|
||||
|
||||
To build one yourself requires installing a custom firmware on a supported LoRa
|
||||
development board with an auto-install script. Please see the :ref:`Communications Hardware<hardware-main>`
|
||||
chapter for a guide. If you prefer purchasing a ready-made unit, you can refer to the
|
||||
:ref:`list of suppliers<rnode-suppliers>`. For more information on RNode, you can also
|
||||
refer to these additional external resources:
|
||||
|
||||
* `How To Make Your Own RNodes <https://unsigned.io/how-to-make-your-own-rnodes/>`_
|
||||
* `Installing RNode Firmware on Compatible LoRa Devices <https://unsigned.io/installing-rnode-firmware-on-t-beam-and-lora32-devices/>`_
|
||||
* `Private, Secure and Uncensorable Messaging Over a LoRa Mesh <https://unsigned.io/private-messaging-over-lora/>`_
|
||||
* `RNode Firmware <https://github.com/markqvist/RNode_Firmware/>`_
|
||||
|
||||
If you have communications hardware that is not already supported by any of the
|
||||
:ref:`existing interface types<interfaces-main>`, but you think would be suitable for use with Reticulum,
|
||||
you are welcome to head over to the `GitHub discussion pages <https://github.com/markqvist/Reticulum/discussions>`_
|
||||
and propose adding an interface for the hardware.
|
||||
|
||||
|
||||
Develop a Program with Reticulum
|
||||
===========================================
|
||||
If you want to develop programs that use Reticulum, the easiest way to get
|
||||
|
@ -310,21 +341,26 @@ It is also possible to include Reticulum in apps compiled and distributed as
|
|||
Android APKs. A detailed tutorial and example source code will be included
|
||||
here at a later point.
|
||||
|
||||
Adding Radio Interfaces
|
||||
Pure-Python Reticulum
|
||||
==============================================
|
||||
Once you have Reticulum installed and working, you can add radio interfaces with
|
||||
any compatible hardware you have available. For information on how to configure
|
||||
this, see the :ref:`Interfaces<interfaces-main>` section of this manual.
|
||||
In some rare cases, and on more obscure system types, it is not possible to
|
||||
install one or more dependencies
|
||||
|
||||
A range of common LoRa development boards and transceiver modules can be used
|
||||
as interfaces with Reticulum. You can refer to the following external resources
|
||||
for more information:
|
||||
On more unusual systems, and in some rare cases, it might not be possible to
|
||||
install or even compile one or more of the above modules. In such situations,
|
||||
you can use the ``rnspure`` package instead of the ``rns`` package. The ``rnspure``
|
||||
package requires no external dependencies for installation. Please note that the
|
||||
actual contents of the ``rns`` and ``rnspure`` packages are *completely identical*.
|
||||
The only difference is that the ``rnspure`` package lists no dependencies required
|
||||
for installation.
|
||||
|
||||
* `How To Make Your Own RNodes <https://unsigned.io/how-to-make-your-own-rnodes/>`_
|
||||
* `Installing RNode Firmware on Compatible LoRa Devices <https://unsigned.io/installing-rnode-firmware-on-t-beam-and-lora32-devices/>`_
|
||||
* `Private, Secure and Uncensorable Messaging Over a LoRa Mesh <https://unsigned.io/private-messaging-over-lora/>`_
|
||||
* `RNode Firmware <https://github.com/markqvist/RNode_Firmware/>`_
|
||||
No matter how Reticulum is installed and started, it will load external dependencies
|
||||
only if they are *needed* and *available*. If for example you want to use Reticulum
|
||||
on a system that cannot support ``pyserial``, it is perfectly possible to do so using
|
||||
the `rnspure` package, but Reticulum will not be able to use serial-based interfaces.
|
||||
All other available modules will still be loaded when needed.
|
||||
|
||||
If you have communications hardware that you think would be suitable for use with Reticulum,
|
||||
you are welcome to head over to the `GitHub discussion pages <https://github.com/markqvist/Reticulum/discussions>`_
|
||||
and propose adding an interface for the hardware.
|
||||
**Please Note!** If you use the `rnspure` package to run Reticulum on systems that
|
||||
do not support `PyCA/cryptography <https://github.com/pyca/cryptography>`_, it is
|
||||
important that you read and understand the :ref:`Cryptographic Primitives <understanding-primitives>`
|
||||
section of this manual.
|
BIN
docs/source/graphics/board_heltec32.png
Normal file
BIN
docs/source/graphics/board_heltec32.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 191 KiB |
BIN
docs/source/graphics/board_rnode.png
Normal file
BIN
docs/source/graphics/board_rnode.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 259 KiB |
BIN
docs/source/graphics/board_t3v20.png
Normal file
BIN
docs/source/graphics/board_t3v20.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 249 KiB |
BIN
docs/source/graphics/board_t3v21.png
Normal file
BIN
docs/source/graphics/board_t3v21.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 236 KiB |
BIN
docs/source/graphics/board_tbeam.png
Normal file
BIN
docs/source/graphics/board_tbeam.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 191 KiB |
220
docs/source/hardware.rst
Normal file
220
docs/source/hardware.rst
Normal file
|
@ -0,0 +1,220 @@
|
|||
.. _hardware-main:
|
||||
|
||||
***********************
|
||||
Communications Hardware
|
||||
***********************
|
||||
|
||||
One of the truly valuable aspects of Reticulum is the ability to use it over
|
||||
almost any conceivable kind of communications medium. The :ref:`interface types<interfaces-main>`
|
||||
available for configuration in Reticulum are flexible enough to cover the use
|
||||
of most wired and wireless communications hardware available, from decades-old
|
||||
packet radio modems to modern millimeter-wave backhaul systems.
|
||||
|
||||
If you already have or operate some kind of communications hardware, there is a
|
||||
very good chance that it will work with Reticulum out of the box. In case it does
|
||||
not, it is possible to provide the necessary glue with very little effort using
|
||||
for example the :ref:`PipeInterface<interfaces-pipe>` or the :ref:`TCPClientInterface<interfaces-tcpc>`
|
||||
in combination with code like `TCP KISS Server <https://github.com/simplyequipped/tcpkissserver>`_
|
||||
by `simplyequipped <https://github.com/simplyequipped>`_.
|
||||
|
||||
While this broad support and flexibility is very useful, an abundance of options
|
||||
can sometimes make it difficult to know where to begin, especially when you are
|
||||
starting from scratch.
|
||||
|
||||
This chapter will outline a few different sensible easy starting paths to get
|
||||
real-world functional wireless communications up and running with minimal cost
|
||||
and effort. Two fundamental devices types will be covered, *RNodes* and *WiFi-based radios*.
|
||||
|
||||
.. _rnode-main:
|
||||
|
||||
RNode
|
||||
=====
|
||||
|
||||
Reliable and general-purpose long-range digital radio transceiver systems are
|
||||
commonly either very expensive, difficult to set up and operate, hard to source,
|
||||
power-hungry, or all of the above at the same time. In an attempt to alleviate
|
||||
this situation, the transceiver system *RNode* was designed. It is important to
|
||||
note that RNode is not one specific device, from one particular vendor, but
|
||||
*an open plaform* that anyone can use to build digital transceivers suited to
|
||||
their needs and particular situations.
|
||||
|
||||
An RNode is a general purpose, interoperable, low-power and long-range, reliable,
|
||||
open and flexible radio communications device. Depending on its components, it can
|
||||
operate on many different frequency bands, and use many different modulation
|
||||
schemes, but most commonly, and for the purposes of this chapter, we will limit
|
||||
the discussion to RNodes using *LoRa* modulation in common ISM bands.
|
||||
|
||||
**Avoid Confusion!** An RNode can use LoRa as a *physical-layer modulation*, but it
|
||||
does not use, and has nothing to do with the *LoRaWAN* protocol and standard, commonly
|
||||
used for IoT devices. RNodes use *raw LoRa modulation*, without any additional
|
||||
protocol overhead. All high-level protocol funcionality is handled directly by
|
||||
Reticulum.
|
||||
|
||||
.. _rnode-creating:
|
||||
|
||||
Creating RNodes
|
||||
^^^^^^^^^^^^^^^
|
||||
RNode has been designed as a system that is easy to replicate across time and
|
||||
space. You can put together a functioning transceiver using commonly available
|
||||
components, and a few software tools. While you can design and build RNodes
|
||||
completely from scratch, to your exact desired specifications, this chapter
|
||||
will explain the easiest possible approach to creating RNodes, which is using common
|
||||
LoRa development boards. This approach can be boiled down to two simple steps:
|
||||
|
||||
1. Obtain one or more supported development boards
|
||||
2. Install the RNode firmware with the automated installer
|
||||
|
||||
Once the firmware has been installed and provisioned by the install script, it
|
||||
is ready to use with any software that supports RNodes, including Reticulum.
|
||||
The device can be used with Reticulum by adding an :ref:`RNodeInterface<interfaces-rnode>`
|
||||
to the configuration.
|
||||
|
||||
.. _rnode-supported:
|
||||
|
||||
Supported Boards
|
||||
^^^^^^^^^^^^^^^^
|
||||
To create one or more RNodes, you will need to obtain supported development
|
||||
boards. The following boards are supported by the auto-installer.
|
||||
|
||||
LilyGO LoRa32 v2.1
|
||||
""""""""""""""""""
|
||||
.. image:: graphics/board_t3v21.png
|
||||
:width: 50%
|
||||
:align: center
|
||||
|
||||
- **Supported Firmware Lines** v1.x & v2.x
|
||||
- **Transceiver IC** Semtech SX1276
|
||||
- **Device Platform** ESP32
|
||||
- **Manufacturer** `LilyGO <https://lilygo.cn>`_
|
||||
|
||||
|
||||
LilyGO LoRa32 v2.0
|
||||
""""""""""""""""""
|
||||
.. image:: graphics/board_t3v20.png
|
||||
:width: 50%
|
||||
:align: center
|
||||
|
||||
- **Supported Firmware Lines** v1.x & v2.x
|
||||
- **Transceiver IC** Semtech SX1276
|
||||
- **Device Platform** ESP32
|
||||
- **Manufacturer** `LilyGO <https://lilygo.cn>`_
|
||||
|
||||
|
||||
LilyGO T-Beam
|
||||
"""""""""""""
|
||||
.. image:: graphics/board_tbeam.png
|
||||
:width: 65%
|
||||
:align: center
|
||||
|
||||
- **Supported Firmware Lines** v1.x & v2.x
|
||||
- **Transceiver IC** Semtech SX1276
|
||||
- **Device Platform** ESP32
|
||||
- **Manufacturer** `LilyGO <https://lilygo.cn>`_
|
||||
|
||||
|
||||
Heltec LoRa32 v2.0
|
||||
""""""""""""""""""
|
||||
.. image:: graphics/board_heltec32.png
|
||||
:width: 50%
|
||||
:align: center
|
||||
|
||||
- **Supported Firmware Lines** v1.x & v2.x
|
||||
- **Transceiver IC** Semtech SX1276
|
||||
- **Device Platform** ESP32
|
||||
- **Manufacturer** `Heltec Automation <https://heltec.org>`_
|
||||
|
||||
|
||||
Original RNode v1.x
|
||||
"""""""""""""""""""
|
||||
.. image:: graphics/board_rnode.png
|
||||
:width: 50%
|
||||
:align: center
|
||||
|
||||
- **Supported Firmware Lines** v1.x
|
||||
- **Transceiver IC** Semtech SX1276
|
||||
- **Device Platform** AVR ATmega1284p
|
||||
- **Manufacturer** `unsigned.io <https://unsigned.io>`_
|
||||
|
||||
|
||||
.. _rnode-installation:
|
||||
|
||||
Installation
|
||||
^^^^^^^^^^^^
|
||||
|
||||
Once you have obtained compatible boards, you can install the `RNode Firmware <https://github.com/markqvist/RNode_Firmware>`_
|
||||
using the `RNode Configuration Utility <https://github.com/markqvist/rnodeconfigutil>`_.
|
||||
Make sure that ``Python3`` and ``pip`` is installed on your system, and then install
|
||||
the config utility with ``pip``:
|
||||
|
||||
.. code::
|
||||
|
||||
pip3 install rnodeconf
|
||||
|
||||
Once installation has completed, it is time to start installing the firmware on your
|
||||
devices. Run ``rnodeconf`` in auto-install mode like so:
|
||||
|
||||
.. code::
|
||||
|
||||
rnodeconf --autoinstall
|
||||
|
||||
The utility will guide you through the installation process by asking a series of
|
||||
questions about your hardware. Simply follow the guide, and the utility will
|
||||
auto-install and configure your devices
|
||||
|
||||
**Important Note!** It is currently recommended to use the v1.x line of the RNode firmware,
|
||||
even though the v2.x line is available for early testing. The v2.x line should still be
|
||||
considered an experimental pre-release. Only use the v2.x firmware line if you want to test
|
||||
out the absolutely newest version, and don't care about stability.
|
||||
|
||||
.. _rnode-usage:
|
||||
|
||||
Usage with Reticulum
|
||||
^^^^^^^^^^^^^^^^^^^^
|
||||
When the devices have been installed and provisioned, you can use them with Reticulum
|
||||
by adding the :ref:`relevant interface section<interfaces-rnode>` to the configuration
|
||||
file of Reticulum. For v1.x firmwares, you will have to specify all interface parameters,
|
||||
such as serial port and on-air parameters. For v2.x firmwares, you just need to specify
|
||||
the Connection ID of the RNode, and Reticulum will automatically locate and connect to the
|
||||
RNode, using the parameters stored in the RNode itself.
|
||||
|
||||
.. _rnode-suppliers:
|
||||
|
||||
Suppliers
|
||||
^^^^^^^^^
|
||||
Get in touch if you want to have your RNode supplier listed here, or if you want help to
|
||||
get started with producing RNodes.
|
||||
|
||||
|
||||
WiFi-based Hardware
|
||||
===================
|
||||
|
||||
It is possible to use all kinds of both short- and long-range Wifi-based hardware
|
||||
with Reticulum. Any kind of hardware that fully supports bridged ethernet over the
|
||||
WiFi interface will work with the :ref:`AutoInterface<interfaces-auto>` in Reticulum.
|
||||
Most devices will behave like this by default, or allow it via configuration options.
|
||||
|
||||
This means that you can simply configure the physical links of the WiFi based devices,
|
||||
and start communicating over them using Reticulum. It is not necessary to enable any IP
|
||||
infrastructure such as DHCP servers, DNS or similar, as long as at least Ethernet is
|
||||
available, and packets are passed transparently over the physical WiFi-based devices.
|
||||
|
||||
Below is a list of example WiFi (and similar) radios that work well for high capacity
|
||||
Reticulum links over long distances:
|
||||
|
||||
- `Ubiquiti airMAX radios <https://store.ui.com/collections/operator-airmax-devices>`_
|
||||
- `Ubiquiti LTU radios <https://store.ui.com/collections/operator-ltu>`_
|
||||
- `MikroTik radios <https://mikrotik.com/products/group/wireless-systems>`_
|
||||
|
||||
This list is by no means exhaustive, and only serves as a few examples of radio hardware
|
||||
that is relatively cheap while providing long range and high capacity for Reticulum
|
||||
networks. As in all other cases, it is also possible for Reticulum to co-exist with IP
|
||||
networks running concurrently on such devices.
|
||||
|
||||
Combining Hardware Types
|
||||
========================
|
||||
|
||||
It is a useful tool to combine different link and hardware types when designing and
|
||||
building a network. One useful design pattern is to employ high-capacity point-to-point
|
||||
links based on WiFi or millimeter-wave radios (with high-gain directional antennas)
|
||||
for the network backbone, and using LoRa-based RNodes for covering large areas with
|
||||
connectivity for client devices.
|
|
@ -13,9 +13,11 @@ to participate in the development of Reticulum itself.
|
|||
using
|
||||
networks
|
||||
interfaces
|
||||
hardware
|
||||
understanding
|
||||
reference
|
||||
examples
|
||||
support
|
||||
|
||||
|
||||
.. only:: html
|
||||
|
|
|
@ -274,10 +274,6 @@ with all peers in your local ethernet broadcast domain, the
|
|||
:ref:`Auto Interface<interfaces-auto>` performs better, and is even
|
||||
easier to use.
|
||||
|
||||
The below example is enabled by default on new Reticulum installations,
|
||||
as it provides an easy way to get started and to test Reticulum on a
|
||||
pre-existing LAN.
|
||||
|
||||
.. code::
|
||||
|
||||
# This example enables communication with other
|
||||
|
|
36
docs/source/support.rst
Normal file
36
docs/source/support.rst
Normal file
|
@ -0,0 +1,36 @@
|
|||
.. _support-main:
|
||||
|
||||
*****************
|
||||
Support Reticulum
|
||||
*****************
|
||||
This reference guide lists and explains all classes exposed by the RNS API.
|
||||
|
||||
Donations
|
||||
=========
|
||||
You can help support the continued development of open, free and private communications systems by donating via one of the following channels:
|
||||
|
||||
Monero:
|
||||
|
||||
84FpY1QbxHcgdseePYNmhTHcrgMX4nFf
|
||||
BYtz2GKYToqHVVhJp8Eaw1Z1EedRnKD1
|
||||
9b3B8NiLCGVxzKV17UMmmeEsCrPyA5w
|
||||
|
||||
Ethereum
|
||||
|
||||
0x81F7B979fEa6134bA9FD5c701b3501A2e61E897a
|
||||
|
||||
Bitcoin
|
||||
|
||||
3CPmacGm34qYvR6XWLVEJmi2aNe3PZqUuq
|
||||
|
||||
Ko-Fi: https://ko-fi.com/markqvist
|
||||
|
||||
Are certain features in the development roadmap are important to you or your organisation? Make them a reality quickly by sponsoring their implementation.
|
||||
|
||||
Provide Feedback
|
||||
================
|
||||
All feedback on the usage, functioning and potential dysfunctioning of any and
|
||||
all components of the system is very valuable to the continued development and
|
||||
improvement of Reticulum. Absolutely no automated analytics, telemetly, error
|
||||
reporting or statistics is collected and reported by Reticulum under any
|
||||
circumstances, so we rely on old-fashioned human feedback.
|
|
@ -839,3 +839,52 @@ of the different interface modes, and how they are configured.
|
|||
Boundary ── ✓ ──┤ ├── ✓ ── Boundary
|
||||
Roaming ─── ✕ ──┘ └── ✕ ── Roaming
|
||||
|
||||
|
||||
.. _understanding-primitives:
|
||||
|
||||
Cryptographic Primitives
|
||||
------------------------
|
||||
|
||||
Reticulum has been designed to use a simple suite of efficient, strong and modern
|
||||
cryptographic primitives, with widely available implementations that can be used
|
||||
both on general-purpose CPUs and on microcontrollers. The necessary primitives are:
|
||||
|
||||
* Ed25519 for signatures
|
||||
|
||||
* X22519 for ECDH key exchanges
|
||||
|
||||
* HKDF for key derivation
|
||||
|
||||
* Fernet for encrypted tokens
|
||||
|
||||
* AES-128 in CBC mode
|
||||
|
||||
* HMAC for message authentication
|
||||
|
||||
* SHA-256
|
||||
|
||||
* SHA-512
|
||||
|
||||
In the default installation configuration, the ``X25519``, ``Ed25519`` and ``AES-128-CBC``
|
||||
primitives are provided by `OpenSSL <https://www.openssl.org/>`_ (via the `PyCA/cryptography <https://github.com/pyca/cryptography>`_
|
||||
package). The hashing functions ``SHA-256`` and ``SHA-512`` are provided by the standard
|
||||
Python `hashlib <https://docs.python.org/3/library/hashlib.html>`_. The ``HKDF``, ``HMAC``,
|
||||
``Fernet`` primitives, and the ``PKCS7`` padding function are always provided by the
|
||||
following internal implementations:
|
||||
|
||||
- ``RNS/Cryptography/HKDF.py``
|
||||
- ``RNS/Cryptography/HMAC.py``
|
||||
- ``RNS/Cryptography/Fernet.py``
|
||||
- ``RNS/Cryptography/PKCS7.py``
|
||||
|
||||
|
||||
Reticulum also includes a complete implementation of all necessary primitives in pure Python.
|
||||
If OpenSSL & PyCA are not available on the system when Reticulum is started, Reticulum will
|
||||
instead use the internal pure-python primitives. A trivial consequence of this is performance,
|
||||
with the OpenSSL backend being *much* faster. The most important consequence however, is the
|
||||
potential loss of security by using primitives that has not seen the same amount of scrutiny,
|
||||
testing and review as those from OpenSSL.
|
||||
|
||||
If you want to use the internal pure-python primitives, it is **highly advisable** that you
|
||||
have a good understanding of the risks that this pose, and make an informed decision on whether
|
||||
those risks are acceptable to you.
|
Loading…
Add table
Add a link
Reference in a new issue