mirror of
https://github.com/boostorg/python.git
synced 2026-01-21 05:02:17 +00:00
259 lines
25 KiB
HTML
259 lines
25 KiB
HTML
<html>
|
||
<head>
|
||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
||
<title> Object Interface</title>
|
||
<link rel="stylesheet" href="../boostbook.css" type="text/css">
|
||
<meta name="generator" content="DocBook XSL Stylesheets V1.66.1">
|
||
<link rel="start" href="../index.html" title="Chapter 1. python 1.0">
|
||
<link rel="up" href="../index.html" title="Chapter 1. python 1.0">
|
||
<link rel="prev" href="functions.html" title="Functions">
|
||
<link rel="next" href="embedding.html" title="Embedding">
|
||
</head>
|
||
<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF">
|
||
<table cellpadding="2" width="100%">
|
||
<td valign="top"><img alt="boost.png (6897 bytes)" width="277" height="86" src="../../../../../../../boost.png"></td>
|
||
<td align="center"><a href="../../../../../../../index.htm">Home</a></td>
|
||
<td align="center"><a href="../../../../../../libraries.htm">Libraries</a></td>
|
||
<td align="center"><a href="../../../../../../../people/people.htm">People</a></td>
|
||
<td align="center"><a href="../../../../../../../more/faq.htm">FAQ</a></td>
|
||
<td align="center"><a href="../../../../../../../more/index.htm">More</a></td>
|
||
</table>
|
||
<hr>
|
||
<div class="spirit-nav">
|
||
<a accesskey="p" href="functions.html"><img src="../images/prev.png" alt="Prev"></a><a accesskey="u" href="../index.html"><img src="../images/up.png" alt="Up"></a><a accesskey="h" href="../index.html"><img src="../images/home.png" alt="Home"></a><a accesskey="n" href="embedding.html"><img src="../images/next.png" alt="Next"></a>
|
||
</div>
|
||
<div class="section" lang="en">
|
||
<div class="titlepage"><div><div><h2 class="title" style="clear: both">
|
||
<a name="python.object"></a> Object Interface</h2></div></div></div>
|
||
<div class="toc"><dl>
|
||
<dt><span class="section"><a href="object.html#python.basic_interface">Basic Interface</a></span></dt>
|
||
<dt><span class="section"><a href="object.html#python.derived_object_types">Derived Object types</a></span></dt>
|
||
<dt><span class="section"><a href="object.html#python.extracting_c___objects">Extracting C++ objects</a></span></dt>
|
||
<dt><span class="section"><a href="object.html#python.enums">Enums</a></span></dt>
|
||
</dl></div>
|
||
<p>
|
||
Python is dynamically typed, unlike C++ which is statically typed. Python
|
||
variables may hold an integer, a float, list, dict, tuple, str, long etc.,
|
||
among other things. In the viewpoint of Boost.Python and C++, these
|
||
Pythonic variables are just instances of class <tt class="literal">object</tt>. We shall see in
|
||
this chapter how to deal with Python objects.</p>
|
||
<p>
|
||
As mentioned, one of the goals of Boost.Python is to provide a
|
||
bidirectional mapping between C++ and Python while maintaining the Python
|
||
feel. Boost.Python C++ <tt class="literal">object</tt>s are as close as possible to Python. This
|
||
should minimize the learning curve significantly.</p>
|
||
<p><span class="inlinemediaobject"><img src="../images/python.png"></span></p>
|
||
<div class="section" lang="en">
|
||
<div class="titlepage"><div><div><h3 class="title">
|
||
<a name="python.basic_interface"></a>Basic Interface</h3></div></div></div>
|
||
<p>
|
||
Class <tt class="literal">object</tt> wraps <tt class="literal">PyObject*</tt>. All the intricacies of dealing with
|
||
<tt class="literal">PyObject</tt>s such as managing reference counting are handled by the
|
||
<tt class="literal">object</tt> class. C++ object interoperability is seamless. Boost.Python C++
|
||
<tt class="literal">object</tt>s can in fact be explicitly constructed from any C++ object.</p>
|
||
<p>
|
||
To illustrate, this Python code snippet:</p>
|
||
<pre class="programlisting"><tt class="literal"><span class="identifier">def</span><span class="identifier"> f</span><span class="special">(</span><span class="identifier">x</span><span class="special">,</span><span class="identifier"> y</span><span class="special">):</span><span class="keyword">
|
||
if</span><span class="special"> (</span><span class="identifier">y</span><span class="special"> ==</span><span class="char"> 'foo'</span><span class="special">):</span><span class="identifier">
|
||
x</span><span class="special">[</span><span class="number">3</span><span class="special">:</span><span class="number">7</span><span class="special">]</span><span class="special"> =</span><span class="char"> 'bar'</span><span class="keyword">
|
||
else</span><span class="special">:</span><span class="identifier">
|
||
x</span><span class="special">.</span><span class="identifier">items</span><span class="special"> +=</span><span class="identifier"> y</span><span class="special">(</span><span class="number">3</span><span class="special">,</span><span class="identifier"> x</span><span class="special">)</span><span class="keyword">
|
||
return</span><span class="identifier"> x</span><span class="identifier">
|
||
|
||
def</span><span class="identifier"> getfunc</span><span class="special">():</span><span class="keyword">
|
||
return</span><span class="identifier"> f</span><span class="special">;</span></tt></pre>
|
||
<p>
|
||
Can be rewritten in C++ using Boost.Python facilities this way:</p>
|
||
<pre class="programlisting"><tt class="literal"><span class="identifier">object</span><span class="identifier"> f</span><span class="special">(</span><span class="identifier">object</span><span class="identifier"> x</span><span class="special">,</span><span class="identifier"> object</span><span class="identifier"> y</span><span class="special">)</span><span class="special"> {</span><span class="keyword">
|
||
if</span><span class="special"> (</span><span class="identifier">y</span><span class="special"> ==</span><span class="string"> "foo"</span><span class="special">)</span><span class="identifier">
|
||
x</span><span class="special">.</span><span class="identifier">slice</span><span class="special">(</span><span class="number">3</span><span class="special">,</span><span class="number">7</span><span class="special">)</span><span class="special"> =</span><span class="string"> "bar"</span><span class="special">;</span><span class="keyword">
|
||
else</span><span class="identifier">
|
||
x</span><span class="special">.</span><span class="identifier">attr</span><span class="special">(</span><span class="string">"items"</span><span class="special">)</span><span class="special"> +=</span><span class="identifier"> y</span><span class="special">(</span><span class="number">3</span><span class="special">,</span><span class="identifier"> x</span><span class="special">);</span><span class="keyword">
|
||
return</span><span class="identifier"> x</span><span class="special">;</span><span class="special">
|
||
}</span><span class="identifier">
|
||
object</span><span class="identifier"> getfunc</span><span class="special">()</span><span class="special"> {</span><span class="keyword">
|
||
return</span><span class="identifier"> object</span><span class="special">(</span><span class="identifier">f</span><span class="special">);</span><span class="special">
|
||
}</span></tt></pre>
|
||
<p>
|
||
Apart from cosmetic differences due to the fact that we are writing the
|
||
code in C++, the look and feel should be immediately apparent to the Python
|
||
coder.</p>
|
||
</div>
|
||
<div class="section" lang="en">
|
||
<div class="titlepage"><div><div><h3 class="title">
|
||
<a name="python.derived_object_types"></a>Derived Object types</h3></div></div></div>
|
||
<p>
|
||
Boost.Python comes with a set of derived <tt class="literal">object</tt> types corresponding to
|
||
that of Python's:</p>
|
||
<div class="itemizedlist"><ul type="disc">
|
||
<li>
|
||
list
|
||
</li>
|
||
<li>
|
||
dict
|
||
</li>
|
||
<li>
|
||
tuple
|
||
</li>
|
||
<li>
|
||
str
|
||
</li>
|
||
<li>
|
||
long_
|
||
</li>
|
||
<li>
|
||
enum
|
||
</li>
|
||
</ul></div>
|
||
<p>
|
||
These derived <tt class="literal">object</tt> types act like real Python types. For instance:</p>
|
||
<pre class="programlisting"><tt class="literal"><span class="identifier">str</span><span class="special">(</span><span class="number">1</span><span class="special">)</span><span class="special"> ==></span><span class="string"> "1"</span></tt></pre>
|
||
<p>
|
||
Wherever appropriate, a particular derived <tt class="literal">object</tt> has corresponding
|
||
Python type's methods. For instance, <tt class="literal">dict</tt> has a <tt class="literal">keys()</tt> method:</p>
|
||
<pre class="programlisting"><tt class="literal"><span class="identifier">d</span><span class="special">.</span><span class="identifier">keys</span><span class="special">()</span></tt></pre>
|
||
<p><tt class="literal">make_tuple</tt> is provided for declaring <span class="emphasis"><em>tuple literals</em></span>. Example:</p>
|
||
<pre class="programlisting"><tt class="literal"><span class="identifier">make_tuple</span><span class="special">(</span><span class="number">123</span><span class="special">,</span><span class="char"> 'D'</span><span class="special">,</span><span class="string"> "Hello, World"</span><span class="special">,</span><span class="number"> 0.0</span><span class="special">);</span></tt></pre>
|
||
<p>
|
||
In C++, when Boost.Python <tt class="literal">object</tt>s are used as arguments to functions,
|
||
subtype matching is required. For example, when a function <tt class="literal">f</tt>, as
|
||
declared below, is wrapped, it will only accept instances of Python's
|
||
<tt class="literal">str</tt> type and subtypes.</p>
|
||
<pre class="programlisting"><tt class="literal"><span class="keyword">void</span><span class="identifier"> f</span><span class="special">(</span><span class="identifier">str</span><span class="identifier"> name</span><span class="special">)</span><span class="special">
|
||
{</span><span class="identifier">
|
||
object</span><span class="identifier"> n2</span><span class="special"> =</span><span class="identifier"> name</span><span class="special">.</span><span class="identifier">attr</span><span class="special">(</span><span class="string">"upper"</span><span class="special">)();</span><span class="comment"> // NAME = name.upper()
|
||
</span><span class="identifier"> str</span><span class="identifier"> NAME</span><span class="special"> =</span><span class="identifier"> name</span><span class="special">.</span><span class="identifier">upper</span><span class="special">();</span><span class="comment"> // better
|
||
</span><span class="identifier"> object</span><span class="identifier"> msg</span><span class="special"> =</span><span class="string"> "%s is bigger than %s"</span><span class="special"> %</span><span class="identifier"> make_tuple</span><span class="special">(</span><span class="identifier">NAME</span><span class="special">,</span><span class="identifier">name</span><span class="special">);</span><span class="special">
|
||
}</span></tt></pre>
|
||
<p>
|
||
In finer detail:</p>
|
||
<pre class="programlisting"><tt class="literal"><span class="identifier">str</span><span class="identifier"> NAME</span><span class="special"> =</span><span class="identifier"> name</span><span class="special">.</span><span class="identifier">upper</span><span class="special">();</span></tt></pre>
|
||
<p>
|
||
Illustrates that we provide versions of the str type's methods as C++
|
||
member functions.</p>
|
||
<pre class="programlisting"><tt class="literal"><span class="identifier">object</span><span class="identifier"> msg</span><span class="special"> =</span><span class="string"> "%s is bigger than %s"</span><span class="special"> %</span><span class="identifier"> make_tuple</span><span class="special">(</span><span class="identifier">NAME</span><span class="special">,</span><span class="identifier">name</span><span class="special">);</span></tt></pre>
|
||
<p>
|
||
Demonstrates that you can write the C++ equivalent of <tt class="literal">"format" % x,y,z</tt>
|
||
in Python, which is useful since there's no easy way to do that in std C++.</p>
|
||
<p><span class="inlinemediaobject"><img src="../images/alert.png"></span><span class="bold"><b>Beware</b></span> the common pitfall of forgetting that the constructors
|
||
of most of Python's mutable types make copies, just as in Python.</p>
|
||
<p>
|
||
Python:</p>
|
||
<pre class="programlisting"><tt class="literal"><span class="special">>>></span><span class="identifier"> d</span><span class="special"> =</span><span class="identifier"> dict</span><span class="special">(</span><span class="identifier">x</span><span class="special">.</span><span class="identifier">__dict__</span><span class="special">)</span> #<span class="identifier"> copies</span><span class="identifier"> x</span><span class="special">.</span><span class="identifier">__dict__</span><span class="special">
|
||
>>></span><span class="identifier"> d</span><span class="special">[</span><span class="char">'whatever'</span><span class="special">]</span> #<span class="identifier"> modifies</span><span class="identifier"> the</span><span class="identifier"> copy</span></tt></pre>
|
||
<p>
|
||
C++:</p>
|
||
<pre class="programlisting"><tt class="literal"><span class="identifier">dict</span><span class="identifier"> d</span><span class="special">(</span><span class="identifier">x</span><span class="special">.</span><span class="identifier">attr</span><span class="special">(</span><span class="string">"__dict__"</span><span class="special">));</span> #<span class="identifier"> copies</span><span class="identifier"> x</span><span class="special">.</span><span class="identifier">__dict__</span><span class="identifier">
|
||
d</span><span class="special">[</span><span class="char">'whatever'</span><span class="special">]</span><span class="special"> =</span><span class="number"> 3</span><span class="special">;</span> #<span class="identifier"> modifies</span><span class="identifier"> the</span><span class="identifier"> copy</span></tt></pre>
|
||
<a name="derived_object_types.class__lt_t_gt__as_objects"></a><h2>
|
||
<a name="id459892"></a>class_<T> as objects</h2>
|
||
<p>
|
||
Due to the dynamic nature of Boost.Python objects, any <tt class="literal">class_<T></tt> may
|
||
also be one of these types! The following code snippet wraps the class
|
||
(type) object.</p>
|
||
<p>
|
||
We can use this to create wrapped instances. Example:</p>
|
||
<pre class="programlisting"><tt class="literal"><span class="identifier">object</span><span class="identifier"> vec345</span><span class="special"> =</span><span class="special"> (</span><span class="identifier">
|
||
class_</span><span class="special"><</span><span class="identifier">Vec2</span><span class="special">>(</span><span class="string">"Vec2"</span><span class="special">,</span><span class="identifier"> init</span><span class="special"><</span><span class="keyword">double</span><span class="special">,</span><span class="keyword"> double</span><span class="special">>())</span><span class="special">
|
||
.</span><span class="identifier">def_readonly</span><span class="special">(</span><span class="string">"length"</span><span class="special">,</span><span class="special"> &</span><span class="identifier">Point</span><span class="special">::</span><span class="identifier">length</span><span class="special">)</span><span class="special">
|
||
.</span><span class="identifier">def_readonly</span><span class="special">(</span><span class="string">"angle"</span><span class="special">,</span><span class="special"> &</span><span class="identifier">Point</span><span class="special">::</span><span class="identifier">angle</span><span class="special">)</span><span class="special">
|
||
)(</span><span class="number">3.0</span><span class="special">,</span><span class="number"> 4.0</span><span class="special">);</span><span class="identifier">
|
||
|
||
assert</span><span class="special">(</span><span class="identifier">vec345</span><span class="special">.</span><span class="identifier">attr</span><span class="special">(</span><span class="string">"length"</span><span class="special">)</span><span class="special"> ==</span><span class="number"> 5.0</span><span class="special">);</span></tt></pre>
|
||
</div>
|
||
<div class="section" lang="en">
|
||
<div class="titlepage"><div><div><h3 class="title">
|
||
<a name="python.extracting_c___objects"></a>Extracting C++ objects</h3></div></div></div>
|
||
<p>
|
||
At some point, we will need to get C++ values out of object instances. This
|
||
can be achieved with the <tt class="literal">extract<T></tt> function. Consider the following:</p>
|
||
<pre class="programlisting"><tt class="literal"><span class="keyword">double</span><span class="identifier"> x</span><span class="special"> =</span><span class="identifier"> o</span><span class="special">.</span><span class="identifier">attr</span><span class="special">(</span><span class="string">"length"</span><span class="special">);</span><span class="comment"> // compile error
|
||
</span></tt></pre>
|
||
<p>
|
||
In the code above, we got a compiler error because Boost.Python
|
||
<tt class="literal">object</tt> can't be implicitly converted to <tt class="literal">double</tt>s. Instead, what
|
||
we wanted to do above can be achieved by writing:</p>
|
||
<pre class="programlisting"><tt class="literal"><span class="keyword">double</span><span class="identifier"> l</span><span class="special"> =</span><span class="identifier"> extract</span><span class="special"><</span><span class="keyword">double</span><span class="special">>(</span><span class="identifier">o</span><span class="special">.</span><span class="identifier">attr</span><span class="special">(</span><span class="string">"length"</span><span class="special">));</span><span class="identifier">
|
||
Vec2</span><span class="special">&</span><span class="identifier"> v</span><span class="special"> =</span><span class="identifier"> extract</span><span class="special"><</span><span class="identifier">Vec2</span><span class="special">&>(</span><span class="identifier">o</span><span class="special">);</span><span class="identifier">
|
||
assert</span><span class="special">(</span><span class="identifier">l</span><span class="special"> ==</span><span class="identifier"> v</span><span class="special">.</span><span class="identifier">length</span><span class="special">());</span></tt></pre>
|
||
<p>
|
||
The first line attempts to extract the "length" attribute of the
|
||
Boost.Python <tt class="literal">object</tt><tt class="literal">o</tt>. The second line attempts to <span class="emphasis"><em>extract</em></span> the
|
||
<tt class="literal">Vec2</tt> object from held by the Boost.Python <tt class="literal">object</tt><tt class="literal">o</tt>.</p>
|
||
<p>
|
||
Take note that we said "attempt to" above. What if the Boost.Python
|
||
<tt class="literal">object</tt><tt class="literal">o</tt> does not really hold a <tt class="literal">Vec2</tt> type? This is certainly
|
||
a possibility considering the dynamic nature of Python <tt class="literal">object</tt>s. To
|
||
be on the safe side, if the C++ type can't be extracted, an
|
||
appropriate exception is thrown. To avoid an exception, we need to
|
||
test for extractibility:</p>
|
||
<pre class="programlisting"><tt class="literal"><span class="identifier">extract</span><span class="special"><</span><span class="identifier">Vec2</span><span class="special">&></span><span class="identifier"> x</span><span class="special">(</span><span class="identifier">o</span><span class="special">);</span><span class="keyword">
|
||
if</span><span class="special"> (</span><span class="identifier">x</span><span class="special">.</span><span class="identifier">check</span><span class="special">())</span><span class="special"> {</span><span class="identifier">
|
||
Vec2</span><span class="special">&</span><span class="identifier"> v</span><span class="special"> =</span><span class="identifier"> x</span><span class="special">();</span><span class="special"> ...</span></tt></pre>
|
||
<p><span class="inlinemediaobject"><img src="../images/tip.png"></span> The astute reader might have noticed that the <tt class="literal">extract<T></tt>
|
||
facility in fact solves the mutable copying problem:</p>
|
||
<pre class="programlisting"><tt class="literal"><span class="identifier">dict</span><span class="identifier"> d</span><span class="special"> =</span><span class="identifier"> extract</span><span class="special"><</span><span class="identifier">dict</span><span class="special">>(</span><span class="identifier">x</span><span class="special">.</span><span class="identifier">attr</span><span class="special">(</span><span class="string">"__dict__"</span><span class="special">));</span><span class="identifier">
|
||
d</span><span class="special">[</span><span class="char">'whatever'</span><span class="special">]</span><span class="special"> =</span><span class="number"> 3</span><span class="special">;</span> #<span class="identifier"> modifies</span><span class="identifier"> x</span><span class="special">.</span><span class="identifier">__dict__</span><span class="special"> !</span></tt></pre>
|
||
</div>
|
||
<div class="section" lang="en">
|
||
<div class="titlepage"><div><div><h3 class="title">
|
||
<a name="python.enums"></a>Enums</h3></div></div></div>
|
||
<p>
|
||
Boost.Python has a nifty facility to capture and wrap C++ enums. While
|
||
Python has no <tt class="literal">enum</tt> type, we'll often want to expose our C++ enums to
|
||
Python as an <tt class="literal">int</tt>. Boost.Python's enum facility makes this easy while
|
||
taking care of the proper conversions from Python's dynamic typing to C++'s
|
||
strong static typing (in C++, ints cannot be implicitly converted to
|
||
enums). To illustrate, given a C++ enum:</p>
|
||
<pre class="programlisting"><tt class="literal"><span class="keyword">enum</span><span class="identifier"> choice</span><span class="special"> {</span><span class="identifier"> red</span><span class="special">,</span><span class="identifier"> blue</span><span class="special"> };</span></tt></pre>
|
||
<p>
|
||
the construct:</p>
|
||
<pre class="programlisting"><tt class="literal"><span class="identifier">enum_</span><span class="special"><</span><span class="identifier">choice</span><span class="special">>(</span><span class="string">"choice"</span><span class="special">)</span><span class="special">
|
||
.</span><span class="identifier">value</span><span class="special">(</span><span class="string">"red"</span><span class="special">,</span><span class="identifier"> red</span><span class="special">)</span><span class="special">
|
||
.</span><span class="identifier">value</span><span class="special">(</span><span class="string">"blue"</span><span class="special">,</span><span class="identifier"> blue</span><span class="special">)</span><span class="special">
|
||
;</span></tt></pre>
|
||
<p>
|
||
can be used to expose to Python. The new enum type is created in the
|
||
current <tt class="literal">scope()</tt>, which is usually the current module. The snippet above
|
||
creates a Python class derived from Python's <tt class="literal">int</tt> type which is
|
||
associated with the C++ type passed as its first parameter.</p>
|
||
<div class="informaltable"><table class="table">
|
||
<colgroup><col></colgroup>
|
||
<tbody><tr><td>
|
||
<span class="inlinemediaobject"><img src="../images/note.png"></span><span class="bold"><b>what is a scope?</b></span><p></p>
|
||
<p></p>
|
||
The scope is a class that has an
|
||
associated global Python object which controls the Python namespace in
|
||
which new extension classes and wrapped functions will be defined as
|
||
attributes. Details can be found <a href="../../../../v2/scope.html" target="_top">here</a>.</td></tr></tbody>
|
||
</table></div>
|
||
<p>
|
||
You can access those values in Python as</p>
|
||
<pre class="programlisting"><tt class="literal"><span class="special">>>></span><span class="identifier"> my_module</span><span class="special">.</span><span class="identifier">choice</span><span class="special">.</span><span class="identifier">red</span><span class="identifier">
|
||
my_module</span><span class="special">.</span><span class="identifier">choice</span><span class="special">.</span><span class="identifier">red</span></tt></pre>
|
||
<p>
|
||
where my_module is the module where the enum is declared. You can also
|
||
create a new scope around a class:</p>
|
||
<pre class="programlisting"><tt class="literal"><span class="identifier">scope</span><span class="identifier"> in_X</span><span class="special"> =</span><span class="identifier"> class_</span><span class="special"><</span><span class="identifier">X</span><span class="special">>(</span><span class="string">"X"</span><span class="special">)</span><span class="special">
|
||
.</span><span class="identifier">def</span><span class="special">(</span><span class="special"> ...</span><span class="special"> )</span><span class="special">
|
||
.</span><span class="identifier">def</span><span class="special">(</span><span class="special"> ...</span><span class="special"> )</span><span class="special">
|
||
;</span><span class="comment">
|
||
|
||
// Expose X::nested as X.nested
|
||
</span><span class="identifier">enum_</span><span class="special"><</span><span class="identifier">X</span><span class="special">::</span><span class="identifier">nested</span><span class="special">>(</span><span class="string">"nested"</span><span class="special">)</span><span class="special">
|
||
.</span><span class="identifier">value</span><span class="special">(</span><span class="string">"red"</span><span class="special">,</span><span class="identifier"> red</span><span class="special">)</span><span class="special">
|
||
.</span><span class="identifier">value</span><span class="special">(</span><span class="string">"blue"</span><span class="special">,</span><span class="identifier"> blue</span><span class="special">)</span><span class="special">
|
||
;</span></tt></pre>
|
||
</div>
|
||
</div>
|
||
<table xmlns:rev="http://www.cs.rpi.edu/~gregod/boost/tools/doc/revision" width="100%"><tr>
|
||
<td align="left"></td>
|
||
<td align="right"><small>Copyright © 2002-2004 Joel de Guzman, David Abrahams</small></td>
|
||
</tr></table>
|
||
<hr>
|
||
<div class="spirit-nav">
|
||
<a accesskey="p" href="functions.html"><img src="../images/prev.png" alt="Prev"></a><a accesskey="u" href="../index.html"><img src="../images/up.png" alt="Up"></a><a accesskey="h" href="../index.html"><img src="../images/home.png" alt="Home"></a><a accesskey="n" href="embedding.html"><img src="../images/next.png" alt="Next"></a>
|
||
</div>
|
||
</body>
|
||
</html>
|