summaryrefslogtreecommitdiff
path: root/docs
diff options
context:
space:
mode:
Diffstat (limited to 'docs')
-rw-r--r--docs/src/about.md11
-rw-r--r--docs/src/api/go/example.md72
-rw-r--r--docs/src/api/go/functions.md11
-rw-r--r--docs/src/api/overview/README.md2
-rw-r--r--docs/src/api/overview/getconfig.md9
-rw-r--r--docs/src/api/python/example.md49
-rw-r--r--docs/src/api/python/functions.md49
-rw-r--r--docs/src/gettingstarted/README.md2
-rw-r--r--docs/src/gettingstarted/building/python.md2
-rw-r--r--docs/src/gettingstarted/debugging/fsm.md8
-rw-r--r--docs/src/gettingstarted/debugging/fsm_example.svg2
-rw-r--r--docs/src/godifferences.pngbin0 -> 73985 bytes
12 files changed, 76 insertions, 141 deletions
diff --git a/docs/src/about.md b/docs/src/about.md
index e2715c0..672ae6a 100644
--- a/docs/src/about.md
+++ b/docs/src/about.md
@@ -1,8 +1,8 @@
# About
This chapter contains background information for the library. We give a general introduction to eduVPN and explain what problems this library aims to solve.
-## eduVPN introduction
-eduVPN-common is a library for [eduVPN](https://www.eduvpn.org/), which is a VPN by [Surf](https://www.surf.nl) for research institutions such as Universities. Each institution that uses eduVPN has its own server. To discover these servers and establish a VPN connection with them, eduVPN clients are used. eduVPN has clients for each common platform:
+## EduVPN introduction
+eduVPN-common is a library for [eduVPN](https://www.eduvpn.org/), which is a VPN by [SURF](https://www.surf.nl) and a project by [GÉANT](https://geant.org/), for research institutes such as Universities. Each institute that uses eduVPN has its own server. To discover these servers and establish a VPN connection with them, eduVPN clients are used. eduVPN has clients for each common platform:
- [Android](https://github.com/eduvpn/android)
- [Linux](https://github.com/eduvpn/python-eduvpn-client)
- [MacOS/iOS](https://github.com/eduvpn/apple)
@@ -12,8 +12,13 @@ eduVPN-common is a library for [eduVPN](https://www.eduvpn.org/), which is a VPN
However, as these clients are rather similar in functionality, apart from platform specific differences, right now there is duplicate code between them. For example, the process to discover institution's servers, the authorization process (OAuth) and Wireguard key generation.
This goal of this library is to provide the common functionality between these clients into one codebase. The library is written in the [Go](https://go.dev/) language and has wrapper code for each of the languages that are used by the current clients.
+The main goal is thus the following:
+![](./godifferences.png)
+
+This library tries to remove non-platform specific common functionality. This way eduVPN clients have less duplicate code.
+
## License
[MIT](https://github.com/jwijenbergh/eduvpn-common/blob/main/LICENSE)
## Authors
-This library is written by [Steven Wallis de Vries](https://github.com/stevenwdv) and [Jeroen Wijenbergh](https://github.com/jwijenbergh), two Radboud University students that worked at Surf for their research internship.
+This library is written by [Steven Wallis de Vries](https://github.com/stevenwdv) and [Jeroen Wijenbergh](https://github.com/jwijenbergh), two Radboud University students that worked at SURF for their research internship.
diff --git a/docs/src/api/go/example.md b/docs/src/api/go/example.md
index e7b0d36..0ed7d02 100644
--- a/docs/src/api/go/example.md
+++ b/docs/src/api/go/example.md
@@ -1,63 +1,13 @@
-# Example with Comments
-
+# Example with comments
+The following is an example [in the repository](https://github.com/jwijenbergh/eduvpn-common/blob/main/cmd/cli/main.go). It is a command line client with the following flags
+```
+-get-institute string
+ The url of an institute to connect to
+-get-secure string
+ Gets secure internet servers.
+-get-secure-all string
+ Gets certificates for all secure internet servers. It stores them in ./certs. Provide an URL for the home server e.g. nl.eduvpn.org.
+```
```go
-
-// Bring the library into scope with the eduvpn prefix
-import eduvpn "github.com/jwijenbergh/eduvpn-common"
-
-// Callbacks
-
-func stateCallback(state *eduvpn.VPNState, oldState string, newState string, data string) {
-
- // OAuth is started, open the browser with the authorization URL
- if newState == "OAuth_Started" {
- openBrowser(data)
- }
-
- // Multiple profiles are found, we need to send a profile ID back using state.SetProfileID
- if newState == "Ask_Profile" {
- selectAndSendProfile(state, data)
- }
-}
-
-func main() {
- // Create the VPNState
- state := &eduvpn.VPNState{}
-
- // Register the state
- // We use linux so the client ID will be org.eduvpn.app.linux
- // We want to store the config files in configs
- // We wrap the callback with the state argument
- // And enable debugging
- registerErr := state.Register("org.eduvpn.app.linux", "configs", func(old string, new string, data string) {
- stateCallback(state, old, new, data)
- }, true)
-
- if registErr != nil {
- // handle the error of not being able to register
- }
-
- // Cleanup the library at the end
- defer state.Deregister()
-
- // Connect to an example server without forcing TCP
- config, configType, configErr := state.GetConnectConfig("eduvpn.example.com", false)
-
- if configErr != nil {
- // handle the error of not being able to get a config
- }
-
- if configType == "wireguard" {
- // Connect using wireguard with the config
- } else {
- // Connect using OpenVPN with the config
- }
-
- // We are connected
- setConnectErr := state.SetConnected()
-
- if setConnectErr != nil {
- // handle the error of not being able to call set connected
- }
-}
+{{#include ../../../../cmd/cli/main.go}}
```
diff --git a/docs/src/api/go/functions.md b/docs/src/api/go/functions.md
index c647787..381f5be 100644
--- a/docs/src/api/go/functions.md
+++ b/docs/src/api/go/functions.md
@@ -26,9 +26,10 @@ Returns a string of JSON data with the servers/organizations and an `error`, nil
## OpenVPN/Wireguard config
See [Overview](../overview/getconfig.html)
```go
-func GetConnectConfig(url string, forceTCP bool) (string, string, error)
+func GetConfigInstituteAccess(url string, forceTCP bool) (string, string, error)
+func GetConfigSecureInternet(url string, forceTCP bool) (string, string, error)
```
-- `url`: The url of the server to get a connect config for
+- `url`: The URL of the Institute Access or Secure Internet server to get a connect config for
- `forceTCP`: Whether or not we want to force enable TCP
Returns:
@@ -36,6 +37,12 @@ Returns:
- A `string`, `openvpn` or `wireguard` indicating if it is an OpenVPN or Wireguard config
- An `error` (can be nil)
+### Cancelling OAuth
+```go
+func CancelOAuth() error
+```
+Returns an `error`, can be nil indicating no error
+
### Setting a profile ID
```go
func SetProfileID(profileID string) error
diff --git a/docs/src/api/overview/README.md b/docs/src/api/overview/README.md
index d233b0c..8af056a 100644
--- a/docs/src/api/overview/README.md
+++ b/docs/src/api/overview/README.md
@@ -1,4 +1,4 @@
-# API Overview
+# API overview
This section defines the API in high-level, we explain what functions there are, what their use is and what a typical flow is for creating an eduVPN client with this library. The language specific documentation will be given in separate sections.
diff --git a/docs/src/api/overview/getconfig.md b/docs/src/api/overview/getconfig.md
index 70bcb39..ca35835 100644
--- a/docs/src/api/overview/getconfig.md
+++ b/docs/src/api/overview/getconfig.md
@@ -1,6 +1,6 @@
# Getting an OpenVPN/Wireguard config
## Summary
-name: `Get Connect Config`
+name: `Get Config Institute Access` and `Get Config Secure Internet`
| Arguments | Description | type |
| --------- | -------------------------------------- | -------- |
@@ -13,9 +13,10 @@ Used to obtain the OpenVPN/Wireguard config
## Detailed information
-To get a configuration that is used to actually establish a tunnel with the VPN server, we have the Get Connect Config (the exact name depends on the language you're using) function in the library. This function has two parameters *URL* and *Force TCP*.
+To get a configuration that is used to actually establish a tunnel with the VPN server, we have the Get Config function for Institute Access and Secure Internet (the exact name depends on the language you're using) function in the library. This function has two parameters *URL* and *Force TCP*.
-*URL* is the base url of the server to connect to e.g. `nl.eduvpn.org`. Note that this function does not need any further input whether or not we want to connect for institute access or secure internet. This is handled in the library by checking the discovery list. If it does not find the server in the discovery list, it assumes it wants to connect as an institute server.
+*URL* is the base url of the server to connect to
+e.g. `nl.eduvpn.org`. Use the correct function to indicate if it is an Institute Access server or a Secure Internet server. A user configured server is often an Institute Access server.
The *Force TCP* flag is a boolean that indicates whether or not we want to use TCP to connect over the VPN. This flag is useful if the user has enabled e.g. a setting that forces the use of TCP, which is only supported by OpenVPN. If the Force TCP flag is set to true but the server only supports Wireguard then an error is returned and the config will be empty.
@@ -33,6 +34,8 @@ The format of the authorization URL is e.g. this:
`https://eduvpn.example.com/vpn-user-portal/oauth/authorize?client_id=org.eduvpn.app.linux&code_challenge=DsmGyWFBkvDXiIO33Fs40Z0fn4pxtzDCW2jKvAMptBg&code_challenge_method=S256&redirect_uri=http%3A%2F%2F127.0.0.1%3A8000%2Fcallback&response_type=code&scope=config&state=vha2Krx-HpOyvFkWsWYmey0jrHQ6bnb06PQ6zBXX_bg`
+This callback can be cancelled by using a `Cancel OAuth` function.
+
### Callback: Selecting a profile
Another aspect that needs to be taken into account is the fact that there can be multiple profiles that a client can connect to. When the function gets called for obtaining an OpenVPN/Wireguard configuration, it asks the client which profile it wants to connect to using the callback that gets triggered on the Ask Profile state. The data is the list of profiles in JSON format, e.g.
diff --git a/docs/src/api/python/example.md b/docs/src/api/python/example.md
index 7c0997f..f371b68 100644
--- a/docs/src/api/python/example.md
+++ b/docs/src/api/python/example.md
@@ -1,48 +1,7 @@
-# Example with Comments
+# Example with comments
-```python
-import eduvpncommon.main as eduvpn
-
-# Callbacks
-@_eduvpn.event.on("OAuth_Started", eduvpn.StateType.Enter)
-def oauth_initialized(url):
- # Open the webbrowser with the url
- webbrowser.open(url)
-
-
-@_eduvpn.event.on("Ask_Profile", eduvpn.StateType.Enter)
-def ask_profile(profiles):
- # Set a profile
- _eduvpn.set_profile("example")
-
-# Register the state
-# We use linux so the client ID will be org.eduvpn.app.linux
-# We want to store the config files in configs
-# And enable debugging
-_eduvpn = eduvpn.EduVPN("org.eduvpn.app.linux", "configs")
-register_err = _eduvpn.register(debug=True)
-
-if register_err:
- # Handle error
+This is an example that can also be found [in the repository](https://github.com/jwijenbergh/eduvpn-common/blob/main/wrappers/python/main.py). It gets a config from an Institute Access server with support for multiple profiles.
-# Connect to eduvpn.example.com
-config, config_type, config_err = _eduvpn.get_connect_config("eduvpn.example.com", False)
-
-if config_err:
- # Handle error
-
-if config_type == "wireguard":
- # Connect using wireguard with the config
-elif config_type == "openvpn":
- # Connect using OpenVPN with the config
-else:
- # Handle error
-
-# Set connected
-set_connect_err = _eduvpn.set_connected()
-if set_connect_err:
- # Handle error
-
-# Handle cleanup
-_eduvpn.deregister()
+```python
+{{#include ../../../../wrappers/python/main.py}}
```
diff --git a/docs/src/api/python/functions.md b/docs/src/api/python/functions.md
index ebfb774..2a348cd 100644
--- a/docs/src/api/python/functions.md
+++ b/docs/src/api/python/functions.md
@@ -12,59 +12,70 @@ def __init__(self, name: str, directory: str)
## Registering
See [Overview](../overview/registering.html)
```python
-def register(self, debug=False: bool) -> Optional[str]
+def register(self, debug: bool = False) -> None
```
-- `debug`: Whether or not we want to enable debugging
+- `debug`: Whether or not we want to enable debugging, default: `False`
-Returns an optional `string` for the error message
+Returns nothing. Raises an exception in case of an error.
## Discovery
See [Overview](../overview/discovery.html)
```python
-def get_disco_servers(self) -> (Optional[str], Optional[str])
+def get_disco_servers(self) -> str
```
```python
-def get_disco_organizations(self) -> (Optional[str], Optional[str])
+def get_disco_organizations(self) -> str
```
-Returns an optional `string` of JSON data with the servers/organizations and an optional error message
+Returns a `string` of JSON data with the servers/organizations. Raises an exception in case of an error.
## OpenVPN/Wireguard config
See [Overview](../overview/getconfig.html)
```python
-def get_connect_config(self, url: str, forceTCP: bool) -> (Optional[str], Optional[str], Optional[str])
+def get_config_institute_access(self, url: str, forceTCP: bool = False) -> Tuple[str, str]
```
-- `url`: The url of the server to get a connect config for
-- `forceTCP`: Whether or not we want to force enable TCP
+```python
+def get_config_secure_internet(self, url: str, forceTCP: bool = False) -> Tuple[str, str]
+```
+- `url`: The url of the Secure Internet or Institute Access server to get a connect config for
+- `forceTCP`: Whether or not we want to force enable TCP, default: `False`
Returns:
-- An optional `string` of the OpenVPN/Wireguard config
-- An optional `string`, `openvpn` or `wireguard` indicating if it is an OpenVPN or Wireguard config
-- An optional error message `string`
+- A `string` of the OpenVPN/Wireguard config
+- An `string`, `openvpn` or `wireguard` indicating if it is an OpenVPN or Wireguard config
+
+Raises an exception in case of an error.
+
+### Cancelling OAuth
+```python
+def cancel_oauth(self) -> None
+```
+
+Returns nothing. Raises an exception in case of an error.
### Setting a profile ID
```python
-def set_profile(self, profile_id: str) -> Optional[str]
+def set_profile(self, profile_id: str) -> None
```
- `profile_id`: The profile ID to connect to
-Returns an optional `string`, which is the error message
+Returns nothing. Raises an exception in case of an errorr.
## Connecting/Disconnecting
See [Overview](../overview/connecting.html)
```python
-def set_connected(self) -> Optional[str]
+def set_connected(self) -> None
```
```python
-def set_disconnected(self) -> Optional[str]
+def set_disconnected(self) -> None
```
-Returns an optional `string`, which is the error message
+Returns an nothing. Raises an exception in case of an error.
## Deregister
See [Overview](../overview/deregistering.html)
```python
-def deregister() -> Optional[str]
+def deregister() -> None
```
-Returns an optional `string`, which is the error message
+Returns nothing. Raises an exception in case of an error.
diff --git a/docs/src/gettingstarted/README.md b/docs/src/gettingstarted/README.md
index 7c7912d..d2c7455 100644
--- a/docs/src/gettingstarted/README.md
+++ b/docs/src/gettingstarted/README.md
@@ -1,4 +1,4 @@
-# Getting Started
+# Getting started
This chapter contains the steps to get started with the Go library. You will learn how to build the library, how to run the test suite and how to debug possible errors.
The documentation on how to use this library will be given in the next chapter: [API](../api/index.html).
diff --git a/docs/src/gettingstarted/building/python.md b/docs/src/gettingstarted/building/python.md
index 6995f9e..78ce424 100644
--- a/docs/src/gettingstarted/building/python.md
+++ b/docs/src/gettingstarted/building/python.md
@@ -1,4 +1,4 @@
-# Python Wrapper
+# Python wrapper
To build the python wrapper issue the following command (in the root directory of the eduvpn-common project):
diff --git a/docs/src/gettingstarted/debugging/fsm.md b/docs/src/gettingstarted/debugging/fsm.md
index 11d51de..8479a92 100644
--- a/docs/src/gettingstarted/debugging/fsm.md
+++ b/docs/src/gettingstarted/debugging/fsm.md
@@ -1,6 +1,6 @@
-# Finite State Machine
+# Finite state machine
-The eduvpn-common library uses a Finite State Machine internally to keep track of which state the client is in and to communicate data callbacks (e.g. to communicate the Authorization URL in the OAuth process to the client).
+The eduvpn-common library uses a finite state machine internally to keep track of which state the client is in and to communicate data callbacks (e.g. to communicate the Authorization URL in the OAuth process to the client).
## Viewing the FSM
To view the FSM in an image, set the debug variable to `True`. This outputs the graph with a `.graph` extension in the client-specified config directory (See [API](../../api/index.html)). The format of this graph is from [Mermaid](https://mermaid-js.github.io/mermaid/#/).
@@ -9,7 +9,7 @@ If you have the [Mermaid command line client](https://github.com/mermaid-js/merm
If you do not want to install additional tools to view the graph, you can submit the contents of the `.graph` file to the [Mermaid Live Editor](https://mermaid.live/) to see the image.
-## FSM Example
+## FSM example
The following is an example of the FSM when the client has obtained a Wireguard/OpenVPN configuration from an eduVPN server
![](./fsm_example.svg)
@@ -21,7 +21,7 @@ The states mean the following:
- `Deregistered`: The client has not registered with the library yet, the state variables are not initialized
- `No_Server`: The client is registered, but has not chosen a server yet
-- `Chosen_ServeR`: The client has chosen a server to connect to
+- `Chosen_Server`: The client has chosen a server to connect to
- `OAuth_Started`: The OAuth process has been started. This means that the client needs to redirect to the browser so that the user can login and approve the application
- `Authorized`: The OAuth process has finished. The client now has tokens and is thus authorized
- `Request_Config`: The client is in the process of requesting an OpenVPN/Wireguard configuration from the server
diff --git a/docs/src/gettingstarted/debugging/fsm_example.svg b/docs/src/gettingstarted/debugging/fsm_example.svg
index 9b19280..134b0fb 100644
--- a/docs/src/gettingstarted/debugging/fsm_example.svg
+++ b/docs/src/gettingstarted/debugging/fsm_example.svg
@@ -1 +1 @@
-<svg id="mermaid-1650984468240" width="100%" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" height="796" style="max-width: 1009.15px; background-color: white;" viewBox="0 0 1009.15234375 796"><style>#mermaid-1650984468240 {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-1650984468240 .error-icon{fill:#552222;}#mermaid-1650984468240 .error-text{fill:#552222;stroke:#552222;}#mermaid-1650984468240 .edge-thickness-normal{stroke-width:2px;}#mermaid-1650984468240 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-1650984468240 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-1650984468240 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-1650984468240 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-1650984468240 .marker{fill:#333333;stroke:#333333;}#mermaid-1650984468240 .marker.cross{stroke:#333333;}#mermaid-1650984468240 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-1650984468240 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-1650984468240 .cluster-label text{fill:#333;}#mermaid-1650984468240 .cluster-label span{color:#333;}#mermaid-1650984468240 .label text,#mermaid-1650984468240 span{fill:#333;color:#333;}#mermaid-1650984468240 .node rect,#mermaid-1650984468240 .node circle,#mermaid-1650984468240 .node ellipse,#mermaid-1650984468240 .node polygon,#mermaid-1650984468240 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-1650984468240 .node .label{text-align:center;}#mermaid-1650984468240 .node.clickable{cursor:pointer;}#mermaid-1650984468240 .arrowheadPath{fill:#333333;}#mermaid-1650984468240 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-1650984468240 .flowchart-link{stroke:#333333;fill:none;}#mermaid-1650984468240 .edgeLabel{background-color:#e8e8e8;text-align:center;}#mermaid-1650984468240 .edgeLabel rect{opacity:0.5;background-color:#e8e8e8;fill:#e8e8e8;}#mermaid-1650984468240 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-1650984468240 .cluster text{fill:#333;}#mermaid-1650984468240 .cluster span{color:#333;}#mermaid-1650984468240 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-1650984468240 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}</style><g><g class="output"><g class="clusters"></g><g class="edgePaths"><g class="edgePath LS-Deregistered LE-No_Server" id="L-Deregistered-No_Server" style="opacity: 1;"><path class="path" d="M377.39453125,46L377.39453125,51.666666666666664C377.39453125,57.333333333333336,377.39453125,68.66666666666667,377.39453125,80C377.39453125,91.33333333333333,377.39453125,102.66666666666667,377.39453125,108.33333333333333L377.39453125,114" marker-end="url(#arrowhead71)" style="fill:none"></path><defs><marker id="arrowhead71" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath LS-No_Server LE-Chosen_Server" id="L-No_Server-Chosen_Server" style="opacity: 1;"><path class="path" d="M377.39453125,152L377.39453125,157.66666666666666C377.39453125,163.33333333333334,377.39453125,174.66666666666666,377.39453125,186C377.39453125,197.33333333333334,377.39453125,208.66666666666666,377.39453125,214.33333333333334L377.39453125,220" marker-end="url(#arrowhead72)" style="fill:none"></path><defs><marker id="arrowhead72" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath LS-Chosen_Server LE-Authorized" id="L-Chosen_Server-Authorized" style="opacity: 1;"><path class="path" d="M377.39453125,258L377.39453125,263.6666666666667C377.39453125,269.3333333333333,377.39453125,280.6666666666667,377.39453125,292C377.39453125,303.3333333333333,377.39453125,314.6666666666667,377.39453125,320.3333333333333L377.39453125,326" marker-end="url(#arrowhead73)" style="fill:none"></path><defs><marker id="arrowhead73" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath LS-Chosen_Server LE-OAuth_Started" id="L-Chosen_Server-OAuth_Started" style="opacity: 1;"><path class="path" d="M311.80859375,251.45392075910038L276.220703125,258.21160063258367C240.6328125,264.9692805060669,169.45703125,278.48464025303343,133.869140625,294.07565345985006C98.28125,309.6666666666667,98.28125,327.3333333333333,98.28125,345C98.28125,362.6666666666667,98.28125,380.3333333333333,128.71028645833334,395.7359725470853C159.13932291666666,411.1386117608372,219.99739583333334,424.2772235216744,250.42643229166666,430.846529402093L280.85546875,437.4158352825115" marker-end="url(#arrowhead74)" style="fill:none"></path><defs><marker id="arrowhead74" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath LS-OAuth_Started LE-Authorized" id="L-OAuth_Started-Authorized" style="opacity: 1;"><path class="path" d="M369.5760613207547,432L377.27041568396226,426.3333333333333C384.9647700471698,420.6666666666667,400.35347877358487,409.3333333333333,403.9477692610063,398C407.5420597484277,386.6666666666667,399.3419319968554,375.3333333333333,395.2418681210692,369.6666666666667L391.141804245283,364" marker-end="url(#arrowhead75)" style="fill:none"></path><defs><marker id="arrowhead75" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath LS-OAuth_Started LE-Chosen_Server" id="L-OAuth_Started-Chosen_Server" style="opacity: 1;"><path class="path" d="M406.69921875,434.7339430313423L430.3821614583333,428.6116191927852C454.0651041666667,422.4892953542282,501.4309895833333,410.2446476771141,525.1139322916666,395.2889905052237C548.796875,380.3333333333333,548.796875,362.6666666666667,548.796875,345C548.796875,327.3333333333333,548.796875,309.6666666666667,530.4708382468554,295.1666666666667C512.1448014937107,280.6666666666667,475.4927279874214,269.3333333333333,457.1666912342768,263.6666666666667L438.8406544811321,258" marker-end="url(#arrowhead76)" style="fill:none"></path><defs><marker id="arrowhead76" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath LS-Authorized LE-OAuth_Started" id="L-Authorized-OAuth_Started" style="opacity: 1;"><path class="path" d="M329.14453125,359.8714477181345L308.5266927083333,366.2262064317788C287.9088541666667,372.580965145423,246.67317708333334,385.2904825727115,240.8463910180818,397.31190795302246C235.01960495283018,409.3333333333333,264.60170990566036,420.6666666666667,279.3927623820755,426.3333333333333L294.18381485849056,432" marker-end="url(#arrowhead77)" style="fill:none"></path><defs><marker id="arrowhead77" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath LS-Authorized LE-Request_Config" id="L-Authorized-Request_Config" style="opacity: 1;"><path class="path" d="M425.64453125,354.29895882160764L463.4368489583333,361.582465684673C501.2291666666667,368.8659725477384,576.8138020833334,383.4329862738692,614.6061197916666,396.3831598036013C652.3984375,409.3333333333333,652.3984375,420.6666666666667,652.3984375,426.3333333333333L652.3984375,432" marker-end="url(#arrowhead78)" style="fill:none"></path><defs><marker id="arrowhead78" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath LS-Request_Config LE-Ask_Profile" id="L-Request_Config-Ask_Profile" style="opacity: 1;"><path class="path" d="M683.6585347877359,470L692.9817216981132,475.6666666666667C702.3049086084906,481.3333333333333,720.9512824292452,492.6666666666667,730.2744693396226,504C739.59765625,515.3333333333334,739.59765625,526.6666666666666,739.59765625,532.3333333333334L739.59765625,538" marker-end="url(#arrowhead79)" style="fill:none"></path><defs><marker id="arrowhead79" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath LS-Request_Config LE-Has_Config" id="L-Request_Config-Has_Config" style="opacity: 1;"><path class="path" d="M621.1383402122641,470L611.8151533018868,475.6666666666667C602.4919663915094,481.3333333333333,583.8455925707548,492.6666666666667,574.5224056603773,507.1666666666667C565.19921875,521.6666666666666,565.19921875,539.3333333333334,565.19921875,557C565.19921875,574.6666666666666,565.19921875,592.3333333333334,574.5224056603773,606.8333333333334C583.8455925707548,621.3333333333334,602.4919663915094,632.6666666666666,611.8151533018868,638.3333333333334L621.1383402122641,644" marker-end="url(#arrowhead80)" style="fill:none"></path><defs><marker id="arrowhead80" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath LS-Has_Config LE-Connected" id="L-Has_Config-Connected" style="opacity: 1;"><path class="path" d="M652.3984375,682L652.3984375,687.6666666666666C652.3984375,693.3333333333334,652.3984375,704.6666666666666,664.6927820361635,716C676.987126572327,727.3333333333334,701.5758156446541,738.6666666666666,713.8701601808176,744.3333333333334L726.1645047169811,750" marker-end="url(#arrowhead81)" style="fill:none"></path><defs><marker id="arrowhead81" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath LS-Ask_Profile LE-Has_Config" id="L-Ask_Profile-Has_Config" style="opacity: 1;"><path class="path" d="M739.59765625,576L739.59765625,581.6666666666666C739.59765625,587.3333333333334,739.59765625,598.6666666666666,730.2744693396227,610C720.9512824292452,621.3333333333334,702.3049086084906,632.6666666666666,692.9817216981132,638.3333333333334L683.6585347877359,644" marker-end="url(#arrowhead82)" style="fill:none"></path><defs><marker id="arrowhead82" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath LS-Connected LE-Authorized" id="L-Connected-Authorized" style="opacity: 1;"><path class="path" d="M816.08203125,751.2888162127385L832.2526041666666,745.4073468439487C848.4231770833334,739.5258774751591,880.7643229166666,727.7629387375795,896.9348958333334,713.0481360354564C913.10546875,698.3333333333334,913.10546875,680.6666666666666,913.10546875,663C913.10546875,645.3333333333334,913.10546875,627.6666666666666,913.10546875,610C913.10546875,592.3333333333334,913.10546875,574.6666666666666,913.10546875,557C913.10546875,539.3333333333334,913.10546875,521.6666666666666,913.10546875,504C913.10546875,486.3333333333333,913.10546875,468.6666666666667,913.10546875,451C913.10546875,433.3333333333333,913.10546875,415.6666666666667,831.8619791666666,398.7955938613505C750.6184895833334,381.92452105603434,588.1315104166666,365.84904211206873,506.8880208333333,357.8113026400859L425.64453125,349.7735631681031" marker-end="url(#arrowhead83)" style="fill:none"></path><defs><marker id="arrowhead83" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g></g><g class="edgeLabels"><g class="edgeLabel" transform="translate(377.39453125,80)" style="opacity: 1;"><g transform="translate(-53.3515625,-9)" class="label"><rect rx="0" ry="0" width="106.703125" height="18"></rect><foreignObject width="106.703125" height="18"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span id="L-L-Deregistered-No_Server" class="edgeLabel L-LS-Deregistered' L-LE-No_Server">Client registers</span></div></foreignObject></g></g><g class="edgeLabel" transform="translate(377.39453125,186)" style="opacity: 1;"><g transform="translate(-80.03125,-9)" class="label"><rect rx="0" ry="0" width="160.0625" height="18"></rect><foreignObject width="160.0625" height="18"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span id="L-L-No_Server-Chosen_Server" class="edgeLabel L-LS-No_Server' L-LE-Chosen_Server">User chooses a server</span></div></foreignObject></g></g><g class="edgeLabel" transform="translate(377.39453125,292)" style="opacity: 1;"><g transform="translate(-80.5,-9)" class="label"><rect rx="0" ry="0" width="161" height="18"></rect><foreignObject width="161" height="18"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span id="L-L-Chosen_Server-Authorized" class="edgeLabel L-LS-Chosen_Server' L-LE-Authorized">Found tokens in config</span></div></foreignObject></g></g><g class="edgeLabel" transform="translate(98.28125,345)" style="opacity: 1;"><g transform="translate(-90.28125,-9)" class="label"><rect rx="0" ry="0" width="180.5625" height="18"></rect><foreignObject width="180.5625" height="18"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span id="L-L-Chosen_Server-OAuth_Started" class="edgeLabel L-LS-Chosen_Server' L-LE-OAuth_Started">No tokens found in config</span></div></foreignObject></g></g><g class="edgeLabel" transform="translate(415.7421875,398)" style="opacity: 1;"><g transform="translate(-103.1484375,-9)" class="label"><rect rx="0" ry="0" width="206.296875" height="18"></rect><foreignObject width="206.296875" height="18"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span id="L-L-OAuth_Started-Authorized" class="edgeLabel L-LS-OAuth_Started' L-LE-Authorized">User authorizes with browser</span></div></foreignObject></g></g><g class="edgeLabel" transform="translate(548.796875,345)" style="opacity: 1;"><g transform="translate(-49.8046875,-9)" class="label"><rect rx="0" ry="0" width="99.609375" height="18"></rect><foreignObject width="99.609375" height="18"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span id="L-L-OAuth_Started-Chosen_Server" class="edgeLabel L-LS-OAuth_Started' L-LE-Chosen_Server">Cancel OAuth</span></div></foreignObject></g></g><g class="edgeLabel" transform="translate(205.4375,398)" style="opacity: 1;"><g transform="translate(-87.15625,-9)" class="label"><rect rx="0" ry="0" width="174.3125" height="18"></rect><foreignObject width="174.3125" height="18"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span id="L-L-Authorized-OAuth_Started" class="edgeLabel L-LS-Authorized' L-LE-OAuth_Started">Re-authorize with OAuth</span></div></foreignObject></g></g><g class="edgeLabel" transform="translate(652.3984375,398)" style="opacity: 1;"><g transform="translate(-83.6015625,-9)" class="label"><rect rx="0" ry="0" width="167.203125" height="18"></rect><foreignObject width="167.203125" height="18"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span id="L-L-Authorized-Request_Config" class="edgeLabel L-LS-Authorized' L-LE-Request_Config">Client requests a config</span></div></foreignObject></g></g><g class="edgeLabel" transform="translate(739.59765625,504)" style="opacity: 1;"><g transform="translate(-77.8203125,-9)" class="label"><rect rx="0" ry="0" width="155.640625" height="18"></rect><foreignObject width="155.640625" height="18"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span id="L-L-Request_Config-Ask_Profile" class="edgeLabel L-LS-Request_Config' L-LE-Ask_Profile">Multiple profiles found</span></div></foreignObject></g></g><g class="edgeLabel" transform="translate(565.19921875,557)" style="opacity: 1;"><g transform="translate(-88.9375,-9)" class="label"><rect rx="0" ry="0" width="177.875" height="18"></rect><foreignObject width="177.875" height="18"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span id="L-L-Request_Config-Has_Config" class="edgeLabel L-LS-Request_Config' L-LE-Has_Config">Success, only one profile</span></div></foreignObject></g></g><g class="edgeLabel" transform="translate(652.3984375,716)" style="opacity: 1;"><g transform="translate(-77.8203125,-9)" class="label"><rect rx="0" ry="0" width="155.640625" height="18"></rect><foreignObject width="155.640625" height="18"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span id="L-L-Has_Config-Connected" class="edgeLabel L-LS-Has_Config' L-LE-Connected">OS reports connected</span></div></foreignObject></g></g><g class="edgeLabel" transform="translate(739.59765625,610)" style="opacity: 1;"><g transform="translate(-119.6171875,-9)" class="label"><rect rx="0" ry="0" width="239.234375" height="18"></rect><foreignObject width="239.234375" height="18"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span id="L-L-Ask_Profile-Has_Config" class="edgeLabel L-LS-Ask_Profile' L-LE-Has_Config">User chooses profile and success</span></div></foreignObject></g></g><g class="edgeLabel" transform="translate(913.10546875,557)" style="opacity: 1;"><g transform="translate(-88.046875,-9)" class="label"><rect rx="0" ry="0" width="176.09375" height="18"></rect><foreignObject width="176.09375" height="18"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span id="L-L-Connected-Authorized" class="edgeLabel L-LS-Connected' L-LE-Authorized">OS reports disconnected</span></div></foreignObject></g></g></g><g class="nodes"><g class="node default" id="flowchart-Deregistered-39" transform="translate(377.39453125,27)" style="opacity: 1;"><rect rx="5" ry="5" x="-55.8046875" y="-19" width="111.609375" height="38" class="label-container" style="fill:white;"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-45.8046875,-9)"><foreignObject width="91.609375" height="18"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;">Deregistered</div></foreignObject></g></g></g><g class="node default" id="flowchart-No_Server-41" transform="translate(377.39453125,133)" style="opacity: 1;"><rect rx="5" ry="5" x="-48.2421875" y="-19" width="96.484375" height="38" class="label-container" style="fill:white;"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-38.2421875,-9)"><foreignObject width="76.484375" height="18"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;">No_Server</div></foreignObject></g></g></g><g class="node default" id="flowchart-Chosen_Server-44" transform="translate(377.39453125,239)" style="opacity: 1;"><rect rx="5" ry="5" x="-65.5859375" y="-19" width="131.171875" height="38" class="label-container" style="fill:white;fill:white;"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-55.5859375,-9)"><foreignObject width="111.171875" height="18"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;">Chosen_Server</div></foreignObject></g></g></g><g class="node default" id="flowchart-Authorized-47" transform="translate(377.39453125,345)" style="opacity: 1;"><rect rx="5" ry="5" x="-48.25" y="-19" width="96.5" height="38" class="label-container" style="fill:white;fill:white;"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-38.25,-9)"><foreignObject width="76.5" height="18"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;">Authorized</div></foreignObject></g></g></g><g class="node default" id="flowchart-OAuth_Started-50" transform="translate(343.77734375,451)" style="opacity: 1;"><rect rx="5" ry="5" x="-62.921875" y="-19" width="125.84375" height="38" class="label-container" style="fill:white;fill:white;"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-52.921875,-9)"><foreignObject width="105.84375" height="18"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;">OAuth_Started</div></foreignObject></g></g></g><g class="node default" id="flowchart-Request_Config-62" transform="translate(652.3984375,451)" style="opacity: 1;"><rect rx="5" ry="5" x="-67.375" y="-19" width="134.75" height="38" class="label-container" style="fill:white;fill:white;"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-57.375,-9)"><foreignObject width="114.75" height="18"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;">Request_Config</div></foreignObject></g></g></g><g class="node default" id="flowchart-Ask_Profile-65" transform="translate(739.59765625,557)" style="opacity: 1;"><rect rx="5" ry="5" x="-50.4609375" y="-19" width="100.921875" height="38" class="label-container" style="fill:white;"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-40.4609375,-9)"><foreignObject width="80.921875" height="18"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;">Ask_Profile</div></foreignObject></g></g></g><g class="node default" id="flowchart-Has_Config-68" transform="translate(652.3984375,663)" style="opacity: 1;"><rect rx="5" ry="5" x="-51.8046875" y="-19" width="103.609375" height="38" class="label-container" style="fill:cyan;"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-41.8046875,-9)"><foreignObject width="83.609375" height="18"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;">Has_Config</div></foreignObject></g></g></g><g class="node default" id="flowchart-Connected-71" transform="translate(767.38671875,769)" style="opacity: 1;"><rect rx="5" ry="5" x="-48.6953125" y="-19" width="97.390625" height="38" class="label-container" style="fill:white;"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-38.6953125,-9)"><foreignObject width="77.390625" height="18"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;">Connected</div></foreignObject></g></g></g></g></g></g></svg> \ No newline at end of file
+<svg id="mermaid-1652441732449" width="100%" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" height="796" style="max-width: 1351.44px; background-color: white;" viewBox="0 0 1351.4375 796"><style>#mermaid-1652441732449 {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-1652441732449 .error-icon{fill:#552222;}#mermaid-1652441732449 .error-text{fill:#552222;stroke:#552222;}#mermaid-1652441732449 .edge-thickness-normal{stroke-width:2px;}#mermaid-1652441732449 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-1652441732449 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-1652441732449 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-1652441732449 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-1652441732449 .marker{fill:#333333;stroke:#333333;}#mermaid-1652441732449 .marker.cross{stroke:#333333;}#mermaid-1652441732449 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-1652441732449 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-1652441732449 .cluster-label text{fill:#333;}#mermaid-1652441732449 .cluster-label span{color:#333;}#mermaid-1652441732449 .label text,#mermaid-1652441732449 span{fill:#333;color:#333;}#mermaid-1652441732449 .node rect,#mermaid-1652441732449 .node circle,#mermaid-1652441732449 .node ellipse,#mermaid-1652441732449 .node polygon,#mermaid-1652441732449 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-1652441732449 .node .label{text-align:center;}#mermaid-1652441732449 .node.clickable{cursor:pointer;}#mermaid-1652441732449 .arrowheadPath{fill:#333333;}#mermaid-1652441732449 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-1652441732449 .flowchart-link{stroke:#333333;fill:none;}#mermaid-1652441732449 .edgeLabel{background-color:#e8e8e8;text-align:center;}#mermaid-1652441732449 .edgeLabel rect{opacity:0.5;background-color:#e8e8e8;fill:#e8e8e8;}#mermaid-1652441732449 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-1652441732449 .cluster text{fill:#333;}#mermaid-1652441732449 .cluster span{color:#333;}#mermaid-1652441732449 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-1652441732449 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}</style><g><g class="output"><g class="clusters"></g><g class="edgePaths"><g class="edgePath LS-Deregistered LE-No_Server" id="L-Deregistered-No_Server" style="opacity: 1;"><path class="path" d="M855.8828125,46L855.8828125,51.666666666666664C855.8828125,57.333333333333336,855.8828125,68.66666666666667,855.8828125,80C855.8828125,91.33333333333333,855.8828125,102.66666666666667,855.8828125,108.33333333333333L855.8828125,114" marker-end="url(#arrowhead109)" style="fill:none"></path><defs><marker id="arrowhead109" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath LS-No_Server LE-Chosen_Server" id="L-No_Server-Chosen_Server" style="opacity: 1;"><path class="path" d="M807.640625,136.6325343663113L698.369140625,144.86044530525942C589.09765625,153.08835624420752,370.5546875,169.54417812210377,261.283203125,183.43875572771856C152.01171875,197.33333333333334,152.01171875,208.66666666666666,152.01171875,214.33333333333334L152.01171875,220" marker-end="url(#arrowhead110)" style="fill:none"></path><defs><marker id="arrowhead110" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath LS-Chosen_Server LE-Authorized" id="L-Chosen_Server-Authorized" style="opacity: 1;"><path class="path" d="M209.98076356132077,258L227.26977692610066,263.6666666666667C244.55879029088052,269.3333333333333,279.1368170204403,280.6666666666667,296.42583038522014,292C313.71484375,303.3333333333333,313.71484375,314.6666666666667,313.71484375,320.3333333333333L313.71484375,326" marker-end="url(#arrowhead111)" style="fill:none"></path><defs><marker id="arrowhead111" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath LS-Chosen_Server LE-OAuth_Started" id="L-Chosen_Server-OAuth_Started" style="opacity: 1;"><path class="path" d="M132.74985259433961,258L127.00508549528301,263.6666666666667C121.26031839622641,269.3333333333333,109.77078419811319,280.6666666666667,104.0260170990566,295.1666666666667C98.28125,309.6666666666667,98.28125,327.3333333333333,98.28125,345C98.28125,362.6666666666667,98.28125,380.3333333333333,98.28125,398C98.28125,415.6666666666667,98.28125,433.3333333333333,98.28125,451C98.28125,468.6666666666667,98.28125,486.3333333333333,119.537109375,501.081704507387C140.79296875,515.8300756814406,183.3046875,527.6601513628813,204.560546875,533.5751892036016L225.81640625,539.4902270443218" marker-end="url(#arrowhead112)" style="fill:none"></path><defs><marker id="arrowhead112" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath LS-OAuth_Started LE-Authorized" id="L-OAuth_Started-Authorized" style="opacity: 1;"><path class="path" d="M335.38826650943395,538L349.3014200078616,532.3333333333334C363.2145735062893,526.6666666666666,391.0408805031446,515.3333333333334,404.9540340015723,500.8333333333333C418.8671875,486.3333333333333,418.8671875,468.6666666666667,418.8671875,451C418.8671875,433.3333333333333,418.8671875,415.6666666666667,407.6244840801887,401.1666666666667C396.3817806603774,386.6666666666667,373.8963738207547,375.3333333333333,362.65367040094344,369.6666666666667L351.4109669811321,364" marker-end="url(#arrowhead113)" style="fill:none"></path><defs><marker id="arrowhead113" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath LS-OAuth_Started LE-No_Server" id="L-OAuth_Started-No_Server" style="opacity: 1;"><path class="path" d="M351.66015625,544.1957405324334L384.5813802083333,537.4964504436945C417.5026041666667,530.7971603549556,483.3450520833333,517.3985801774778,516.2662760416666,501.86595675540553C549.1875,486.3333333333333,549.1875,468.6666666666667,549.1875,451C549.1875,433.3333333333333,549.1875,415.6666666666667,549.1875,398C549.1875,380.3333333333333,549.1875,362.6666666666667,549.1875,345C549.1875,327.3333333333333,549.1875,309.6666666666667,549.1875,292C549.1875,274.3333333333333,549.1875,256.6666666666667,549.1875,239C549.1875,221.33333333333334,549.1875,203.66666666666666,592.2630208333334,187.3894549592005C635.3385416666666,171.1122432517343,721.4895833333334,156.2244865034686,764.5651041666666,148.78060812933575L807.640625,141.3367297552029" marker-end="url(#arrowhead114)" style="fill:none"></path><defs><marker id="arrowhead114" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath LS-Authorized LE-OAuth_Started" id="L-Authorized-OAuth_Started" style="opacity: 1;"><path class="path" d="M276.0187205188679,364L264.77601709905656,369.6666666666667C253.53331367924525,375.3333333333333,231.04790683962264,386.6666666666667,219.8052034198113,401.1666666666667C208.5625,415.6666666666667,208.5625,433.3333333333333,208.5625,451C208.5625,468.6666666666667,208.5625,486.3333333333333,217.13475334119497,500.8333333333333C225.70700668238996,515.3333333333334,242.85151336477986,526.6666666666666,251.42376670597483,532.3333333333334L259.9960200471698,538" marker-end="url(#arrowhead115)" style="fill:none"></path><defs><marker id="arrowhead115" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath LS-Authorized LE-Request_Config" id="L-Authorized-Request_Config" style="opacity: 1;"><path class="path" d="M361.96484375,352.5418591523335L410.435546875,360.1182159602779C458.90625,367.6945727682223,555.84765625,382.84728638411116,610.6236119300314,396.09030985872226C665.399567610063,409.3333333333333,678.0100727201258,420.6666666666667,684.3153252751572,426.3333333333333L690.6205778301887,432" marker-end="url(#arrowhead116)" style="fill:none"></path><defs><marker id="arrowhead116" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath LS-Request_Config LE-Ask_Profile" id="L-Request_Config-Ask_Profile" style="opacity: 1;"><path class="path" d="M750.6537441037735,470L762.2531200864779,475.6666666666667C773.8524960691824,481.3333333333333,797.0512480345911,492.6666666666667,818.85546875,504C840.6596894654089,515.3333333333334,861.0693789308176,526.6666666666666,871.2742236635221,532.3333333333334L881.4790683962265,538" marker-end="url(#arrowhead117)" style="fill:none"></path><defs><marker id="arrowhead117" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath LS-Request_Config LE-Has_Config" id="L-Request_Config-Has_Config" style="opacity: 1;"><path class="path" d="M677.5454746462265,470L667.3406299135221,475.6666666666667C657.1357851808176,481.3333333333333,636.7260957154089,492.6666666666667,626.5212509827044,507.1666666666667C616.31640625,521.6666666666666,616.31640625,539.3333333333334,616.31640625,557C616.31640625,574.6666666666666,616.31640625,592.3333333333334,671.5462239583334,608.8057733149838C726.7760416666666,625.2782132966341,837.2356770833334,640.5564265932684,892.4654947916666,648.1955332415855L947.6953125,655.8346398899026" marker-end="url(#arrowhead118)" style="fill:none"></path><defs><marker id="arrowhead118" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath LS-Request_Config LE-No_Server" id="L-Request_Config-No_Server" style="opacity: 1;"><path class="path" d="M760.8567216981132,432L775.4990909984277,426.3333333333333C790.1414602987421,420.6666666666667,819.4261988993711,409.3333333333333,834.0685681996856,394.8333333333333C848.7109375,380.3333333333333,848.7109375,362.6666666666667,848.7109375,345C848.7109375,327.3333333333333,848.7109375,309.6666666666667,848.7109375,292C848.7109375,274.3333333333333,848.7109375,256.6666666666667,848.7109375,239C848.7109375,221.33333333333334,848.7109375,203.66666666666666,849.477741745283,189.16666666666666C850.244545990566,174.66666666666666,851.778154481132,163.33333333333334,852.5449587264151,157.66666666666666L853.3117629716982,152" marker-end="url(#arrowhead119)" style="fill:none"></path><defs><marker id="arrowhead119" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath LS-Request_Config LE-OAuth_Started" id="L-Request_Config-OAuth_Started" style="opacity: 1;"><path class="path" d="M644.38671875,459.9709911678116L589.2747395833334,467.3091593065096C534.1627604166666,474.64732744520774,423.9388020833333,489.32366372260384,366.15637283805034,502.3284985279686C308.3739435927673,515.3333333333334,303.0330434355346,526.6666666666666,300.36259335691824,532.3333333333334L297.6921432783019,538" marker-end="url(#arrowhead120)" style="fill:none"></path><defs><marker id="arrowhead120" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath LS-Has_Config LE-Connected" id="L-Has_Config-Connected" style="opacity: 1;"><path class="path" d="M966.1841833726415,682L956.2478871855346,687.6666666666666C946.3115909984277,693.3333333333334,926.4389986242139,704.6666666666666,926.4389986242137,716C926.4389986242139,727.3333333333334,946.3115909984277,738.6666666666666,956.2478871855346,744.3333333333334L966.1841833726415,750" marker-end="url(#arrowhead121)" style="fill:none"></path><defs><marker id="arrowhead121" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath LS-Has_Config LE-Request_Config" id="L-Has_Config-Request_Config" style="opacity: 1;"><path class="path" d="M1036.245283018868,644L1047.2044025157231,638.3333333333334C1058.1635220125786,632.6666666666666,1080.0817610062893,621.3333333333334,1091.0408805031445,606.8333333333334C1102,592.3333333333334,1102,574.6666666666666,1102,557C1102,539.3333333333334,1102,521.6666666666666,1048.189453125,505.52508316566735C994.37890625,489.383499664668,886.7578125,474.766999329336,832.947265625,467.45874916167L779.13671875,460.15049899400407" marker-end="url(#arrowhead122)" style="fill:none"></path><defs><marker id="arrowhead122" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath LS-Has_Config LE-No_Server" id="L-Has_Config-No_Server" style="opacity: 1;"><path class="path" d="M1051.3046875,650.4623452606044L1079.1692708333333,643.7186210505037C1107.0338541666667,636.974896840403,1162.7630208333333,623.4874484202014,1190.6276041666667,607.9103908767673C1218.4921875,592.3333333333334,1218.4921875,574.6666666666666,1218.4921875,557C1218.4921875,539.3333333333334,1218.4921875,521.6666666666666,1218.4921875,504C1218.4921875,486.3333333333333,1218.4921875,468.6666666666667,1218.4921875,451C1218.4921875,433.3333333333333,1218.4921875,415.6666666666667,1218.4921875,398C1218.4921875,380.3333333333333,1218.4921875,362.6666666666667,1218.4921875,345C1218.4921875,327.3333333333333,1218.4921875,309.6666666666667,1218.4921875,292C1218.4921875,274.3333333333333,1218.4921875,256.6666666666667,1218.4921875,239C1218.4921875,221.33333333333334,1218.4921875,203.66666666666666,1166.09765625,187.17520216601312C1113.703125,170.6837376653596,1008.9140625,155.36747533071917,956.51953125,147.70934416339898L904.125,140.05121299607876" marker-end="url(#arrowhead123)" style="fill:none"></path><defs><marker id="arrowhead123" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath LS-Ask_Profile LE-Has_Config" id="L-Ask_Profile-Has_Config" style="opacity: 1;"><path class="path" d="M915.6953125,576L915.6953125,581.6666666666666C915.6953125,587.3333333333334,915.6953125,598.6666666666666,924.6555621069183,610C933.6158117138365,621.3333333333334,951.5363109276728,632.6666666666666,960.4965605345911,638.3333333333334L969.4568101415094,644" marker-end="url(#arrowhead124)" style="fill:none"></path><defs><marker id="arrowhead124" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath LS-Ask_Profile LE-No_Server" id="L-Ask_Profile-No_Server" style="opacity: 1;"><path class="path" d="M944.7694575471698,538L953.4406937893082,532.3333333333334C962.1119300314466,526.6666666666666,979.4544025157232,515.3333333333334,988.1256387578616,500.8333333333333C996.796875,486.3333333333333,996.796875,468.6666666666667,996.796875,451C996.796875,433.3333333333333,996.796875,415.6666666666667,996.796875,398C996.796875,380.3333333333333,996.796875,362.6666666666667,996.796875,345C996.796875,327.3333333333333,996.796875,309.6666666666667,996.796875,292C996.796875,274.3333333333333,996.796875,256.6666666666667,996.796875,239C996.796875,221.33333333333334,996.796875,203.66666666666666,981.3515625,189.0241078523775C965.90625,174.38154903808837,935.015625,162.76309807617676,919.5703125,156.95387259522093L904.125,151.14464711426513" marker-end="url(#arrowhead125)" style="fill:none"></path><defs><marker id="arrowhead125" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath LS-Connected LE-Has_Config" id="L-Connected-Has_Config" style="opacity: 1;"><path class="path" d="M1032.8158166273586,750L1042.7521128144656,744.3333333333334C1052.6884090015724,738.6666666666666,1072.5610013757862,727.3333333333334,1072.5610013757862,716C1072.5610013757862,704.6666666666666,1052.6884090015724,693.3333333333334,1042.7521128144656,687.6666666666666L1032.8158166273586,682" marker-end="url(#arrowhead126)" style="fill:none"></path><defs><marker id="arrowhead126" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g></g><g class="edgeLabels"><g class="edgeLabel" transform="translate(855.8828125,80)" style="opacity: 1;"><g transform="translate(-53.3515625,-9)" class="label"><rect rx="0" ry="0" width="106.703125" height="18"></rect><foreignObject width="106.703125" height="18"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span id="L-L-Deregistered-No_Server" class="edgeLabel L-LS-Deregistered' L-LE-No_Server">Client registers</span></div></foreignObject></g></g><g class="edgeLabel" transform="translate(152.01171875,186)" style="opacity: 1;"><g transform="translate(-80.03125,-9)" class="label"><rect rx="0" ry="0" width="160.0625" height="18"></rect><foreignObject width="160.0625" height="18"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span id="L-L-No_Server-Chosen_Server" class="edgeLabel L-LS-No_Server' L-LE-Chosen_Server">User chooses a server</span></div></foreignObject></g></g><g class="edgeLabel" transform="translate(313.71484375,292)" style="opacity: 1;"><g transform="translate(-80.5,-9)" class="label"><rect rx="0" ry="0" width="161" height="18"></rect><foreignObject width="161" height="18"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span id="L-L-Chosen_Server-Authorized" class="edgeLabel L-LS-Chosen_Server' L-LE-Authorized">Found tokens in config</span></div></foreignObject></g></g><g class="edgeLabel" transform="translate(98.28125,398)" style="opacity: 1;"><g transform="translate(-90.28125,-9)" class="label"><rect rx="0" ry="0" width="180.5625" height="18"></rect><foreignObject width="180.5625" height="18"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span id="L-L-Chosen_Server-OAuth_Started" class="edgeLabel L-LS-Chosen_Server' L-LE-OAuth_Started">No tokens found in config</span></div></foreignObject></g></g><g class="edgeLabel" transform="translate(418.8671875,451)" style="opacity: 1;"><g transform="translate(-103.1484375,-9)" class="label"><rect rx="0" ry="0" width="206.296875" height="18"></rect><foreignObject width="206.296875" height="18"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span id="L-L-OAuth_Started-Authorized" class="edgeLabel L-LS-OAuth_Started' L-LE-Authorized">User authorizes with browser</span></div></foreignObject></g></g><g class="edgeLabel" transform="translate(549.1875,345)" style="opacity: 1;"><g transform="translate(-54.2421875,-9)" class="label"><rect rx="0" ry="0" width="108.484375" height="18"></rect><foreignObject width="108.484375" height="18"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span id="L-L-OAuth_Started-No_Server" class="edgeLabel L-LS-OAuth_Started' L-LE-No_Server">Cancel or Error</span></div></foreignObject></g></g><g class="edgeLabel" transform="translate(208.5625,451)" style="opacity: 1;"><g transform="translate(-87.15625,-9)" class="label"><rect rx="0" ry="0" width="174.3125" height="18"></rect><foreignObject width="174.3125" height="18"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span id="L-L-Authorized-OAuth_Started" class="edgeLabel L-LS-Authorized' L-LE-OAuth_Started">Re-authorize with OAuth</span></div></foreignObject></g></g><g class="edgeLabel" transform="translate(652.7890625,398)" style="opacity: 1;"><g transform="translate(-83.6015625,-9)" class="label"><rect rx="0" ry="0" width="167.203125" height="18"></rect><foreignObject width="167.203125" height="18"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span id="L-L-Authorized-Request_Config" class="edgeLabel L-LS-Authorized' L-LE-Request_Config">Client requests a config</span></div></foreignObject></g></g><g class="edgeLabel" transform="translate(820.25,504)" style="opacity: 1;"><g transform="translate(-156.546875,-9)" class="label"><rect rx="0" ry="0" width="313.09375" height="18"></rect><foreignObject width="313.09375" height="18"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span id="L-L-Request_Config-Ask_Profile" class="edgeLabel L-LS-Request_Config' L-LE-Ask_Profile">Multiple profiles found and no profile chosen</span></div></foreignObject></g></g><g class="edgeLabel" transform="translate(616.31640625,557)" style="opacity: 1;"><g transform="translate(-145.859375,-9)" class="label"><rect rx="0" ry="0" width="291.71875" height="18"></rect><foreignObject width="291.71875" height="18"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span id="L-L-Request_Config-Has_Config" class="edgeLabel L-LS-Request_Config' L-LE-Has_Config">Only one profile or profile already chosen</span></div></foreignObject></g></g><g class="edgeLabel" transform="translate(848.7109375,292)" style="opacity: 1;"><g transform="translate(-54.2421875,-9)" class="label"><rect rx="0" ry="0" width="108.484375" height="18"></rect><foreignObject width="108.484375" height="18"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span id="L-L-Request_Config-No_Server" class="edgeLabel L-LS-Request_Config' L-LE-No_Server">Cancel or Error</span></div></foreignObject></g></g><g class="edgeLabel" transform="translate(313.71484375,504)" style="opacity: 1;"><g transform="translate(-45.8046875,-9)" class="label"><rect rx="0" ry="0" width="91.609375" height="18"></rect><foreignObject width="91.609375" height="18"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span id="L-L-Request_Config-OAuth_Started" class="edgeLabel L-LS-Request_Config' L-LE-OAuth_Started">Re-authorize</span></div></foreignObject></g></g><g class="edgeLabel" transform="translate(906.56640625,716)" style="opacity: 1;"><g transform="translate(-77.8203125,-9)" class="label"><rect rx="0" ry="0" width="155.640625" height="18"></rect><foreignObject width="155.640625" height="18"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span id="L-L-Has_Config-Connected" class="edgeLabel L-LS-Has_Config' L-LE-Connected">OS reports connected</span></div></foreignObject></g></g><g class="edgeLabel" transform="translate(1102,557)" style="opacity: 1;"><g transform="translate(-96.4921875,-9)" class="label"><rect rx="0" ry="0" width="192.984375" height="18"></rect><foreignObject width="192.984375" height="18"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span id="L-L-Has_Config-Request_Config" class="edgeLabel L-LS-Has_Config' L-LE-Request_Config">User chooses a new profile</span></div></foreignObject></g></g><g class="edgeLabel" transform="translate(1218.4921875,398)" style="opacity: 1;"><g transform="translate(-124.9453125,-9)" class="label"><rect rx="0" ry="0" width="249.890625" height="18"></rect><foreignObject width="249.890625" height="18"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span id="L-L-Has_Config-No_Server" class="edgeLabel L-LS-Has_Config' L-LE-No_Server">User wants to choose a new server</span></div></foreignObject></g></g><g class="edgeLabel" transform="translate(915.6953125,610)" style="opacity: 1;"><g transform="translate(-72.921875,-9)" class="label"><rect rx="0" ry="0" width="145.84375" height="18"></rect><foreignObject width="145.84375" height="18"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span id="L-L-Ask_Profile-Has_Config" class="edgeLabel L-LS-Ask_Profile' L-LE-Has_Config">User chooses profile</span></div></foreignObject></g></g><g class="edgeLabel" transform="translate(996.796875,345)" style="opacity: 1;"><g transform="translate(-99.625,-9)" class="label"><rect rx="0" ry="0" width="199.25" height="18"></rect><foreignObject width="199.25" height="18"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span id="L-L-Ask_Profile-No_Server" class="edgeLabel L-LS-Ask_Profile' L-LE-No_Server">Done but no profile selected</span></div></foreignObject></g></g><g class="edgeLabel" transform="translate(1092.43359375,716)" style="opacity: 1;"><g transform="translate(-88.046875,-9)" class="label"><rect rx="0" ry="0" width="176.09375" height="18"></rect><foreignObject width="176.09375" height="18"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span id="L-L-Connected-Has_Config" class="edgeLabel L-LS-Connected' L-LE-Has_Config">OS reports disconnected</span></div></foreignObject></g></g></g><g class="nodes"><g class="node default" id="flowchart-Deregistered-54" transform="translate(855.8828125,27)" style="opacity: 1;"><rect rx="5" ry="5" x="-55.8046875" y="-19" width="111.609375" height="38" class="label-container" style="fill:white;"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-45.8046875,-9)"><foreignObject width="91.609375" height="18"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;">Deregistered</div></foreignObject></g></g></g><g class="node default" id="flowchart-No_Server-56" transform="translate(855.8828125,133)" style="opacity: 1;"><rect rx="5" ry="5" x="-48.2421875" y="-19" width="96.484375" height="38" class="label-container" style="fill:white;"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-38.2421875,-9)"><foreignObject width="76.484375" height="18"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;">No_Server</div></foreignObject></g></g></g><g class="node default" id="flowchart-Chosen_Server-59" transform="translate(152.01171875,239)" style="opacity: 1;"><rect rx="5" ry="5" x="-65.5859375" y="-19" width="131.171875" height="38" class="label-container" style="fill:white;fill:white;"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-55.5859375,-9)"><foreignObject width="111.171875" height="18"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;">Chosen_Server</div></foreignObject></g></g></g><g class="node default" id="flowchart-Authorized-62" transform="translate(313.71484375,345)" style="opacity: 1;"><rect rx="5" ry="5" x="-48.25" y="-19" width="96.5" height="38" class="label-container" style="fill:white;fill:white;"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-38.25,-9)"><foreignObject width="76.5" height="18"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;">Authorized</div></foreignObject></g></g></g><g class="node default" id="flowchart-OAuth_Started-65" transform="translate(288.73828125,557)" style="opacity: 1;"><rect rx="5" ry="5" x="-62.921875" y="-19" width="125.84375" height="38" class="label-container" style="fill:white;fill:white;"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-52.921875,-9)"><foreignObject width="105.84375" height="18"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;">OAuth_Started</div></foreignObject></g></g></g><g class="node default" id="flowchart-Request_Config-77" transform="translate(711.76171875,451)" style="opacity: 1;"><rect rx="5" ry="5" x="-67.375" y="-19" width="134.75" height="38" class="label-container" style="fill:white;fill:white;fill:white;fill:white;"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-57.375,-9)"><foreignObject width="114.75" height="18"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;">Request_Config</div></foreignObject></g></g></g><g class="node default" id="flowchart-Ask_Profile-80" transform="translate(915.6953125,557)" style="opacity: 1;"><rect rx="5" ry="5" x="-50.4609375" y="-19" width="100.921875" height="38" class="label-container" style="fill:white;fill:white;"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-40.4609375,-9)"><foreignObject width="80.921875" height="18"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;">Ask_Profile</div></foreignObject></g></g></g><g class="node default" id="flowchart-Has_Config-83" transform="translate(999.5,663)" style="opacity: 1;"><rect rx="5" ry="5" x="-51.8046875" y="-19" width="103.609375" height="38" class="label-container" style="fill:cyan;fill:cyan;fill:cyan;"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-41.8046875,-9)"><foreignObject width="83.609375" height="18"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;">Has_Config</div></foreignObject></g></g></g><g class="node default" id="flowchart-Connected-92" transform="translate(999.5,769)" style="opacity: 1;"><rect rx="5" ry="5" x="-48.6953125" y="-19" width="97.390625" height="38" class="label-container" style="fill:white;"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-38.6953125,-9)"><foreignObject width="77.390625" height="18"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;">Connected</div></foreignObject></g></g></g></g></g></g></svg> \ No newline at end of file
diff --git a/docs/src/godifferences.png b/docs/src/godifferences.png
new file mode 100644
index 0000000..916afd2
--- /dev/null
+++ b/docs/src/godifferences.png
Binary files differ