Skip to content
Snippets Groups Projects
index.html 32.3 KiB
Newer Older

<!doctype html>
<html lang="en" class="no-js">
  <head>
    
      <meta charset="utf-8">
      <meta name="viewport" content="width=device-width,initial-scale=1">
      
        <meta name="description" content="ETSI SDG TFS Documentation page">
      
      
        <meta name="author" content="TeraflowSDN by ETSI">
      
      
        <link rel="canonical" href="https://tfs.etsi.org/develop/development_guide/configure_environment/python/">
        <link rel="prev" href="../configure_environment/">
        <link rel="next" href="../java_quarkus/">
      
      
      <link rel="icon" href="../../../images/favicon.png">
      <meta name="generator" content="mkdocs-1.6.1, mkdocs-material-9.5.34">
    
    
      
        <title>2.1.1. Python - ETSI SDG TFS Documentation</title>
      <link rel="stylesheet" href="../../../assets/stylesheets/main.35f28582.min.css">
        <link rel="stylesheet" href="../../../assets/stylesheets/palette.06af60db.min.css">
      
      


    
    
      
    
    
      
        
        
        <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
        <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,300i,400,400i,700,700i%7CRoboto+Mono:400,400i,700,700i&display=fallback">
        <style>:root{--md-text-font:"Roboto";--md-code-font:"Roboto Mono"}</style>
      
    
    
      <link rel="stylesheet" href="../../../stylesheets/extra.css">
    <script>__md_scope=new URL("../../..",location),__md_hash=e=>[...e].reduce(((e,_)=>(e<<5)-e+_.charCodeAt(0)),0),__md_get=(e,_=localStorage,t=__md_scope)=>JSON.parse(_.getItem(t.pathname+"."+e)),__md_set=(e,_,t=localStorage,a=__md_scope)=>{try{t.setItem(a.pathname+"."+e,JSON.stringify(_))}catch(e){}}</script>
    <body dir="ltr" data-md-color-scheme="default" data-md-color-primary="red" data-md-color-accent="light-red">
  
    
    <input class="md-toggle" data-md-toggle="drawer" type="checkbox" id="__drawer" autocomplete="off">
    <input class="md-toggle" data-md-toggle="search" type="checkbox" id="__search" autocomplete="off">
    <label class="md-overlay" for="__drawer"></label>
    <div data-md-component="skip">
      
        
        <a href="#upgrade-the-ubuntu-distribution" class="md-skip">
          Skip to content
        </a>
      
    </div>
    <div data-md-component="announce">
      
    </div>
    
      <div data-md-color-scheme="default" data-md-component="outdated" hidden>
        
      </div>
    
    
      

  

<header class="md-header md-header--shadow" data-md-component="header">
  <nav class="md-header__inner md-grid" aria-label="Header">
    <a href="../../.." title="ETSI SDG TFS Documentation" class="md-header__button md-logo" aria-label="ETSI SDG TFS Documentation" data-md-component="logo">
  <img src="../../../images/logos/TeraFlowSDN_tr.png" alt="logo">

    </a>
    <label class="md-header__button md-icon" for="__drawer">
      
      <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M3 6h18v2H3zm0 5h18v2H3zm0 5h18v2H3z"/></svg>
    </label>
    <div class="md-header__title" data-md-component="header-title">
      <div class="md-header__ellipsis">
        <div class="md-header__topic">
          <span class="md-ellipsis">
            ETSI SDG TFS Documentation
          </span>
        </div>
        <div class="md-header__topic" data-md-component="header-topic">
          <span class="md-ellipsis">
            
            
          </span>
        </div>
      </div>
    </div>
    
      
    
    
    
    
      <label class="md-header__button md-icon" for="__search">
        
        <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M9.5 3A6.5 6.5 0 0 1 16 9.5c0 1.61-.59 3.09-1.56 4.23l.27.27h.79l5 5-1.5 1.5-5-5v-.79l-.27-.27A6.52 6.52 0 0 1 9.5 16 6.5 6.5 0 0 1 3 9.5 6.5 6.5 0 0 1 9.5 3m0 2C7 5 5 7 5 9.5S7 14 9.5 14 14 12 14 9.5 12 5 9.5 5"/></svg>
      </label>
      <div class="md-search" data-md-component="search" role="dialog">
  <label class="md-search__overlay" for="__search"></label>
  <div class="md-search__inner" role="search">
    <form class="md-search__form" name="search">
      <input type="text" class="md-search__input" name="query" aria-label="Search" placeholder="Search" autocapitalize="off" autocorrect="off" autocomplete="off" spellcheck="false" data-md-component="search-query" required>
      <label class="md-search__icon md-icon" for="__search">
        
        <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M9.5 3A6.5 6.5 0 0 1 16 9.5c0 1.61-.59 3.09-1.56 4.23l.27.27h.79l5 5-1.5 1.5-5-5v-.79l-.27-.27A6.52 6.52 0 0 1 9.5 16 6.5 6.5 0 0 1 3 9.5 6.5 6.5 0 0 1 9.5 3m0 2C7 5 5 7 5 9.5S7 14 9.5 14 14 12 14 9.5 12 5 9.5 5"/></svg>
        
        <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M20 11v2H8l5.5 5.5-1.42 1.42L4.16 12l7.92-7.92L13.5 5.5 8 11z"/></svg>
      </label>
      <nav class="md-search__options" aria-label="Search">
        
        <button type="reset" class="md-search__icon md-icon" title="Clear" aria-label="Clear" tabindex="-1">
          
          <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M19 6.41 17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"/></svg>
        </button>
      </nav>
      
    </form>
    <div class="md-search__output">
      <div class="md-search__scrollwrap" tabindex="0" data-md-scrollfix>
        <div class="md-search-result" data-md-component="search-result">
          <div class="md-search-result__meta">
            Initializing search
          </div>
          <ol class="md-search-result__list" role="presentation"></ol>
        </div>
      </div>
    </div>
  </div>
</div>
    
    
      <div class="md-header__source">
        <a href="https://labs.etsi.org/rep/tfs" title="Go to repository" class="md-source" data-md-component="source">
  <div class="md-source__icon md-icon">
    
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--! Font Awesome Free 6.6.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2024 Fonticons, Inc.--><path d="m503.5 204.6-.7-1.8-69.7-181.78c-1.4-3.57-3.9-6.59-7.2-8.64-2.4-1.55-5.1-2.515-8-2.81s-5.7.083-8.4 1.11c-2.7 1.02-5.1 2.66-7.1 4.78-1.9 2.12-3.3 4.67-4.1 7.44l-47 144H160.8l-47.1-144c-.8-2.77-2.2-5.31-4.1-7.43-2-2.12-4.4-3.75-7.1-4.77a18.1 18.1 0 0 0-8.38-1.113 18.4 18.4 0 0 0-8.04 2.793 18.1 18.1 0 0 0-7.16 8.64L9.267 202.8l-.724 1.8a129.57 129.57 0 0 0-3.52 82c7.747 26.9 24.047 50.7 46.447 67.6l.27.2.59.4 105.97 79.5 52.6 39.7 32 24.2c3.7 1.9 8.3 4.3 13 4.3s9.3-2.4 13-4.3l32-24.2 52.6-39.7 106.7-79.9.3-.3c22.4-16.9 38.7-40.6 45.6-67.5 8.6-27 7.4-55.8-2.6-82"/></svg>
  </div>
  <div class="md-source__repository">
    TFS GitLab
  </div>
</a>
      </div>
    
  </nav>
  
</header>
    
    <div class="md-container" data-md-component="container">
      
      
        
          
        
      
      <main class="md-main" data-md-component="main">
        <div class="md-main__inner md-grid">
          
            
              
              <div class="md-sidebar md-sidebar--primary" data-md-component="sidebar" data-md-type="navigation" >
                <div class="md-sidebar__scrollwrap">
                  <div class="md-sidebar__inner">
                    



