[pre-commit.ci lite] apply automatic fixes
This commit is contained in:
parent
b3ae3117f9
commit
3d83d8138c
102 changed files with 26790 additions and 26749 deletions
|
|
@ -5,7 +5,7 @@
|
|||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>Subclassing Flask — Flask Documentation (3.2.x)</title>
|
||||
<title>View Decorators — Flask Documentation (3.2.x)</title>
|
||||
<link rel="stylesheet" type="text/css" href="../_static/pygments.css?v=6625fa76" />
|
||||
<link rel="stylesheet" type="text/css" href="../_static/flask.css?v=b87c8d14" />
|
||||
<script src="../_static/documentation_options.js?v=56528222"></script>
|
||||
|
|
@ -15,8 +15,8 @@
|
|||
<link rel="icon" href="../_static/shortcut-icon.png"/>
|
||||
<link rel="index" title="Index" href="../genindex.html" />
|
||||
<link rel="search" title="Search" href="../search.html" />
|
||||
<link rel="next" title="Single-Page Applications" href="singlepageapplications.html" />
|
||||
<link rel="prev" title="Background Tasks with Celery" href="celery.html" />
|
||||
<link rel="next" title="Form Validation with WTForms" href="wtforms.html" />
|
||||
<link rel="prev" title="Caching" href="caching.html" />
|
||||
</head><body>
|
||||
<div class="related" role="navigation" aria-label="Related">
|
||||
<h3>Navigation</h3>
|
||||
|
|
@ -28,37 +28,186 @@
|
|||
<a href="../py-modindex.html" title="Python Module Index"
|
||||
>modules</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="singlepageapplications.html" title="Single-Page Applications"
|
||||
<a href="wtforms.html" title="Form Validation with WTForms"
|
||||
accesskey="N">next</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="celery.html" title="Background Tasks with Celery"
|
||||
<a href="caching.html" title="Caching"
|
||||
accesskey="P">previous</a> |</li>
|
||||
<li class="nav-item nav-item-0"><a href="../index.html">Flask Documentation (3.2.x)</a> »</li>
|
||||
<li class="nav-item nav-item-1"><a href="index.html" accesskey="U">Patterns for Flask</a> »</li>
|
||||
<li class="nav-item nav-item-this"><a href="">Subclassing Flask</a></li>
|
||||
<li class="nav-item nav-item-this"><a href="">View Decorators</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="document">
|
||||
<div class="documentwrapper">
|
||||
<div class="bodywrapper">
|
||||
<div class="body" role="main">
|
||||
|
||||
<section id="subclassing-flask">
|
||||
<h1>Subclassing Flask<a class="headerlink" href="#subclassing-flask" title="Link to this heading">¶</a></h1>
|
||||
<p>The <a class="reference internal" href="../api.html#flask.Flask" title="flask.Flask"><code class="xref py py-class docutils literal notranslate"><span class="pre">Flask</span></code></a> class is designed for subclassing.</p>
|
||||
<p>For example, you may want to override how request parameters are handled to preserve their order:</p>
|
||||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span><span class="w"> </span><span class="nn">flask</span><span class="w"> </span><span class="kn">import</span> <span class="n">Flask</span><span class="p">,</span> <span class="n">Request</span>
|
||||
<span class="kn">from</span><span class="w"> </span><span class="nn">werkzeug.datastructures</span><span class="w"> </span><span class="kn">import</span> <span class="n">ImmutableOrderedMultiDict</span>
|
||||
<span class="k">class</span><span class="w"> </span><span class="nc">MyRequest</span><span class="p">(</span><span class="n">Request</span><span class="p">):</span>
|
||||
<span class="w"> </span><span class="sd">"""Request subclass to override request parameter storage"""</span>
|
||||
<span class="n">parameter_storage_class</span> <span class="o">=</span> <span class="n">ImmutableOrderedMultiDict</span>
|
||||
<span class="k">class</span><span class="w"> </span><span class="nc">MyFlask</span><span class="p">(</span><span class="n">Flask</span><span class="p">):</span>
|
||||
<span class="w"> </span><span class="sd">"""Flask subclass using the custom request class"""</span>
|
||||
<span class="n">request_class</span> <span class="o">=</span> <span class="n">MyRequest</span>
|
||||
|
||||
<section id="view-decorators">
|
||||
<h1>View Decorators<a class="headerlink" href="#view-decorators" title="Link to this heading">¶</a></h1>
|
||||
<p>Python has a really interesting feature called function decorators. This
|
||||
allows some really neat things for web applications. Because each view in
|
||||
Flask is a function, decorators can be used to inject additional
|
||||
functionality to one or more functions. The <a class="reference internal" href="../api.html#flask.Flask.route" title="flask.Flask.route"><code class="xref py py-meth docutils literal notranslate"><span class="pre">route()</span></code></a>
|
||||
decorator is the one you probably used already. But there are use cases
|
||||
for implementing your own decorator. For instance, imagine you have a
|
||||
view that should only be used by people that are logged in. If a user
|
||||
goes to the site and is not logged in, they should be redirected to the
|
||||
login page. This is a good example of a use case where a decorator is an
|
||||
excellent solution.</p>
|
||||
<section id="login-required-decorator">
|
||||
<h2>Login Required Decorator<a class="headerlink" href="#login-required-decorator" title="Link to this heading">¶</a></h2>
|
||||
<p>So let’s implement such a decorator. A decorator is a function that
|
||||
wraps and replaces another function. Since the original function is
|
||||
replaced, you need to remember to copy the original function’s information
|
||||
to the new function. Use <a class="reference external" href="https://docs.python.org/3/library/functools.html#functools.wraps" title="(in Python v3.13)"><code class="xref py py-func docutils literal notranslate"><span class="pre">functools.wraps()</span></code></a> to handle this for you.</p>
|
||||
<p>This example assumes that the login page is called <code class="docutils literal notranslate"><span class="pre">'login'</span></code> and that
|
||||
the current user is stored in <code class="docutils literal notranslate"><span class="pre">g.user</span></code> and is <code class="docutils literal notranslate"><span class="pre">None</span></code> if there is no-one
|
||||
logged in.</p>
|
||||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span><span class="w"> </span><span class="nn">functools</span><span class="w"> </span><span class="kn">import</span> <span class="n">wraps</span>
|
||||
<span class="kn">from</span><span class="w"> </span><span class="nn">flask</span><span class="w"> </span><span class="kn">import</span> <span class="n">g</span><span class="p">,</span> <span class="n">request</span><span class="p">,</span> <span class="n">redirect</span><span class="p">,</span> <span class="n">url_for</span>
|
||||
|
||||
<span class="k">def</span><span class="w"> </span><span class="nf">login_required</span><span class="p">(</span><span class="n">f</span><span class="p">):</span>
|
||||
<span class="nd">@wraps</span><span class="p">(</span><span class="n">f</span><span class="p">)</span>
|
||||
<span class="k">def</span><span class="w"> </span><span class="nf">decorated_function</span><span class="p">(</span><span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
|
||||
<span class="k">if</span> <span class="n">g</span><span class="o">.</span><span class="n">user</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
|
||||
<span class="k">return</span> <span class="n">redirect</span><span class="p">(</span><span class="n">url_for</span><span class="p">(</span><span class="s1">'login'</span><span class="p">,</span> <span class="nb">next</span><span class="o">=</span><span class="n">request</span><span class="o">.</span><span class="n">url</span><span class="p">))</span>
|
||||
<span class="k">return</span> <span class="n">f</span><span class="p">(</span><span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span>
|
||||
<span class="k">return</span> <span class="n">decorated_function</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>This is the recommended approach for overriding or augmenting Flask’s internal functionality.</p>
|
||||
<p>To use the decorator, apply it as innermost decorator to a view function.
|
||||
When applying further decorators, always remember
|
||||
that the <a class="reference internal" href="../api.html#flask.Flask.route" title="flask.Flask.route"><code class="xref py py-meth docutils literal notranslate"><span class="pre">route()</span></code></a> decorator is the outermost.</p>
|
||||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="nd">@app</span><span class="o">.</span><span class="n">route</span><span class="p">(</span><span class="s1">'/secret_page'</span><span class="p">)</span>
|
||||
<span class="nd">@login_required</span>
|
||||
<span class="k">def</span><span class="w"> </span><span class="nf">secret_page</span><span class="p">():</span>
|
||||
<span class="k">pass</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<div class="admonition note">
|
||||
<p class="admonition-title">Note</p>
|
||||
<p>The <code class="docutils literal notranslate"><span class="pre">next</span></code> value will exist in <code class="docutils literal notranslate"><span class="pre">request.args</span></code> after a <code class="docutils literal notranslate"><span class="pre">GET</span></code> request for
|
||||
the login page. You’ll have to pass it along when sending the <code class="docutils literal notranslate"><span class="pre">POST</span></code> request
|
||||
from the login form. You can do this with a hidden input tag, then retrieve it
|
||||
from <code class="docutils literal notranslate"><span class="pre">request.form</span></code> when logging the user in.</p>
|
||||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="o"><</span><span class="nb">input</span> <span class="nb">type</span><span class="o">=</span><span class="s2">"hidden"</span> <span class="n">value</span><span class="o">=</span><span class="s2">"{{ request.args.get('next', '') }}"</span><span class="o">/></span>
|
||||
</pre></div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<section id="caching-decorator">
|
||||
<h2>Caching Decorator<a class="headerlink" href="#caching-decorator" title="Link to this heading">¶</a></h2>
|
||||
<p>Imagine you have a view function that does an expensive calculation and
|
||||
because of that you would like to cache the generated results for a
|
||||
certain amount of time. A decorator would be nice for that. We’re
|
||||
assuming you have set up a cache like mentioned in <a class="reference internal" href="caching.html"><span class="doc">Caching</span></a>.</p>
|
||||
<p>Here is an example cache function. It generates the cache key from a
|
||||
specific prefix (actually a format string) and the current path of the
|
||||
request. Notice that we are using a function that first creates the
|
||||
decorator that then decorates the function. Sounds awful? Unfortunately
|
||||
it is a little bit more complex, but the code should still be
|
||||
straightforward to read.</p>
|
||||
<p>The decorated function will then work as follows</p>
|
||||
<ol class="arabic simple">
|
||||
<li><p>get the unique cache key for the current request based on the current
|
||||
path.</p></li>
|
||||
<li><p>get the value for that key from the cache. If the cache returned
|
||||
something we will return that value.</p></li>
|
||||
<li><p>otherwise the original function is called and the return value is
|
||||
stored in the cache for the timeout provided (by default 5 minutes).</p></li>
|
||||
</ol>
|
||||
<p>Here the code:</p>
|
||||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span><span class="w"> </span><span class="nn">functools</span><span class="w"> </span><span class="kn">import</span> <span class="n">wraps</span>
|
||||
<span class="kn">from</span><span class="w"> </span><span class="nn">flask</span><span class="w"> </span><span class="kn">import</span> <span class="n">request</span>
|
||||
|
||||
<span class="k">def</span><span class="w"> </span><span class="nf">cached</span><span class="p">(</span><span class="n">timeout</span><span class="o">=</span><span class="mi">5</span> <span class="o">*</span> <span class="mi">60</span><span class="p">,</span> <span class="n">key</span><span class="o">=</span><span class="s1">'view/</span><span class="si">{}</span><span class="s1">'</span><span class="p">):</span>
|
||||
<span class="k">def</span><span class="w"> </span><span class="nf">decorator</span><span class="p">(</span><span class="n">f</span><span class="p">):</span>
|
||||
<span class="nd">@wraps</span><span class="p">(</span><span class="n">f</span><span class="p">)</span>
|
||||
<span class="k">def</span><span class="w"> </span><span class="nf">decorated_function</span><span class="p">(</span><span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
|
||||
<span class="n">cache_key</span> <span class="o">=</span> <span class="n">key</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">request</span><span class="o">.</span><span class="n">path</span><span class="p">)</span>
|
||||
<span class="n">rv</span> <span class="o">=</span> <span class="n">cache</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">cache_key</span><span class="p">)</span>
|
||||
<span class="k">if</span> <span class="n">rv</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span>
|
||||
<span class="k">return</span> <span class="n">rv</span>
|
||||
<span class="n">rv</span> <span class="o">=</span> <span class="n">f</span><span class="p">(</span><span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span>
|
||||
<span class="n">cache</span><span class="o">.</span><span class="n">set</span><span class="p">(</span><span class="n">cache_key</span><span class="p">,</span> <span class="n">rv</span><span class="p">,</span> <span class="n">timeout</span><span class="o">=</span><span class="n">timeout</span><span class="p">)</span>
|
||||
<span class="k">return</span> <span class="n">rv</span>
|
||||
<span class="k">return</span> <span class="n">decorated_function</span>
|
||||
<span class="k">return</span> <span class="n">decorator</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>Notice that this assumes an instantiated <code class="docutils literal notranslate"><span class="pre">cache</span></code> object is available, see
|
||||
<a class="reference internal" href="caching.html"><span class="doc">Caching</span></a>.</p>
|
||||
</section>
|
||||
<section id="templating-decorator">
|
||||
<h2>Templating Decorator<a class="headerlink" href="#templating-decorator" title="Link to this heading">¶</a></h2>
|
||||
<p>A common pattern invented by the TurboGears guys a while back is a
|
||||
templating decorator. The idea of that decorator is that you return a
|
||||
dictionary with the values passed to the template from the view function
|
||||
and the template is automatically rendered. With that, the following
|
||||
three examples do exactly the same:</p>
|
||||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="nd">@app</span><span class="o">.</span><span class="n">route</span><span class="p">(</span><span class="s1">'/'</span><span class="p">)</span>
|
||||
<span class="k">def</span><span class="w"> </span><span class="nf">index</span><span class="p">():</span>
|
||||
<span class="k">return</span> <span class="n">render_template</span><span class="p">(</span><span class="s1">'index.html'</span><span class="p">,</span> <span class="n">value</span><span class="o">=</span><span class="mi">42</span><span class="p">)</span>
|
||||
|
||||
<span class="nd">@app</span><span class="o">.</span><span class="n">route</span><span class="p">(</span><span class="s1">'/'</span><span class="p">)</span>
|
||||
<span class="nd">@templated</span><span class="p">(</span><span class="s1">'index.html'</span><span class="p">)</span>
|
||||
<span class="k">def</span><span class="w"> </span><span class="nf">index</span><span class="p">():</span>
|
||||
<span class="k">return</span> <span class="nb">dict</span><span class="p">(</span><span class="n">value</span><span class="o">=</span><span class="mi">42</span><span class="p">)</span>
|
||||
|
||||
<span class="nd">@app</span><span class="o">.</span><span class="n">route</span><span class="p">(</span><span class="s1">'/'</span><span class="p">)</span>
|
||||
<span class="nd">@templated</span><span class="p">()</span>
|
||||
<span class="k">def</span><span class="w"> </span><span class="nf">index</span><span class="p">():</span>
|
||||
<span class="k">return</span> <span class="nb">dict</span><span class="p">(</span><span class="n">value</span><span class="o">=</span><span class="mi">42</span><span class="p">)</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>As you can see, if no template name is provided it will use the endpoint
|
||||
of the URL map with dots converted to slashes + <code class="docutils literal notranslate"><span class="pre">'.html'</span></code>. Otherwise
|
||||
the provided template name is used. When the decorated function returns,
|
||||
the dictionary returned is passed to the template rendering function. If
|
||||
<code class="docutils literal notranslate"><span class="pre">None</span></code> is returned, an empty dictionary is assumed, if something else than
|
||||
a dictionary is returned we return it from the function unchanged. That
|
||||
way you can still use the redirect function or return simple strings.</p>
|
||||
<p>Here is the code for that decorator:</p>
|
||||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span><span class="w"> </span><span class="nn">functools</span><span class="w"> </span><span class="kn">import</span> <span class="n">wraps</span>
|
||||
<span class="kn">from</span><span class="w"> </span><span class="nn">flask</span><span class="w"> </span><span class="kn">import</span> <span class="n">request</span><span class="p">,</span> <span class="n">render_template</span>
|
||||
|
||||
<span class="k">def</span><span class="w"> </span><span class="nf">templated</span><span class="p">(</span><span class="n">template</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span>
|
||||
<span class="k">def</span><span class="w"> </span><span class="nf">decorator</span><span class="p">(</span><span class="n">f</span><span class="p">):</span>
|
||||
<span class="nd">@wraps</span><span class="p">(</span><span class="n">f</span><span class="p">)</span>
|
||||
<span class="k">def</span><span class="w"> </span><span class="nf">decorated_function</span><span class="p">(</span><span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
|
||||
<span class="n">template_name</span> <span class="o">=</span> <span class="n">template</span>
|
||||
<span class="k">if</span> <span class="n">template_name</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
|
||||
<span class="n">template_name</span> <span class="o">=</span> <span class="sa">f</span><span class="s2">"</span><span class="si">{</span><span class="n">request</span><span class="o">.</span><span class="n">endpoint</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="s1">'.'</span><span class="p">,</span><span class="w"> </span><span class="s1">'/'</span><span class="p">)</span><span class="si">}</span><span class="s2">.html"</span>
|
||||
<span class="n">ctx</span> <span class="o">=</span> <span class="n">f</span><span class="p">(</span><span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span>
|
||||
<span class="k">if</span> <span class="n">ctx</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
|
||||
<span class="n">ctx</span> <span class="o">=</span> <span class="p">{}</span>
|
||||
<span class="k">elif</span> <span class="ow">not</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">ctx</span><span class="p">,</span> <span class="nb">dict</span><span class="p">):</span>
|
||||
<span class="k">return</span> <span class="n">ctx</span>
|
||||
<span class="k">return</span> <span class="n">render_template</span><span class="p">(</span><span class="n">template_name</span><span class="p">,</span> <span class="o">**</span><span class="n">ctx</span><span class="p">)</span>
|
||||
<span class="k">return</span> <span class="n">decorated_function</span>
|
||||
<span class="k">return</span> <span class="n">decorator</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
</section>
|
||||
<section id="endpoint-decorator">
|
||||
<h2>Endpoint Decorator<a class="headerlink" href="#endpoint-decorator" title="Link to this heading">¶</a></h2>
|
||||
<p>When you want to use the werkzeug routing system for more flexibility you
|
||||
need to map the endpoint as defined in the <a class="reference external" href="https://werkzeug.palletsprojects.com/en/stable/routing/#werkzeug.routing.Rule" title="(in Werkzeug v3.1.x)"><code class="xref py py-class docutils literal notranslate"><span class="pre">Rule</span></code></a>
|
||||
to a view function. This is possible with this decorator. For example:</p>
|
||||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span><span class="w"> </span><span class="nn">flask</span><span class="w"> </span><span class="kn">import</span> <span class="n">Flask</span>
|
||||
<span class="kn">from</span><span class="w"> </span><span class="nn">werkzeug.routing</span><span class="w"> </span><span class="kn">import</span> <span class="n">Rule</span>
|
||||
|
||||
<span class="n">app</span> <span class="o">=</span> <span class="n">Flask</span><span class="p">(</span><span class="vm">__name__</span><span class="p">)</span>
|
||||
<span class="n">app</span><span class="o">.</span><span class="n">url_map</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">Rule</span><span class="p">(</span><span class="s1">'/'</span><span class="p">,</span> <span class="n">endpoint</span><span class="o">=</span><span class="s1">'index'</span><span class="p">))</span>
|
||||
|
||||
<span class="nd">@app</span><span class="o">.</span><span class="n">endpoint</span><span class="p">(</span><span class="s1">'index'</span><span class="p">)</span>
|
||||
<span class="k">def</span><span class="w"> </span><span class="nf">my_index</span><span class="p">():</span>
|
||||
<span class="k">return</span> <span class="s2">"Hello world"</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
|
||||
|
|
@ -69,20 +218,31 @@
|
|||
<span id="sidebar-top"></span>
|
||||
<div class="sphinxsidebar" role="navigation" aria-label="Main">
|
||||
<div class="sphinxsidebarwrapper">
|
||||
|
||||
|
||||
|
||||
|
||||
<p class="logo"><a href="../index.html">
|
||||
<img class="logo" src="../_static/flask-vertical.png" alt="Logo of Flask"/>
|
||||
</a></p>
|
||||
|
||||
|
||||
|
||||
<h3>Contents</h3>
|
||||
<ul>
|
||||
<li><a class="reference internal" href="#">View Decorators</a><ul>
|
||||
<li><a class="reference internal" href="#login-required-decorator">Login Required Decorator</a></li>
|
||||
<li><a class="reference internal" href="#caching-decorator">Caching Decorator</a></li>
|
||||
<li><a class="reference internal" href="#templating-decorator">Templating Decorator</a></li>
|
||||
<li><a class="reference internal" href="#endpoint-decorator">Endpoint Decorator</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
<h3>Navigation</h3>
|
||||
<ul>
|
||||
<li><a href="../index.html">Overview</a>
|
||||
<ul>
|
||||
<li><a href="index.html">Patterns for Flask</a>
|
||||
<ul>
|
||||
<li>Previous: <a href="celery.html" title="previous chapter">Background Tasks with Celery</a>
|
||||
<li>Next: <a href="singlepageapplications.html" title="next chapter">Single-Page Applications</a></ul>
|
||||
<li>Previous: <a href="caching.html" title="previous chapter">Caching</a>
|
||||
<li>Next: <a href="wtforms.html" title="next chapter">Form Validation with WTForms</a></ul>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
|
|
@ -106,4 +266,4 @@
|
|||
Created using <a href="https://www.sphinx-doc.org/">Sphinx</a> 8.1.3.
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue