diff --git a/sphinx/Makefile b/sphinx/Makefile new file mode 100644 index 0000000..d4bb2cb --- /dev/null +++ b/sphinx/Makefile @@ -0,0 +1,20 @@ +# Minimal makefile for Sphinx documentation +# + +# You can set these variables from the command line, and also +# from the environment for the first two. +SPHINXOPTS ?= +SPHINXBUILD ?= sphinx-build +SOURCEDIR = . +BUILDDIR = _build + +# Put it first so that "make" without argument is like "make help". +help: + @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) + +.PHONY: help Makefile + +# Catch-all target: route all unknown targets to Sphinx using the new +# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). +%: Makefile + @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) diff --git a/sphinx/_static/css/custom.css b/sphinx/_static/css/custom.css new file mode 100644 index 0000000..6cc94d6 --- /dev/null +++ b/sphinx/_static/css/custom.css @@ -0,0 +1,29 @@ +.class { + padding-bottom: 15px; + padding-top: 15px; +} + +.function { + padding-bottom: 15px; + padding-top: 15px; +} + +.method { + /* border-bottom: 3px solid #d0d0d0; */ + padding-bottom: 15px; + padding-top: 15px; +} + +.attribute { + padding-bottom: 15px; + padding-top: 15px; +} + +.admonition-todo { + color: orangered; + border: 3px dashed orangered; +} + +section { + padding-top: 20px; +} \ No newline at end of file diff --git a/sphinx/_templates/layout.html b/sphinx/_templates/layout.html new file mode 100644 index 0000000..138cda6 --- /dev/null +++ b/sphinx/_templates/layout.html @@ -0,0 +1,2 @@ +{% extends "!layout.html" %} +{% set css_files = css_files + [ "../_static/css/functions.css" ] %} \ No newline at end of file diff --git a/sphinx/conf.py b/sphinx/conf.py new file mode 100644 index 0000000..acd636f --- /dev/null +++ b/sphinx/conf.py @@ -0,0 +1,74 @@ +# Configuration file for the Sphinx documentation builder. +# +# This file only contains a selection of the most common options. For a full +# list see the documentation: +# https://www.sphinx-doc.org/en/master/usage/configuration.html + +# -- Path setup -------------------------------------------------------------- + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. +# +import os +import sys +sys.path.insert(0, os.path.abspath('../skill')) + + +# -- Project information ----------------------------------------------------- + +project = 'AskNavidrome' +copyright = '2022, Ross Stewart' +author = 'Ross Stewart' + +# The full version, including alpha/beta/rc tags +release = '0.1' + + +# -- General configuration --------------------------------------------------- + +# Add any Sphinx extension module names here, as strings. They can be +# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom +# ones. +extensions = [ + 'rinoh.frontend.sphinx', + 'sphinx.ext.autodoc', + 'autodocsumm', + 'sphinx.ext.todo' +] + +autodoc_default_options = {"autosummary": True} +autoclass_content = 'both' +autodoc_member_order = 'groupwise' + +todo_include_todos = True + + +# Add any paths that contain templates here, relative to this directory. +templates_path = ['_templates'] + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +# This pattern also affects html_static_path and html_extra_path. +exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] + + +# -- Options for HTML output ------------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. +# +html_theme = 'groundwork' + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +html_static_path = ['_static'] + +html_css_files = [ + 'css/custom.css', +] + +latex_elements = { + 'extraclassoptions': 'openany,oneside' +} diff --git a/sphinx/index.rst b/sphinx/index.rst new file mode 100644 index 0000000..de2e3ae --- /dev/null +++ b/sphinx/index.rst @@ -0,0 +1,442 @@ +.. AskNavidrome documentation master file, created by + sphinx-quickstart on Sat Jul 2 13:52:30 2022. + You can adapt this file completely to your liking, but it should at least + contain the root `toctree` directive. + +**AskNavidrome Alexa Skill Documentation** +========================================== + +**AskNavidrome** is an Alexa skill which allows you to play music hosted on a SubSonic API compatible media server, like Navidrome. + +This allows to you stream your own music collection to your Echo devices without the restrictions you would normally face with regular +streaming services like Amazon Music or Spotify. AskNavidrome allows you to: + +- Skip backwards and forwards in your current queue or playlist without limitation. +- Avoid paying subscription costs. +- Avoid being forced to listen to adverts at regular intervals. +- Actually use the music collection you have already paid for! +- Run the service on a PC directly or inside a Docker container. + +This skill was inspired by `AskSonic `_, however AskSonic was missing two features I required, +the ability to play playlists and the ability to play an individual song. Instead of contributing to that project I have opted to +create a new skill based on the **Alexa Skills Kit SDK for Python** as this has been updated more recently than *flask-ask* which is used +by AskSonic, AskNavidrome is not a replacement for AskSonic and it does not implement all of AskSonic's features, it is however a viable +alternative for those that would like a simple skill to let you stream your own music collection. + +.. warning:: + The skill requires a username and password for your Navidrome installation which is stored in clear text. As the web service needs to be + publicly accessible there is a chance that this password could be compromised. Please do not use an administrative account for your + Navidrome installation or a password that you use on any other service. This software is distributed under the MIT license and no warranty + is provided. + + +Requirements +************ + +In order to use AskNavidrome you will need: + +**Your Music Collection** + +Your collection needs to have been converted to a digital format like MP3. There are many tutorials available on the web to help you do this, but do +be aware that there are limitations on the types of files that Echo devices can stream. You should review these before converting your collection as if +you do not meet the requirements they will need to be transcoded before your Echo device can stream them. This article explains `Amazon's +Audio Stream Requirements `_ + +**A SubSonic API Compatible Media Server** + +I use Navidrome, but you can use any flavour of SubSonic that you like. For information on getting and setting up Navidrome +check out their website `Navidrome `_. Your media server must be available on port 443 and serve requests using +https with a valid TLS certificate, these are requirements dictated by Amazon and you must meet them or you will be unable to stream your collection. +The media server needs to be publicly accessible from the Internet, in addition to allowing you to use this skill you will then be able to use any +SubSonic API compatible mobile app to listen to your collection too. + +You can get free TLS certificates from `Let's Encrypt `_ + +You can set up dynamic DNS to make your media server accessible for free with `afraid.org `_ + +**Tags** + +This may seem obvious but you need to make sure that your collection is accurately tagged with information like the artist, title, track number etc. +as this is the only way that your media server can identify the music in your collection. If you need a tool to help with this have a look at +`MusicBrainz Picard `_. + +**An Amazon Echo Device** + +You need something to listen to your music on! + + +About the AskNavidrome Skill +**************************** + +.. image:: resources/AskNavidrome_Diagram.png + :width: 800 + :align: center + :alt: AskNavidrome Overview Diagram + +The skill consists of two parts, the actual Alexa skill and the web service service which allows the skill to connect to your SubSonic API +compatible media server. The web service needs to have a valid TLS certificate, the easiest way to enable this is to run the web service +behind a reverse proxy, the web service also needs to be publicly accessible on the Internet to allow the Alexa skill to access the service. + + +Supported Intents +***************** + ++-------------------------------------------+--------------------------------------------+-------------------------------------+ +| Intent Name | Description | Example | ++===========================================+============================================+=====================================+ +| :class:`~app.NaviSonicPlayMusicByArtist` | Play music by a specific artist | Play Where is my Mind by The Pixies | ++-------------------------------------------+--------------------------------------------+-------------------------------------+ +| :class:`~app.NaviSonicPlayAlbumByArtist` | Play a specific album by a specific artist | Play The Blue Album by The Beatles | ++-------------------------------------------+--------------------------------------------+-------------------------------------+ +| :class:`~app.NaviSonicPlaySongByArtist` | Play a specific song by a specific artist | Play the song Help by The Beatles | ++-------------------------------------------+--------------------------------------------+-------------------------------------+ +| :class:`~app.NaviSonicPlayPlaylist` | Play a playlist | Play the playlist work music | ++-------------------------------------------+--------------------------------------------+-------------------------------------+ +| :class:`~app.NaviSonicPlayMusicByGenre` | Play music with a specific genre | Play jazz music | ++-------------------------------------------+--------------------------------------------+-------------------------------------+ +| :class:`~app.NaviSonicPlayMusicRandom` | Play a random mix of songs | Play random songs | ++-------------------------------------------+--------------------------------------------+-------------------------------------+ +| :class:`~app.NaviSonicPlayFavouriteSongs` | Play your starred / favourite songs | Play my favourite songs | ++-------------------------------------------+--------------------------------------------+-------------------------------------+ +| :class:`~app.NaviSonicSongDetails` | Give details on the playing track | What is playing | ++-------------------------------------------+--------------------------------------------+-------------------------------------+ +| :class:`~app.NaviSonicStarSong` | Star / favourite a song | Star this song | ++-------------------------------------------+--------------------------------------------+-------------------------------------+ +| :class:`~app.NaviSonicUnstarSong` | Unstar / unfavourite a song | Unstar this song | ++-------------------------------------------+--------------------------------------------+-------------------------------------+ + +The following control intents are also supported: + +- :class:`Next / Skip ` +- :class:`Previous / Back ` +- :class:`Pause ` +- :class:`Resume ` + +Due to the way that Alexa skills operate there are some limitations. Full music Alexa skills require a catalog of content to be provided and this defeats +the purpose of being able to search and stream from your own server directly. Because of this a custom skill type is used along with the AudioPlayer interface, +but this has some limitations: + +1. You need to open the skill to use it, say *Alexa, open Navisonic*. +2. Some intents that you would expect to be able to use when a track is playing need a full skill invocation. For example if you want to get + information on the track that is playing you will need to invoke the skill and call the intent by saying the following while the track is playing: + + - Alexa, open Navisonic + - What is playing? + + You will then be given information about the current track and it will automatically resume. This is also required for the *star* and *unstar* intents. + + +Installation and Setup +********************** + +Creating the AskNavidrome Alexa Skill +------------------------------------- + +#. Login to the Amazon Alexa Skills Kit Builder at https://developer.amazon.com. + - You must use the same account that is set on your Echo devices. +#. Click *Create Skill* +#. Configure the skill: + + .. image:: resources/create_skill_1.png + :width: 800 + :align: center + :alt: Skill Creation Step 1 + + + - Set *Skill name* to the name you wish to use to invoke the skill. This should be two words or a warning will be raised, I have found that a single word + still works when testing. It can be hard to find a good skill name so feel free to experiment! + - Set *Primary locale* to your locale, this **must** also be the locale set on your Echo device. + + .. note:: The locale setting is extremely important, if the skill locale and the locale set on your Echo device do not match the skill will not work. In + addition there are no error messages generated making the issue quite difficult to troubleshoot. The locale on your Echo device can be set via the Alexa Android + app. Please do check the locale setting if you have trouble setting up the skill as the Alexa Skill Builder will default to your local locale, but Echo devices + are set to the US locale by default. Checking this first will save you a few hours of troubleshooting! + + - Set sync locales to *No* + - Choose *Custom* as the model. + - Choose *Provision your own* as the hosting method for backend resources. + - Click *Create skill* again + +#. Choose the template + + .. image:: resources/create_skill_2.png + :width: 800 + :align: center + :alt: Skill Creation Step 2 + + - Choose *Start from Scratch* + - Click *Continue with template* and wait while the skill is created. + +#. Upload the intents + + .. image:: resources/create_skill_3.png + :width: 800 + :align: center + :alt: Skill Creation Step 3 + + - Click *Interaction Model*, then *JSON Editor* + - Delete everything that is currently in the editor and paste in the contents of **alexa.json** + - Click *Save Model* + +#. Configure playlists + + To be able to play your playlists you must add the name of each playlist to the *playlist_names* slot type. + You will need to maintain the list and add additional playlist names as you create them to allow them to + be played via the AskNavisonic skill. + + .. image:: resources/create_skill_4.png + :width: 800 + :align: center + :alt: Skill Creation Step 4 + + - Click *Slot Types*. + - Click *playlist_names*. + - Add and remove names as required. + - Click the *Save Model* button when you are done. + +#. Enable the Audio Player interface + + .. image:: resources/create_skill_5.png + :width: 800 + :align: center + :alt: Skill Creation Step 5 + + - Click *Interfaces*, enable *Audio Player*, then click *Save Interfaces* + +#. Set the endpoint + + The skill's endpoint is the location of the AskNavidrome web service. + + .. image:: resources/create_skill_6.png + :width: 800 + :align: center + :alt: Skill Creation Step 6 + + - Click *Endpoint* + - Select *HTTPS* + - Enter the the URL to the web service in the *Default Region* box. + - Select the SSL certificate type. This will depend on your setup, if you are using Let's Encrypt + choose *My development endpoints has a certificate from a trusted certificate authority* + - Click *Save Endpoints* + +#. Build the skill + + .. image:: resources/create_skill_7.png + :width: 800 + :align: center + :alt: Skill Creation Step 7 + + - Click *Invocations*, *Skill Invocation Name*. + - Click *Save Model*. + - Click *Build Model*, the process will take a few minutes. + +#. Add the skill to your Echo devices. + + The skill you just created should now be available as a development skill in your Alexa app, you can add the development skill to your + Echo devices. + + .. warning:: It is important that you **do not** publish the skill. If you do anyone that uses the skill will be able to stream your music + collection, it may also be possible for credentials to be retrieved. + + +Deploying the AskNavidrome Web Service +-------------------------------------- + +The AskNavidrome Web Service is written in Python and can be run directly on a PC with a Python installation, or as a Docker container (recommended). +Whichever method you use, the service and your Navidrome installation must be available via HTTPS with a well known certificate. One of the easiest +ways to implement this is with a reverse proxy. There are several +available for free: + +* `Caddy `_. +* `Apache `_. +* `Nginx `_. + + +Run on your PC +~~~~~~~~~~~~~~ + +Please remember that the web service needs to be publicly accessible, if you are running it directly on your PC this means your PC is publicly +accessible. + +#. Install Python 3 + * `python3.org `_ +#. Install git tools + * `git-scm.com `_ +#. Create a directory for the web service +#. Change to the directory and clone the repository from GitHub + + .. code-block:: bash + + cd directory + git clone https://github.com/rosskouk/asknavidrome.git + + +#. Change directory to the skill folder + + .. code-block:: bash + + cd asknavidrome/skill + +#. Start the skill by setting the required environment variables and executing the application + you can find details of what each option does in the *configuration* section. + + .. code-block:: bash + + NAVI_SKILL_ID= \ + NAVI_SONG_COUNT=50 \ + NAVI_URL=https://your-navidrome-server.test \ + NAVI_USER= \ + NAVI_PASS= \ + NAVI_PORT=443 \ + NAVI_API_PATH=/rest \ + NAVI_API_VER=1.16.1 \ + NAVI_DEBUG=0 \ + python3 app.py + + +Run inside a Docker container +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +A Dockerfile has been provided and a prebuilt container is hosted on github.com. You can configure the service by passing environment variables to +the *docker run* command. + +.. code-block:: bash + + docker run -p 5000:5000 \ + -e NAVI_SKILL_ID= \ + -e NAVI_SONG_COUNT=50 \ + -e NAVI_URL=https://your-navidrome-server.test \ + -e NAVI_USER= \ + -e NAVI_PASS= \ + -e NAVI_PORT=443 \ + -e NAVI_API_PATH=/rest \ + -e NAVI_API_VER=1.16.1 \ + -e NAVI_DEBUG=0 \ + ghcr.io/rosskouk/asknavidrome: + +If you intent to use the container to build a Kubernetes pod, I have created a side car container which can automatically configure and renew +TLS certificates with the Kubernetes Nginx Ingress. `More information `_. + + +Configuration +~~~~~~~~~~~~~ + +The AskNavidrome Web Service reads it's configuration from environment variables and needs the following configuration +information to run: + ++----------------------+----------------------------------------------------------------+------------------------------------------------------+ +| Environment Variable | Description | Example | ++======================+================================================================+======================================================+ +| NAVI_SKILL_ID | The ID of your Alexa skill, this prevents other skills from | amzn1.ask.skill.xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx | +| | connecting to the web service. | | ++----------------------+----------------------------------------------------------------+------------------------------------------------------+ +| NAVI_SONG_COUNT | The minimum number of songs to add to a playlist. If playing | 50 | +| | random music, music by genre or music by an artist the web | | +| | service will ensure the minimum number of tracks added to the | | +| | queue is at least this value | | ++----------------------+----------------------------------------------------------------+------------------------------------------------------+ +| NAVI_URL | The URL to the Subsonic API server | ``https://navidrome.example.test`` | ++----------------------+----------------------------------------------------------------+------------------------------------------------------+ +| NAVI_USER | The user name used to connect to the Subsonic API server | bob | ++----------------------+----------------------------------------------------------------+------------------------------------------------------+ +| NAVI_PASS | The password used to connect to the Subsonic API server | ``Sup3rStrongP@ssword`` | ++----------------------+----------------------------------------------------------------+------------------------------------------------------+ +| NAVI_PORT | The port the Subsonic API server is listening on | 443 | ++----------------------+----------------------------------------------------------------+------------------------------------------------------+ +| NAVI_API_PATH | The path to the Subsonic API, this should be /rest if you are | /rest | +| | using Navidrome and haven't changed anything | | ++----------------------+----------------------------------------------------------------+------------------------------------------------------+ +| NAVI_API_VER | The version of the Subsonic API in use | 1.16.1 | ++----------------------+----------------------------------------------------------------+------------------------------------------------------+ +| NAVI_DEBUG | Enable debugging, to disable to not set this variable | 1 | ++----------------------+----------------------------------------------------------------+------------------------------------------------------+ + + +Troubleshooting +*************** + +Troubleshooting and debugging Alexa skills can be a little frustrating, here are the best ways I have found to do it. + +#. Understand that the Alexa skill is effectively just a set of buttons. + All the skill does is call functions in the web service, it does nothing other than translate what you say to the function name that will perform the task. + Very little can go wrong with this, but here is a list of things to check: + + * Does the locale of the skill match the locale on your Echo device? If this is mismatched it looks like nothing happens when you try to invoke the skill. + * Is the endpoint set correctly? The endpoint is the URL to the web service, if the skill cannot communicate with the web service check this first. + you must ensure that the URL is https and the certificate is compatible with Amazon services. + * If an intent does not work, you might need to add an additional phrase to the intent in the developer console. The included phrases work for me, you might + want to make some changes though. + +#. Enable debugging and look at the logs generated by the web service. + +#. When debugging is enabled the following web pages are available from the web service + + * url-to-web-service/queue + + * Shows the tracks in the current queue + + * url-to-web-service/history + + * Shows the tracks that have already been played + + * url-to-web-service/buffer + + * Shows the tracks in the buffer. Note that the buffer and queue differ as Amazon will request the next track to be queued before the track playing is + finished. The buffer can be thought of as the list of tracks still to be sent to Amazon, where as the queue is the list of tracks still to be played. + +#. Use the test page in the developer console + The test page will show you the responses between Amazon and an simulated Echo device, this can help you uncover error messages that are normally hidden. + + .. image:: resources/debugging_1.png + :width: 800 + :align: center + :alt: debugging Step 1 + + * Click test and make sure you tick **Device Log** + * You can type instructions in the box or use the microphone on your device + + .. image:: resources/debugging_2.png + :width: 800 + :align: center + :alt: debugging Step 2 + + * After you have entered a command you will get the Alexa response back, scroll down to the **Device Log** section and click through the entries + the entries will contain any errors that were thrown. + + +Code Documentation +****************** + +.. toctree:: + :maxdepth: 2 + :caption: Contents: + +AskNavidrome main +----------------- +.. automodule:: app + :members: + :undoc-members: + +AskNavidrome controller +----------------------- +.. automodule:: asknavidrome.controller + :members: + :undoc-members: + +AskNavidrome media queue +------------------------ +.. autoclass:: asknavidrome.media_queue.MediaQueue + :members: + :undoc-members: + +AskNavidrome subsonic API +------------------------- +.. autoclass:: asknavidrome.subsonic_api.SubsonicConnection + :members: + :undoc-members: + +AskNavidrome track +------------------ +.. autoclass:: asknavidrome.track.Track + :members: + :undoc-members: diff --git a/sphinx/make.bat b/sphinx/make.bat new file mode 100644 index 0000000..32bb245 --- /dev/null +++ b/sphinx/make.bat @@ -0,0 +1,35 @@ +@ECHO OFF + +pushd %~dp0 + +REM Command file for Sphinx documentation + +if "%SPHINXBUILD%" == "" ( + set SPHINXBUILD=sphinx-build +) +set SOURCEDIR=. +set BUILDDIR=_build + +%SPHINXBUILD% >NUL 2>NUL +if errorlevel 9009 ( + echo. + echo.The 'sphinx-build' command was not found. Make sure you have Sphinx + echo.installed, then set the SPHINXBUILD environment variable to point + echo.to the full path of the 'sphinx-build' executable. Alternatively you + echo.may add the Sphinx directory to PATH. + echo. + echo.If you don't have Sphinx installed, grab it from + echo.https://www.sphinx-doc.org/ + exit /b 1 +) + +if "%1" == "" goto help + +%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% +goto end + +:help +%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% + +:end +popd diff --git a/sphinx/resources/AskNavidrome_Diagram.drawio b/sphinx/resources/AskNavidrome_Diagram.drawio new file mode 100644 index 0000000..6edd18d --- /dev/null +++ b/sphinx/resources/AskNavidrome_Diagram.drawio @@ -0,0 +1 @@ +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 \ No newline at end of file diff --git a/sphinx/resources/AskNavidrome_Diagram.png b/sphinx/resources/AskNavidrome_Diagram.png new file mode 100644 index 0000000..5e4685c Binary files /dev/null and b/sphinx/resources/AskNavidrome_Diagram.png differ diff --git a/sphinx/resources/create_skill_1.png b/sphinx/resources/create_skill_1.png new file mode 100644 index 0000000..3d3e244 Binary files /dev/null and b/sphinx/resources/create_skill_1.png differ diff --git a/sphinx/resources/create_skill_2.png b/sphinx/resources/create_skill_2.png new file mode 100644 index 0000000..cf26b42 Binary files /dev/null and b/sphinx/resources/create_skill_2.png differ diff --git a/sphinx/resources/create_skill_3.png b/sphinx/resources/create_skill_3.png new file mode 100644 index 0000000..e1b7dad Binary files /dev/null and b/sphinx/resources/create_skill_3.png differ diff --git a/sphinx/resources/create_skill_4.png b/sphinx/resources/create_skill_4.png new file mode 100644 index 0000000..6f3c2a0 Binary files /dev/null and b/sphinx/resources/create_skill_4.png differ diff --git a/sphinx/resources/create_skill_5.png b/sphinx/resources/create_skill_5.png new file mode 100644 index 0000000..f484fa9 Binary files /dev/null and b/sphinx/resources/create_skill_5.png differ diff --git a/sphinx/resources/create_skill_6.png b/sphinx/resources/create_skill_6.png new file mode 100644 index 0000000..0b482d7 Binary files /dev/null and b/sphinx/resources/create_skill_6.png differ diff --git a/sphinx/resources/create_skill_7.png b/sphinx/resources/create_skill_7.png new file mode 100644 index 0000000..1c34498 Binary files /dev/null and b/sphinx/resources/create_skill_7.png differ diff --git a/sphinx/resources/debugging_1.png b/sphinx/resources/debugging_1.png new file mode 100644 index 0000000..7937295 Binary files /dev/null and b/sphinx/resources/debugging_1.png differ diff --git a/sphinx/resources/debugging_2.png b/sphinx/resources/debugging_2.png new file mode 100644 index 0000000..d8fd8c3 Binary files /dev/null and b/sphinx/resources/debugging_2.png differ