<nav class="md-nav md-nav--primary" aria-label="Navigation" data-md-level="0">
  <label class="md-nav__title" for="__drawer">
    <a href="../../.." title="ETSI SDG TFS Documentation" class="md-nav__button md-logo" aria-label="ETSI SDG TFS Documentation" data-md-component="logo">
  <img src="../../../images/logos/TeraFlowSDN_tr.png" alt="logo">

    </a>
    ETSI SDG TFS Documentation
  </label>
  
    <div class="md-nav__source">
      <a href="https://labs.etsi.org/rep/tfs" title="Go to repository" class="md-source" data-md-component="source">
  <div class="md-source__icon md-icon">
    
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--! Font Awesome Free 6.6.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2024 Fonticons, Inc.--><path d="m503.5 204.6-.7-1.8-69.7-181.78c-1.4-3.57-3.9-6.59-7.2-8.64-2.4-1.55-5.1-2.515-8-2.81s-5.7.083-8.4 1.11c-2.7 1.02-5.1 2.66-7.1 4.78-1.9 2.12-3.3 4.67-4.1 7.44l-47 144H160.8l-47.1-144c-.8-2.77-2.2-5.31-4.1-7.43-2-2.12-4.4-3.75-7.1-4.77a18.1 18.1 0 0 0-8.38-1.113 18.4 18.4 0 0 0-8.04 2.793 18.1 18.1 0 0 0-7.16 8.64L9.267 202.8l-.724 1.8a129.57 129.57 0 0 0-3.52 82c7.747 26.9 24.047 50.7 46.447 67.6l.27.2.59.4 105.97 79.5 52.6 39.7 32 24.2c3.7 1.9 8.3 4.3 13 4.3s9.3-2.4 13-4.3l32-24.2 52.6-39.7 106.7-79.9.3-.3c22.4-16.9 38.7-40.6 45.6-67.5 8.6-27 7.4-55.8-2.6-82"/></svg>
  </div>
  <div class="md-source__repository">
    TFS GitLab
  </div>
</a>
    </div>
  
  <ul class="md-nav__list" data-md-scrollfix>
    
      
      
  
  
  
  
    <li class="md-nav__item">
      <a href="../../../deployment_guide/deployment_guide/" class="md-nav__link">
        
  
  <span class="md-ellipsis">
    <li class="md-nav__item">
      <a href="../../../deployment_guide/configure_your_machine/configure_your_machine/" class="md-nav__link">
      <a href="../../../deployment_guide/configure_your_machine/physical_server/" class="md-nav__link">
      <a href="../../../deployment_guide/configure_your_machine/oracle_virtual_box/" class="md-nav__link">
      <a href="../../../deployment_guide/configure_your_machine/vm_ware_fusion/" class="md-nav__link">
      <a href="../../../deployment_guide/configure_your_machine/openstack/" class="md-nav__link">
      <a href="../../../deployment_guide/configure_your_machine/vagrant_box/" class="md-nav__link">
      <a href="../../../deployment_guide/install_micro_k8s/install_micro_k8s/" class="md-nav__link">
      <a href="../../../deployment_guide/deploy_TeraFlowSDN/deploy_TeraFlowSDN/" class="md-nav__link">
      <a href="../../../deployment_guide/webUI_and_grafana_dashboards/webUI_and_grafana_dashboards/" class="md-nav__link">
    1.4. WebUI and Grafana Dashboards
      <a href="../../../deployment_guide/show_deployment_and_logs/show_deployment_and_logs/" class="md-nav__link">
    <li class="md-nav__item">
      <a href="../../development_guide/" class="md-nav__link">
  
    <li class="md-nav__item">
      <a href="../configure_environment/" class="md-nav__link">
    <li class="md-nav__item md-nav__item--active">
      
      <input class="md-nav__toggle md-toggle" type="checkbox" id="__toc">
      
      
      
        <label class="md-nav__link md-nav__link--active" for="__toc">
          
  
  <span class="md-ellipsis">
  </span>
  

          <span class="md-nav__icon md-icon"></span>
        </label>
      
      <a href="./" class="md-nav__link md-nav__link--active">
        

