2007-06-30 14:31:14 -04:00
|
|
|
|
PEP: 3136
|
|
|
|
|
Title: Labeled break and continue
|
|
|
|
|
Version: $Revision$
|
|
|
|
|
Last-Modified: $Date$
|
|
|
|
|
Author: Matt Chisholm <matt-python@theory.org>
|
2007-07-18 19:11:31 -04:00
|
|
|
|
Status: Rejected
|
2007-06-30 14:31:14 -04:00
|
|
|
|
Type: Standards Track
|
|
|
|
|
Content-Type: text/x-rst
|
|
|
|
|
Created: 30-Jun-2007
|
|
|
|
|
Python-Version: 3.1
|
|
|
|
|
Post-History:
|
|
|
|
|
|
|
|
|
|
|
2007-07-18 19:11:31 -04:00
|
|
|
|
Rejection Notice
|
|
|
|
|
================
|
|
|
|
|
|
|
|
|
|
This PEP is rejected.
|
|
|
|
|
See http://mail.python.org/pipermail/python-3000/2007-July/008663.html.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2007-06-30 14:31:14 -04:00
|
|
|
|
Abstract
|
|
|
|
|
========
|
|
|
|
|
|
|
|
|
|
This PEP proposes support for labels in Python's ``break`` and
|
|
|
|
|
``continue`` statements. It is inspired by labeled ``break`` and
|
|
|
|
|
``continue`` in other languages, and the author's own infrequent but
|
|
|
|
|
persistent need for such a feature.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Introduction
|
|
|
|
|
============
|
|
|
|
|
|
|
|
|
|
The ``break`` statement allows the programmer to terminate a loop
|
|
|
|
|
early, and the ``continue`` statement allows the programmer to move to
|
|
|
|
|
the next iteration of a loop early. In Python currently, ``break``
|
|
|
|
|
and ``continue`` can apply only to the innermost enclosing loop.
|
|
|
|
|
|
|
|
|
|
Adding support for labels to the ``break`` and ``continue`` statements
|
|
|
|
|
is a logical extension to the existing behavior of the ``break`` and
|
|
|
|
|
``continue`` statements. Labeled ``break`` and ``continue`` can
|
|
|
|
|
improve the readability and flexibility of complex code which uses
|
|
|
|
|
nested loops.
|
|
|
|
|
|
|
|
|
|
For brevity's sake, the examples and discussion in this PEP usually
|
|
|
|
|
refers to the ``break`` statement. However, all of the examples and
|
|
|
|
|
motivations apply equally to labeled ``continue``.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Motivation
|
|
|
|
|
==========
|
|
|
|
|
|
|
|
|
|
If the programmer wishes to move to the next iteration of an outer
|
|
|
|
|
enclosing loop, or terminate multiple loops at once, he or she has a
|
|
|
|
|
few less-than elegant options.
|
|
|
|
|
|
|
|
|
|
Here's one common way of imitating labeled ``break`` in Python (For
|
|
|
|
|
this and future examples, ``...`` denotes an arbitrary number of
|
|
|
|
|
intervening lines of code)::
|
|
|
|
|
|
|
|
|
|
for a in a_list:
|
|
|
|
|
time_to_break_out_of_a = False
|
|
|
|
|
...
|
|
|
|
|
for b in b_list:
|
|
|
|
|
...
|
|
|
|
|
if condition_one(a, b):
|
|
|
|
|
break
|
|
|
|
|
...
|
|
|
|
|
if condition_two(a, b):
|
|
|
|
|
time_to_break_out_of_a = True
|
|
|
|
|
break
|
|
|
|
|
...
|
|
|
|
|
if time_to_break_out_of_a:
|
|
|
|
|
break
|
|
|
|
|
...
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
This requires five lines and an extra variable,
|
|
|
|
|
``time_to_break_out_of_a``, to keep track of when to break out of the
|
|
|
|
|
outer (a) loop. And those five lines are spread across many lines of
|
|
|
|
|
code, making the control flow difficult to understand.
|
|
|
|
|
|
|
|
|
|
This technique is also error-prone. A programmer modifying this code
|
|
|
|
|
might inadvertently put new code after the end of the inner (b) loop
|
|
|
|
|
but before the test for ``time_to_break_out_of_a``, instead of after
|
|
|
|
|
the test. This means that code which should have been skipped by
|
|
|
|
|
breaking out of the outer loop gets executed incorrectly.
|
|
|
|
|
|
|
|
|
|
This could also be written with an exception. The programmer would
|
|
|
|
|
declare a special exception, wrap the inner loop in a try, and catch
|
|
|
|
|
the exception and break when you see it::
|
|
|
|
|
|
|
|
|
|
class BreakOutOfALoop(Exception): pass
|
|
|
|
|
|
|
|
|
|
for a in a_list:
|
|
|
|
|
...
|
|
|
|
|
try:
|
|
|
|
|
for b in b_list:
|
|
|
|
|
...
|
|
|
|
|
if condition_one(a, b):
|
|
|
|
|
break
|
|
|
|
|
...
|
|
|
|
|
if condition_two(a, b):
|
|
|
|
|
raise BreakOutOfALoop
|
|
|
|
|
...
|
|
|
|
|
except BreakOutOfALoop:
|
|
|
|
|
break
|
|
|
|
|
...
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Again, though; this requires five lines and a new, single-purpose
|
|
|
|
|
exception class (instead of a new variable), and spreads basic control
|
|
|
|
|
flow out over many lines. And it breaks out of the inner loop with
|
|
|
|
|
``break`` and out of the other loop with an exception, which is
|
|
|
|
|
inelegant. [#toowtdi]_
|
|
|
|
|
|
|
|
|
|
This next strategy might be the most elegant solution, assuming
|
|
|
|
|
condition_two() is inexpensive to compute::
|
|
|
|
|
|
|
|
|
|
for a in a_list:
|
|
|
|
|
...
|
|
|
|
|
for b in b_list:
|
|
|
|
|
...
|
|
|
|
|
if condition_one(a, b):
|
|
|
|
|
break
|
|
|
|
|
...
|
|
|
|
|
if condition_two(a, b):
|
|
|
|
|
break
|
|
|
|
|
...
|
|
|
|
|
if condition_two(a, b)
|
|
|
|
|
break
|
|
|
|
|
...
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Breaking twice is still inelegant. This implementation also relies on
|
|
|
|
|
the fact that the inner (b) loop bleeds b into the outer for loop,
|
|
|
|
|
which (although explicitly supported) is both surprising to novices,
|
|
|
|
|
and in my opinion counter-intuitive and poor practice.
|
|
|
|
|
|
|
|
|
|
The programmer must also still remember to put in both breaks on
|
|
|
|
|
condition two and not insert code before the second break. A single
|
|
|
|
|
conceptual action, breaking out of both loops on condition_two(),
|
|
|
|
|
requires four lines of code at two indentation levels, possibly
|
|
|
|
|
separated by many intervening lines at the end of the inner (b) loop.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Other languages
|
|
|
|
|
---------------
|
|
|
|
|
|
|
|
|
|
Now, put aside whatever dislike you may have for other programming
|
|
|
|
|
languages, and consider the syntax of labeled ``break`` and
|
|
|
|
|
``continue``. In Perl::
|
|
|
|
|
|
|
|
|
|
ALOOP: foreach $a (@a_array){
|
|
|
|
|
...
|
|
|
|
|
BLOOP: foreach $b (@b_array){
|
|
|
|
|
...
|
|
|
|
|
if (condition_one($a,$b)){
|
|
|
|
|
last BLOOP; # same as plain old last;
|
|
|
|
|
}
|
|
|
|
|
...
|
|
|
|
|
if (condition_two($a,$b)){
|
|
|
|
|
last ALOOP;
|
|
|
|
|
}
|
|
|
|
|
...
|
|
|
|
|
}
|
|
|
|
|
...
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
(Notes: Perl uses ``last`` instead of ``break``. The BLOOP labels
|
|
|
|
|
could be omitted; ``last`` and ``continue`` apply to the innermost
|
|
|
|
|
loop by default.)
|
|
|
|
|
|
|
|
|
|
PHP uses a number denoting the number of loops to break out of, rather
|
|
|
|
|
than a label::
|
|
|
|
|
|
|
|
|
|
foreach ($a_array as $a){
|
|
|
|
|
....
|
|
|
|
|
foreach ($b_array as $b){
|
|
|
|
|
....
|
|
|
|
|
if (condition_one($a, $b)){
|
|
|
|
|
break 1; # same as plain old break
|
|
|
|
|
}
|
|
|
|
|
....
|
|
|
|
|
if (condition_two($a, $b)){
|
|
|
|
|
break 2;
|
|
|
|
|
}
|
|
|
|
|
....
|
2017-03-23 18:57:19 -04:00
|
|
|
|
}
|
2007-06-30 14:31:14 -04:00
|
|
|
|
...
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
C/C++, Java, and Ruby all have similar constructions.
|
|
|
|
|
|
|
|
|
|
The control flow regarding when to break out of the outer (a) loop is
|
|
|
|
|
fully encapsulated in the ``break`` statement which gets executed when
|
|
|
|
|
the break condition is satisfied. The depth of the break statement
|
|
|
|
|
does not matter. Control flow is not spread out. No extra variables,
|
|
|
|
|
exceptions, or re-checking or storing of control conditions is
|
|
|
|
|
required. There is no danger that code will get inadvertently
|
|
|
|
|
inserted after the end of the inner (b) loop and before the break
|
|
|
|
|
condition is re-checked inside the outer (a) loop. These are the
|
|
|
|
|
benefits that labeled ``break`` and ``continue`` would bring to
|
|
|
|
|
Python.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
What this PEP is not
|
|
|
|
|
====================
|
|
|
|
|
|
|
|
|
|
This PEP is not a proposal to add GOTO to Python. GOTO allows a
|
|
|
|
|
programmer to jump to an arbitrary block or line of code, and
|
|
|
|
|
generally makes control flow more difficult to follow. Although
|
|
|
|
|
``break`` and ``continue`` (with or without support for labels) can be
|
|
|
|
|
considered a type of GOTO, it is much more restricted. Another Python
|
|
|
|
|
construct, ``yield``, could also be considered a form of GOTO -- an
|
|
|
|
|
even less restrictive one. The goal of this PEP is to propose an
|
|
|
|
|
extension to the existing control flow tools ``break`` and
|
|
|
|
|
``continue``, to make control flow easier to understand, not more
|
|
|
|
|
difficult.
|
|
|
|
|
|
|
|
|
|
Labeled ``break`` and ``continue`` cannot transfer control to another
|
|
|
|
|
function or method. They cannot even transfer control to an arbitrary
|
|
|
|
|
line of code in the current scope. Currently, they can only affect
|
|
|
|
|
the behavior of a loop, and are quite different and much more
|
|
|
|
|
restricted than GOTO. This extension allows them to affect any
|
|
|
|
|
enclosing loop in the current name-space, but it does not change their
|
|
|
|
|
behavior to that of GOTO.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Specification
|
|
|
|
|
=============
|
|
|
|
|
|
|
|
|
|
Under all of these proposals, ``break`` and ``continue`` by themselves
|
|
|
|
|
will continue to behave as they currently do, applying to the
|
|
|
|
|
innermost loop by default.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Proposal A - Explicit labels
|
|
|
|
|
----------------------------
|
|
|
|
|
|
|
|
|
|
The for and while loop syntax will be followed by an optional ``as``
|
|
|
|
|
or ``label`` (contextual) keyword [#keyword]_ and then an identifier,
|
|
|
|
|
which may be used to identify the loop out of which to break (or which
|
|
|
|
|
should be continued).
|
|
|
|
|
|
|
|
|
|
The ``break`` (and ``continue``) statements will be followed by an
|
|
|
|
|
optional identifier that refers to the loop out of which to break (or
|
|
|
|
|
which should be continued). Here is an example using the ``as``
|
|
|
|
|
keyword::
|
|
|
|
|
|
|
|
|
|
for a in a_list as a_loop:
|
|
|
|
|
...
|
|
|
|
|
for b in b_list as b_loop:
|
|
|
|
|
...
|
|
|
|
|
if condition_one(a, b):
|
|
|
|
|
break b_loop # same as plain old break
|
|
|
|
|
...
|
|
|
|
|
if condition_two(a, b):
|
|
|
|
|
break a_loop
|
|
|
|
|
...
|
|
|
|
|
...
|
|
|
|
|
|
|
|
|
|
Or, with ``label`` instead of ``as``::
|
|
|
|
|
|
|
|
|
|
for a in a_list label a_loop:
|
|
|
|
|
...
|
|
|
|
|
for b in b_list label b_loop:
|
|
|
|
|
...
|
|
|
|
|
if condition_one(a, b):
|
|
|
|
|
break b_loop # same as plain old break
|
|
|
|
|
...
|
|
|
|
|
if condition_two(a, b):
|
|
|
|
|
break a_loop
|
|
|
|
|
...
|
|
|
|
|
...
|
2017-03-24 17:11:33 -04:00
|
|
|
|
|
2007-06-30 14:31:14 -04:00
|
|
|
|
|
|
|
|
|
This has all the benefits outlined above. It requires modifications
|
|
|
|
|
to the language syntax: the syntax of ``break`` and ``continue``
|
|
|
|
|
syntax statements and for and while statements. It requires either a
|
|
|
|
|
new conditional keyword ``label`` or an extension to the conditional
|
|
|
|
|
keyword ``as``. [#as]_ It is unlikely to require any changes to
|
|
|
|
|
existing Python programs. Passing an identifier not defined in the
|
|
|
|
|
local scope to ``break`` or ``continue`` would raise a NameError.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Proposal B - Numeric break & continue
|
|
|
|
|
-------------------------------------
|
|
|
|
|
|
|
|
|
|
Rather than altering the syntax of ``for`` and ``while`` loops,
|
|
|
|
|
``break`` and ``continue`` would take a numeric argument denoting the
|
|
|
|
|
enclosing loop which is being controlled, similar to PHP.
|
|
|
|
|
|
|
|
|
|
It seems more Pythonic to me for ``break`` and ``continue`` to refer
|
|
|
|
|
to loops indexing from zero, as opposed to indexing from one as PHP
|
|
|
|
|
does.
|
|
|
|
|
|
|
|
|
|
::
|
|
|
|
|
|
|
|
|
|
for a in a_list:
|
|
|
|
|
...
|
|
|
|
|
for b in b_list:
|
|
|
|
|
...
|
|
|
|
|
if condition_one(a,b):
|
|
|
|
|
break 0 # same as plain old break
|
|
|
|
|
...
|
|
|
|
|
if condition_two(a,b):
|
|
|
|
|
break 1
|
|
|
|
|
...
|
|
|
|
|
...
|
|
|
|
|
|
|
|
|
|
Passing a number that was too large, or less than zero, or non-integer
|
|
|
|
|
to ``break`` or ``continue`` would (probably) raise an IndexError.
|
|
|
|
|
|
|
|
|
|
This proposal would not require any changes to existing Python
|
|
|
|
|
programs.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Proposal C - The reduplicative method
|
|
|
|
|
-------------------------------------
|
|
|
|
|
|
|
|
|
|
The syntax of ``break`` and ``continue`` would be altered to allow
|
|
|
|
|
multiple ``break`` and continue statements on the same line. Thus,
|
|
|
|
|
``break break`` would break out of the first and second enclosing
|
|
|
|
|
loops.
|
|
|
|
|
|
|
|
|
|
::
|
|
|
|
|
|
|
|
|
|
for a in a_list:
|
|
|
|
|
...
|
|
|
|
|
for b in b_list:
|
|
|
|
|
...
|
|
|
|
|
if condition_one(a,b):
|
|
|
|
|
break # plain old break
|
|
|
|
|
...
|
|
|
|
|
if condition_two(a,b):
|
|
|
|
|
break break
|
|
|
|
|
...
|
|
|
|
|
...
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
This would also allow the programmer to break out of the inner loop
|
|
|
|
|
and continue the next outermost simply by writing ``break continue``,
|
|
|
|
|
[#breakcontinue]_ and so on. I'm not sure what exception would be
|
|
|
|
|
raised if the programmer used more ``break`` or ``continue``
|
|
|
|
|
statements than existing loops (perhaps a SyntaxError?).
|
|
|
|
|
|
|
|
|
|
I expect this proposal to get rejected because it will be judged too
|
|
|
|
|
difficult to understand.
|
|
|
|
|
|
|
|
|
|
This proposal would not require any changes to existing Python
|
|
|
|
|
programs.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Proposal D - Explicit iterators
|
|
|
|
|
-------------------------------
|
|
|
|
|
|
|
|
|
|
Rather than embellishing for and while loop syntax with labels, the
|
|
|
|
|
programmer wishing to use labeled breaks would be required to create
|
2016-05-03 06:52:22 -04:00
|
|
|
|
the iterator explicitly and assign it to an identifier if he or she
|
2007-06-30 14:31:14 -04:00
|
|
|
|
wanted to ``break`` out of or ``continue`` that loop from within a
|
|
|
|
|
deeper loop.
|
|
|
|
|
|
|
|
|
|
::
|
|
|
|
|
|
|
|
|
|
a_iter = iter(a_list)
|
|
|
|
|
for a in a_iter:
|
|
|
|
|
...
|
|
|
|
|
b_iter = iter(b_list)
|
|
|
|
|
for b in b_iter:
|
|
|
|
|
...
|
|
|
|
|
if condition_one(a,b):
|
|
|
|
|
break b_iter # same as plain old break
|
|
|
|
|
...
|
|
|
|
|
if condition_two(a,b):
|
|
|
|
|
break a_iter
|
|
|
|
|
...
|
|
|
|
|
...
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Passing a non-iterator object to ``break`` or ``continue`` would raise
|
|
|
|
|
a TypeError; and a nonexistent identifier would raise a NameError.
|
|
|
|
|
This proposal requires only one extra line to create a labeled loop,
|
|
|
|
|
and no extra lines to break out of a containing loop, and no changes
|
|
|
|
|
to existing Python programs.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Proposal E - Explicit iterators and iterator methods
|
|
|
|
|
----------------------------------------------------
|
|
|
|
|
|
|
|
|
|
This is a variant of Proposal D. Iterators would need be created
|
|
|
|
|
explicitly if anything other that the most basic use of ``break`` and
|
|
|
|
|
``continue`` was required. Instead of modifying the syntax of
|
|
|
|
|
``break`` and ``continue``, ``.break()`` and ``.continue()`` methods
|
|
|
|
|
could be added to the Iterator type.
|
|
|
|
|
|
|
|
|
|
::
|
|
|
|
|
|
|
|
|
|
a_iter = iter(a_list)
|
|
|
|
|
for a in a_iter:
|
|
|
|
|
...
|
|
|
|
|
b_iter = iter(b_list)
|
|
|
|
|
for b in b_iter:
|
|
|
|
|
...
|
|
|
|
|
if condition_one(a,b):
|
|
|
|
|
b_iter.break() # same as plain old break
|
|
|
|
|
...
|
|
|
|
|
if condition_two(a,b):
|
|
|
|
|
a_iter.break()
|
|
|
|
|
...
|
|
|
|
|
...
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
I expect that this proposal will get rejected on the grounds of sheer
|
|
|
|
|
ugliness. However, it requires no changes to the language syntax
|
|
|
|
|
whatsoever, nor does it require any changes to existing Python
|
|
|
|
|
programs.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Implementation
|
|
|
|
|
==============
|
|
|
|
|
|
|
|
|
|
I have never looked at the Python language implementation itself, so I
|
|
|
|
|
have no idea how difficult this would be to implement. If this PEP is
|
|
|
|
|
accepted, but no one is available to write the feature, I will try to
|
|
|
|
|
implement it myself.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Footnotes
|
|
|
|
|
=========
|
|
|
|
|
|
|
|
|
|
.. [#toowtdi] Breaking some loops with exceptions is inelegant because
|
|
|
|
|
it's a violation of There's Only One Way To Do It.
|
|
|
|
|
|
|
|
|
|
.. [#keyword] Or really any new contextual keyword that the community
|
|
|
|
|
likes: ``as``, ``label``, ``labeled``, ``loop``, ``name``, ``named``,
|
|
|
|
|
``walrus``, whatever.
|
|
|
|
|
|
2017-03-24 17:11:33 -04:00
|
|
|
|
.. [#as] The use of ``as`` in a similar context has been proposed here,
|
2007-06-30 14:31:14 -04:00
|
|
|
|
http://sourceforge.net/tracker/index.php?func=detail&aid=1714448&group_id=5470&atid=355470
|
2017-03-24 17:11:33 -04:00
|
|
|
|
but to my knowledge this idea has not been written up as a PEP.
|
2007-06-30 14:31:14 -04:00
|
|
|
|
|
|
|
|
|
.. [#breakcontinue] To continue the Nth outer loop, you would write
|
|
|
|
|
break N-1 times and then continue. Only one ``continue`` would be
|
|
|
|
|
allowed, and only at the end of a sequence of breaks. ``continue
|
|
|
|
|
break`` or ``continue continue`` makes no sense.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Resources
|
|
|
|
|
=========
|
|
|
|
|
|
|
|
|
|
This issue has come up before, although it has never been resolved, to
|
|
|
|
|
my knowledge.
|
|
|
|
|
|
|
|
|
|
* `labeled breaks`__, on comp.lang.python, in the context of
|
|
|
|
|
``do...while`` loops
|
|
|
|
|
|
|
|
|
|
__ http://groups.google.com/group/comp.lang.python/browse_thread/thread/6da848f762c9cf58/979ca3cd42633b52?lnk=gst&q=labeled+break&rnum=3#979ca3cd42633b52
|
2017-03-24 17:11:33 -04:00
|
|
|
|
|
2007-06-30 14:31:14 -04:00
|
|
|
|
* `break LABEL vs. exceptions + PROPOSAL`__, on python-list, as
|
|
|
|
|
compared to using Exceptions for flow control
|
|
|
|
|
|
|
|
|
|
__ http://mail.python.org/pipermail/python-list/1999-September/#11080
|
|
|
|
|
|
|
|
|
|
* `Named code blocks`__ on python-list, a suggestion motivated by the
|
|
|
|
|
desire for labeled break / continue
|
|
|
|
|
|
|
|
|
|
__ http://mail.python.org/pipermail/python-list/2001-April/#78439
|
|
|
|
|
|
|
|
|
|
* `mod_python bug fix`__ An example of someone setting a flag inside
|
|
|
|
|
an inner loop that triggers a continue in the containing loop, to
|
|
|
|
|
work around the absence of labeled break and continue
|
|
|
|
|
|
|
|
|
|
__ http://mail-archives.apache.org/mod_mbox/httpd-python-cvs/200511.mbox/%3C20051112204322.4010.qmail@minotaur.apache.org%3E
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Copyright
|
|
|
|
|
=========
|
|
|
|
|
|
|
|
|
|
This document has been placed in the public domain.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
..
|
|
|
|
|
Local Variables:
|
|
|
|
|
mode: indented-text
|
|
|
|
|
indent-tabs-mode: nil
|
|
|
|
|
sentence-end-double-space: t
|
|
|
|
|
fill-column: 70
|
|
|
|
|
coding: utf-8
|
|
|
|
|
End:
|