<nav class="md-nav md-nav--secondary" aria-label="Table of contents">
  
  
  
  
    <label class="md-nav__title" for="__toc">
      <span class="md-nav__icon md-icon"></span>
      Table of contents
    </label>
    <ul class="md-nav__list" data-md-component="toc" data-md-scrollfix>
      
        <li class="md-nav__item">
  <a href="#upgrade-the-ubuntu-distribution" class="md-nav__link">
    <span class="md-ellipsis">
      Upgrade the Ubuntu distribution
    </span>
  </a>
  
</li>
      
        <li class="md-nav__item">
  <a href="#install-pyenv-dependencies" class="md-nav__link">
    <span class="md-ellipsis">
      Install PyEnv dependencies
    </span>
  </a>
  
</li>
      
        <li class="md-nav__item">
  <a href="#install-pyenv" class="md-nav__link">
    <span class="md-ellipsis">
      Install PyEnv
    </span>
  </a>
  
</li>
      
        <li class="md-nav__item">
  <a href="#restart-the-machine" class="md-nav__link">
    <span class="md-ellipsis">
      Restart the machine
    </span>
  </a>
  
</li>
      
        <li class="md-nav__item">
  <a href="#install-python-39-over-pyenv" class="md-nav__link">
    <span class="md-ellipsis">
      Install Python 3.9 over PyEnv
    </span>
  </a>
  
</li>
      
        <li class="md-nav__item">
  <a href="#create-the-virtual-environment-for-teraflowsdn" class="md-nav__link">
    <span class="md-ellipsis">
      Create the Virtual Environment for TeraFlowSDN
    </span>
  </a>
  
</li>
      
        <li class="md-nav__item">
  <a href="#install-the-basic-python-packages-within-the-virtual-environment" class="md-nav__link">
    <span class="md-ellipsis">
      Install the basic Python packages within the virtual environment
    </span>
  </a>
  
</li>
      
        <li class="md-nav__item">
  <a href="#generate-the-python-code-from-the-grpc-proto-messages-and-services" class="md-nav__link">
    <span class="md-ellipsis">
      Generate the Python code from the gRPC Proto messages and services
    </span>
  </a>
  
</li>
      
    </ul>
  
</nav>
      
      <a href="../java_quarkus/" class="md-nav__link">
        <input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_16" >
          <label class="md-nav__link" for="__nav_16" id="__nav_16_label" tabindex="0">
            
  
  <span class="md-ellipsis">
    Testing
  </span>
  

            <span class="md-nav__icon md-icon"></span>
          </label>
        
        <nav class="md-nav" data-md-level="1" aria-labelledby="__nav_16_label" aria-expanded="false">
          <label class="md-nav__title" for="__nav_16">
            <span class="md-nav__icon md-icon"></span>
            Testing
          </label>
          <ul class="md-nav__list" data-md-scrollfix>
            
              
                
  
  
  
  
    <li class="md-nav__item">
      <a href="../../../testing/testplan/" class="md-nav__link">
      <a href="../../../testing/robotframework/" class="md-nav__link">
      <a href="../../../testing/postman/" class="md-nav__link">
      <a href="../../../FAQ/" class="md-nav__link">
        
  
  <span class="md-ellipsis">
    FAQ
  </span>
  

      </a>
    </li>
  

    
  </ul>
</nav>
                  </div>
                </div>
              </div>
            
            
              
              <div class="md-sidebar md-sidebar--secondary" data-md-component="sidebar" data-md-type="toc" >
                <div class="md-sidebar__scrollwrap">
                  <div class="md-sidebar__inner">
                    

<nav class="md-nav md-nav--secondary" aria-label="Table of contents">
  
  
  
  
    <label class="md-nav__title" for="__toc">
      <span class="md-nav__icon md-icon"></span>
      Table of contents
    </label>
    <ul class="md-nav__list" data-md-component="toc" data-md-scrollfix>
      
        <li class="md-nav__item">
  <a href="#upgrade-the-ubuntu-distribution" class="md-nav__link">
    <span class="md-ellipsis">
      Upgrade the Ubuntu distribution
    </span>
  </a>
  
</li>
      
        <li class="md-nav__item">
  <a href="#install-pyenv-dependencies" class="md-nav__link">
    <span class="md-ellipsis">
      Install PyEnv dependencies
    </span>
  </a>
  
</li>
      
        <li class="md-nav__item">
  <a href="#install-pyenv" class="md-nav__link">
    <span class="md-ellipsis">
      Install PyEnv
    </span>
  </a>
  
</li>
      
        <li class="md-nav__item">
  <a href="#restart-the-machine" class="md-nav__link">
    <span class="md-ellipsis">
      Restart the machine
    </span>
  </a>
  
</li>
      
        <li class="md-nav__item">
  <a href="#install-python-39-over-pyenv" class="md-nav__link">
    <span class="md-ellipsis">
      Install Python 3.9 over PyEnv
    </span>
  </a>
  
</li>
      
        <li class="md-nav__item">
  <a href="#create-the-virtual-environment-for-teraflowsdn" class="md-nav__link">
    <span class="md-ellipsis">
      Create the Virtual Environment for TeraFlowSDN
    </span>
  </a>
  
</li>
      
        <li class="md-nav__item">
  <a href="#install-the-basic-python-packages-within-the-virtual-environment" class="md-nav__link">
    <span class="md-ellipsis">
      Install the basic Python packages within the virtual environment
    </span>
  </a>
  
</li>
      
        <li class="md-nav__item">
  <a href="#generate-the-python-code-from-the-grpc-proto-messages-and-services" class="md-nav__link">
    <span class="md-ellipsis">
      Generate the Python code from the gRPC Proto messages and services
    </span>
  </a>
  
</li>
      
    </ul>
  
</nav>
                  </div>
                </div>
              </div>
            
          
          
            <div class="md-content" data-md-component="content">
              <article class="md-content__inner md-typeset">
                
                  


<p>This section describes how to configure the Python environment to run experiments and 
develop code for the ETSI TeraFlowSDN controller.
In particular, we use <a href="https://github.com/pyenv/pyenv">PyEnv</a> to install the appropriate 
version of Python and manage the virtual environments.</p>
<h2 id="upgrade-the-ubuntu-distribution">Upgrade the Ubuntu distribution</h2>
<p>Skip this step if you already did it during the installation of your machine.</p>
<pre><code class="language-bash">sudo apt-get update -y
sudo apt-get dist-upgrade -y
</code></pre>
<h2 id="install-pyenv-dependencies">Install PyEnv dependencies</h2>
<pre><code class="language-bash">sudo apt-get install -y make build-essential libssl-dev zlib1g-dev libbz2-dev libreadline-dev libsqlite3-dev wget \
    curl llvm git libncursesw5-dev xz-utils tk-dev libxml2-dev libxmlsec1-dev libffi-dev liblzma-dev
</code></pre>
<h2 id="install-pyenv">Install PyEnv</h2>
<p>We recommend installing PyEnv through<br />
<a href="https://github.com/pyenv/pyenv-installer">PyEnv Installer</a>.
Below you can find the instructions, but we refer you to the link for updated 
instructions.</p>
<pre><code class="language-bash">curl https://pyenv.run | bash
# When finished, edit ~/.bash_profile // ~/.profile // ~/.bashrc as the installer proposes.
# In general, it means to append the following lines to ~/.bashrc:
export PYENV_ROOT=&quot;$HOME/.pyenv&quot;
command -v pyenv &gt;/dev/null || export PATH=&quot;$PYENV_ROOT/bin:$PATH&quot;
eval &quot;$(pyenv init -)&quot;
eval &quot;$(pyenv virtualenv-init -)&quot;
</code></pre>
<p>In case .bashrc is not linked properly to your profile, you may need to append the 
following line into your local .profile file:</p>
<pre><code class="language-bash"># Open ~/.profile and append this line:
+source &quot;$HOME&quot;/.bashrc
</code></pre>
<h2 id="restart-the-machine">Restart the machine</h2>
<p>Restart the machine for all the changes to take effect.</p>
<pre><code class="language-bash">sudo reboot
</code></pre>
<h2 id="install-python-39-over-pyenv">Install Python 3.9 over PyEnv</h2>
<p>ETSI TeraFlowSDN uses Python 3.9 by default.
You should install the latest stable update of Python 3.9, i.e., avoid "-dev" versions.
To find the latest version available in PyEnv, you can run the following command:</p>
<pre><code class="language-bash">pyenv install --list | grep &quot; 3.9&quot;
</code></pre>
<p>At the time of writing, this command will output the following list:</p>
<pre><code>  3.9.0
  3.9-dev
  3.9.1
  3.9.2
  3.9.4
  3.9.5
  3.9.6
  3.9.7
  3.9.8
  3.9.9
  3.9.10
  3.9.11
  3.9.12
  3.9.13
  3.9.14 
  3.9.15
  3.9.16 ** always select the latest version **
</code></pre>
<p>Therefore, the latest stable version is Python 3.9.16.
To install this version, you should run:</p>
<pre><code class="language-bash">pyenv install 3.9.16
    # This command might take some minutes depending on your Internet connection speed 
    # and the performance of your machine.
</code></pre>
<h2 id="create-the-virtual-environment-for-teraflowsdn">Create the Virtual Environment for TeraFlowSDN</h2>
<p>The following commands create a virtual environment named as <code>tfs</code> using Python 3.9 and 
associate that environment with the current folder, i.e., <code>~/tfs-ctrl</code>.
That way, when you are in that folder, the associated virtual environment will be used, 
thus inheriting the Python interpreter, i.e., Python 3.9, and the Python packages 
installed on it.</p>
<pre><code class="language-bash">cd ~/tfs-ctrl
pyenv virtualenv 3.9.16 tfs
pyenv local 3.9.16/envs/tfs
</code></pre>
<p>After completing these commands, you should see in your prompt that now you're within 
the virtual environment <code>3.9.16/envs/tfs</code> on folder <code>~/tfs-ctrl</code>:</p>
<pre><code>(3.9.16/envs/tfs) tfs@tfs-vm:~/tfs-ctrl$
</code></pre>
<p>In case that the correct pyenv does not get automatically activated when you change to 
the tfs-ctrl/ folder, then execute the following command:</p>
<pre><code class="language-bash">cd ~/tfs-ctrl
pyenv activate 3.9.16/envs/tfs
</code></pre>
<h2 id="install-the-basic-python-packages-within-the-virtual-environment">Install the basic Python packages within the virtual environment</h2>
<p>From within the <code>3.9.16/envs/tfs</code> environment on folder <code>~/tfs-ctrl</code>, run the following 
commands to install the basic Python packages required to work with TeraFlowSDN.</p>
<pre><code class="language-bash">cd ~/tfs-ctrl
./install_requirements.sh
</code></pre>
<p>Some dependencies require to re-load the session, so log-out and log-in again.</p>
<h2 id="generate-the-python-code-from-the-grpc-proto-messages-and-services">Generate the Python code from the gRPC Proto messages and services</h2>
<p>The components, e.g., microservices, of the TeraFlowSDN controller, in general, use a gRPC-based open API to interoperate.
All the protocol definitions can be found in sub-folder <code>proto</code> within the root project folder.
For additional details on gRPC, visit the official web-page <a href="https://grpc.io/">gRPC</a>.</p>
<p>In order to interact with the components, (re-)generate the Python code from gRPC definitions running the following command:</p>
<pre><code class="language-bash">cd ~/tfs-ctrl
proto/generate_code_python.sh
</code></pre>












                
              </article>
            </div>
          
          
<script>var target=document.getElementById(location.hash.slice(1));target&&target.name&&(target.checked=target.name.startsWith("__tabbed_"))</script>
        </div>
        
          <button type="button" class="md-top md-icon" data-md-component="top" hidden>
  
  <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M13 20h-2V8l-5.5 5.5-1.42-1.42L12 4.16l7.92 7.92-1.42 1.42L13 8z"/></svg>
  Back to top
</button>