Topic: Have container member functions return useful data,


Author: Jeremy T <jeremy8258@gmail.com>
Date: Tue, 23 Sep 2014 14:13:49 -0700 (PDT)
Raw View
------=_Part_526_1749031692.1411506829526
Content-Type: text/plain; charset=UTF-8

Many container member functions return void instead of data or an iterator.
While this makes sense in some cases, there are others where I believe the
programmer would benefit greatly from a returned value. I intend for this
thread to be a general discussion on this topic. However, I'd like to bring
up two specific cases, namely the pop* functions, and std::list::splice().

For any example given, changing the return type would of course modify
current library headers. However, it wouldn't break any existing code, nor
should it effect run-time efficiency due to return value optimization
(RVO). Therefore, there would be minimal impact.

*I. pop**
Most of the standard containers include one or more of pop(), pop_front(),
or pop_back(). All of these functions return type void. Personally, I have
never used one of these functions without preceding it with a call to
<container>.front() or <container>.back() to first obtain the element I'm
about to pop. Therefore, I propose that all of the pop* functions have
their signatures and logic changed to

container::value_type pop*();

Notice it returns a value rather than a reference or iterator. With move
semantics, such an operation is no longer expensive, and with RVO, the copy
(or move) would be avoided altogether.

*II. Have std::[forward_]list::splice[_forward]() return an iterator*
The current signature of std::list::splice(), in its most verbose form, is

void splice (iterator position, list& x, iterator first, iterator last);

This function transfers elements in the range of [first, last) from x into
the invoking instance list *this pointed into and beginning after position.
After the function returns, all of the iterators passed as arguments are
still valid. However, the catch here is that, after the function returns,
the iterator first, which used to iterate through list x, will now iterate
through list *this. Such behavior especially can be problematic when using
this function in a while loop.

When erasing or transferring elements in a list within a loop, the while
loop is necessary so that you can increment (or decrement) the iterator
conditionally. Specifically, if you erase the element pointed at but then
also increment the iterator, you've effectively jumped two positions.
Therefore, the std::list::erase() function provides a useful return value,
namely "an iterator pointing to the element that followed the last element
erased by the function call. This is the container end if the operation
erased the last element in the sequence." This return value allows the
programmer to write code as such:

auto it = my_list.begin();
while ( it != my_list.end() ) {
  if ( condition )
    it = my_list.erase(it);
  else
    ++it;
}

Indeed, the above is the necessary method to perform such a task. Thus, I
propose that std::list::splice() return a similar value. Specifically, that
its declaration be changed to

iterator splice (iterator position, list& x, iterator first, iterator last);

with its return value being "an iterator pointing to the element that
followed the last element in x transferred by the function call. This is
the container end if the operation transferred the last element in the
sequence."

Similar functionality currently can be achieved by the following (for the
single element case):

auto it = x.begin();
while ( it != x.end() ) {
  auto tmp = it;  // here, it guaranteed not to be x.end
  ++tmp           // tmp may now be x.end
  if ( condition )
    my_list.splice( my_list.begin(), x, it );
  else
    ++it;
  it = tmp;
}

Although this code works, there are some potential mistakes that the
unaware programmer may make, all involving when the temporary iterator is
incremented. First, attempting to assign tmp as something like

  auto tmp = ++it;

will of course jump the loop iterator forward one extra position. Second,
incrementing tmp any time after the splice() operation means that tmp will
then point into and iterate through my_list instead of x.

In the case of iterating through my_list instead of x, but still
transferring elements from x to my_list, the return value would not be used
by the calling function as elements would be inserted after position, and
position would continue to iterate through my_list after the transfer.
Therefore, my three primary arguments are that the proposed change would
provide convenience to the programmer, help the programmer avoid some
potential logic errors, and provide similar functionality to
std::list::erase().

--

---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposals/.

------=_Part_526_1749031692.1411506829526
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable

<div dir=3D"ltr">Many container member functions return <span style=3D"colo=
r: rgb(0, 0, 255);">void</span> instead of data or an iterator. While this =
makes sense in some cases, there are others where I believe the programmer =
would benefit greatly from a returned value. I intend for this thread to be=
 a general discussion on this topic. However, I'd like to bring up two spec=
ific cases, namely the <span style=3D"color: rgb(0, 0, 255);">pop*</span> f=
unctions, and <span style=3D"color: rgb(0, 0, 255);">std::list::splice()</s=
pan>.<br><br>For any example given, changing the return type would of cours=
e modify current library headers. However, it wouldn't break any existing c=
ode, nor should it effect run-time efficiency due to return value optimizat=
ion (RVO). Therefore, there would be minimal impact.<br><br><b>I. pop*</b><=
br>Most of the standard containers include one or more of <span style=3D"co=
lor: rgb(0, 0, 255);">pop()</span>, <span style=3D"color: rgb(0, 0, 255);">=
pop_front()</span>, or <span style=3D"color: rgb(0, 0, 255);">pop_back()</s=
pan>. All of these functions return type <span style=3D"color: rgb(0, 0, 25=
5);">void</span>. Personally, I have never used one of these functions with=
out preceding it with a call to <span style=3D"color: rgb(0, 0, 255);">&lt;=
container&gt;.front()</span> or <span style=3D"color: rgb(0, 0, 255);">&lt;=
container&gt;.back()</span> to first obtain the element I'm about to pop. T=
herefore, I propose that all of the <span style=3D"color: rgb(0, 0, 255);">=
pop*</span> functions have their signatures and logic changed to<br><br><di=
v class=3D"prettyprint" style=3D"background-color: rgb(250, 250, 250); bord=
er-color: rgb(187, 187, 187); border-style: solid; border-width: 1px; word-=
wrap: break-word;"><code class=3D"prettyprint"><div class=3D"subprettyprint=
"><span style=3D"color: #000;" class=3D"styled-by-prettify">container</span=
><span style=3D"color: #660;" class=3D"styled-by-prettify">::</span><span s=
tyle=3D"color: #000;" class=3D"styled-by-prettify">value_type pop</span><sp=
an style=3D"color: #660;" class=3D"styled-by-prettify">*();</span><span sty=
le=3D"color: #000;" class=3D"styled-by-prettify"><br></span></div></code></=
div><br>Notice it returns a value rather than a reference or iterator. With=
 move semantics, such an operation is no longer expensive, and with RVO, th=
e copy (or move) would be avoided altogether.<br><br><b>II. Have std::[forw=
ard_]list::splice[_forward]() return an iterator</b><br>The current signatu=
re of <span style=3D"color: rgb(0, 0, 255);">std::list::splice()</span>, in=
 its most verbose form, is<br><br><div class=3D"prettyprint" style=3D"backg=
round-color: rgb(250, 250, 250); border-color: rgb(187, 187, 187); border-s=
tyle: solid; border-width: 1px; word-wrap: break-word;"><code class=3D"pret=
typrint"><div class=3D"subprettyprint"><span style=3D"color: #008;" class=
=3D"styled-by-prettify">void</span><span style=3D"color: #000;" class=3D"st=
yled-by-prettify"> splice </span><span style=3D"color: #660;" class=3D"styl=
ed-by-prettify">(</span><span style=3D"color: #000;" class=3D"styled-by-pre=
ttify">iterator position</span><span style=3D"color: #660;" class=3D"styled=
-by-prettify">,</span><span style=3D"color: #000;" class=3D"styled-by-prett=
ify"> list</span><span style=3D"color: #660;" class=3D"styled-by-prettify">=
&amp;</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> x</s=
pan><span style=3D"color: #660;" class=3D"styled-by-prettify">,</span><span=
 style=3D"color: #000;" class=3D"styled-by-prettify"> iterator first</span>=
<span style=3D"color: #660;" class=3D"styled-by-prettify">,</span><span sty=
le=3D"color: #000;" class=3D"styled-by-prettify"> iterator </span><span sty=
le=3D"color: #008;" class=3D"styled-by-prettify">last</span><span style=3D"=
color: #660;" class=3D"styled-by-prettify">);</span></div></code></div><br>=
This function transfers elements in the range of [<span style=3D"color: rgb=
(0, 0, 255);">first</span>, <span style=3D"color: rgb(0, 0, 255);">last</sp=
an>) from <span style=3D"color: rgb(0, 0, 255);">x</span> into the invoking=
 instance list <span style=3D"color: rgb(0, 0, 255);">*this</span> pointed =
into and beginning after <span style=3D"color: rgb(0, 0, 255);">position</s=
pan>. After the function returns, all of the iterators passed as arguments =
are still valid. However, the catch here is that, after the function return=
s, the iterator <span style=3D"color: rgb(0, 0, 255);">first</span>, which =
used to iterate through list <span style=3D"color: rgb(0, 0, 255);">x</span=
>, will now iterate through list <span style=3D"color: rgb(0, 0, 255);">*th=
is</span>. Such behavior especially can be problematic when using this func=
tion in a while loop.<br><br>When erasing or transferring elements in a lis=
t within a loop, the while loop is necessary so that you can increment (or =
decrement) the iterator conditionally. Specifically, if you erase the eleme=
nt pointed at but then also increment the iterator, you've effectively jump=
ed two positions. Therefore, the <span style=3D"color: rgb(0, 0, 255);">std=
::list::erase()</span> function provides a useful return value, namely "an =
iterator pointing to the element that followed the last element erased by t=
he function call. This is the container end if the operation erased the las=
t element in the sequence." This return value allows the programmer to writ=
e code as such:<br><br><div class=3D"prettyprint" style=3D"background-color=
: rgb(250, 250, 250); border-color: rgb(187, 187, 187); border-style: solid=
; border-width: 1px; word-wrap: break-word;"><code class=3D"prettyprint"><d=
iv class=3D"subprettyprint"><span style=3D"color: #008;" class=3D"styled-by=
-prettify">auto</span><span style=3D"color: #000;" class=3D"styled-by-prett=
ify"> it </span><span style=3D"color: #660;" class=3D"styled-by-prettify">=
=3D</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> my_lis=
t</span><span style=3D"color: #660;" class=3D"styled-by-prettify">.</span><=
span style=3D"color: #008;" class=3D"styled-by-prettify">begin</span><span =
style=3D"color: #660;" class=3D"styled-by-prettify">();</span><span style=
=3D"color: #000;" class=3D"styled-by-prettify"><br></span><span style=3D"co=
lor: #008;" class=3D"styled-by-prettify">while</span><span style=3D"color: =
#000;" class=3D"styled-by-prettify"> </span><span style=3D"color: #660;" cl=
ass=3D"styled-by-prettify">(</span><span style=3D"color: #000;" class=3D"st=
yled-by-prettify"> it </span><span style=3D"color: #660;" class=3D"styled-b=
y-prettify">!=3D</span><span style=3D"color: #000;" class=3D"styled-by-pret=
tify"> my_list</span><span style=3D"color: #660;" class=3D"styled-by-pretti=
fy">.</span><span style=3D"color: #008;" class=3D"styled-by-prettify">end</=
span><span style=3D"color: #660;" class=3D"styled-by-prettify">()</span><sp=
an style=3D"color: #000;" class=3D"styled-by-prettify"> </span><span style=
=3D"color: #660;" class=3D"styled-by-prettify">)</span><span style=3D"color=
: #000;" class=3D"styled-by-prettify"> </span><span style=3D"color: #660;" =
class=3D"styled-by-prettify">{</span><span style=3D"color: #000;" class=3D"=
styled-by-prettify"><br>&nbsp; </span><span style=3D"color: #008;" class=3D=
"styled-by-prettify">if</span><span style=3D"color: #000;" class=3D"styled-=
by-prettify"> </span><span style=3D"color: #660;" class=3D"styled-by-pretti=
fy">(</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> cond=
ition </span><span style=3D"color: #660;" class=3D"styled-by-prettify">)</s=
pan><span style=3D"color: #000;" class=3D"styled-by-prettify"><br>&nbsp; &n=
bsp; it </span><span style=3D"color: #660;" class=3D"styled-by-prettify">=
=3D</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> my_lis=
t</span><span style=3D"color: #660;" class=3D"styled-by-prettify">.</span><=
span style=3D"color: #000;" class=3D"styled-by-prettify">erase</span><span =
style=3D"color: #660;" class=3D"styled-by-prettify">(</span><span style=3D"=
color: #000;" class=3D"styled-by-prettify">it</span><span style=3D"color: #=
660;" class=3D"styled-by-prettify">);</span><span style=3D"color: #000;" cl=
ass=3D"styled-by-prettify"><br>&nbsp; </span><span style=3D"color: #008;" c=
lass=3D"styled-by-prettify">else</span><span style=3D"color: #000;" class=
=3D"styled-by-prettify"><br>&nbsp; &nbsp; </span><span style=3D"color: #660=
;" class=3D"styled-by-prettify">++</span><span style=3D"color: #000;" class=
=3D"styled-by-prettify">it</span><span style=3D"color: #660;" class=3D"styl=
ed-by-prettify">;</span><span style=3D"color: #000;" class=3D"styled-by-pre=
ttify"><br></span><span style=3D"color: #660;" class=3D"styled-by-prettify"=
>}</span><span style=3D"color: #000;" class=3D"styled-by-prettify"><br></sp=
an></div></code></div><br>Indeed, the above is the necessary method to perf=
orm such a task. Thus, I propose that <span style=3D"color: rgb(0, 0, 255);=
">std::list::splice()</span> return a similar value. Specifically, that its=
 declaration be changed to<br><br><div class=3D"prettyprint" style=3D"backg=
round-color: rgb(250, 250, 250); border-color: rgb(187, 187, 187); border-s=
tyle: solid; border-width: 1px; word-wrap: break-word;"><code class=3D"pret=
typrint"><div class=3D"subprettyprint"><span style=3D"color: #000;" class=
=3D"styled-by-prettify">iterator splice </span><span style=3D"color: #660;"=
 class=3D"styled-by-prettify">(</span><span style=3D"color: #000;" class=3D=
"styled-by-prettify">iterator position</span><span style=3D"color: #660;" c=
lass=3D"styled-by-prettify">,</span><span style=3D"color: #000;" class=3D"s=
tyled-by-prettify"> list</span><span style=3D"color: #660;" class=3D"styled=
-by-prettify">&amp;</span><span style=3D"color: #000;" class=3D"styled-by-p=
rettify"> x</span><span style=3D"color: #660;" class=3D"styled-by-prettify"=
>,</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> iterato=
r first</span><span style=3D"color: #660;" class=3D"styled-by-prettify">,</=
span><span style=3D"color: #000;" class=3D"styled-by-prettify"> iterator </=
span><span style=3D"color: #008;" class=3D"styled-by-prettify">last</span><=
span style=3D"color: #660;" class=3D"styled-by-prettify">);</span><span sty=
le=3D"color: #000;" class=3D"styled-by-prettify"><br></span></div></code></=
div><br>with its return value being "an iterator pointing to the element th=
at followed the last element <span style=3D"color: rgb(0, 0, 255);">in x</s=
pan> transferred by the function call. This is the container end if the ope=
ration transferred the last element in the sequence."<br><br>Similar functi=
onality currently can be achieved by the following (for the single element =
case):<br><br><div class=3D"prettyprint" style=3D"background-color: rgb(250=
, 250, 250); border-color: rgb(187, 187, 187); border-style: solid; border-=
width: 1px; word-wrap: break-word;"><code class=3D"prettyprint"><div class=
=3D"subprettyprint"><span style=3D"color: #008;" class=3D"styled-by-prettif=
y">auto</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> it=
 </span><span style=3D"color: #660;" class=3D"styled-by-prettify">=3D</span=
><span style=3D"color: #000;" class=3D"styled-by-prettify"> x</span><span s=
tyle=3D"color: #660;" class=3D"styled-by-prettify">.</span><span style=3D"c=
olor: #008;" class=3D"styled-by-prettify">begin</span><span style=3D"color:=
 #660;" class=3D"styled-by-prettify">();</span><span style=3D"color: #000;"=
 class=3D"styled-by-prettify"><br></span><span style=3D"color: #008;" class=
=3D"styled-by-prettify">while</span><span style=3D"color: #000;" class=3D"s=
tyled-by-prettify"> </span><span style=3D"color: #660;" class=3D"styled-by-=
prettify">(</span><span style=3D"color: #000;" class=3D"styled-by-prettify"=
> it </span><span style=3D"color: #660;" class=3D"styled-by-prettify">!=3D<=
/span><span style=3D"color: #000;" class=3D"styled-by-prettify"> x</span><s=
pan style=3D"color: #660;" class=3D"styled-by-prettify">.</span><span style=
=3D"color: #008;" class=3D"styled-by-prettify">end</span><span style=3D"col=
or: #660;" class=3D"styled-by-prettify">()</span><span style=3D"color: #000=
;" class=3D"styled-by-prettify"> </span><span style=3D"color: #660;" class=
=3D"styled-by-prettify">)</span><span style=3D"color: #000;" class=3D"style=
d-by-prettify"> </span><span style=3D"color: #660;" class=3D"styled-by-pret=
tify">{</span><span style=3D"color: #000;" class=3D"styled-by-prettify"><br=
>&nbsp; </span><span style=3D"color: #008;" class=3D"styled-by-prettify">au=
to</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> tmp </s=
pan><span style=3D"color: #660;" class=3D"styled-by-prettify">=3D</span><sp=
an style=3D"color: #000;" class=3D"styled-by-prettify"> it</span><span styl=
e=3D"color: #660;" class=3D"styled-by-prettify">;</span><span style=3D"colo=
r: #000;" class=3D"styled-by-prettify"> &nbsp;</span><span style=3D"color: =
#800;" class=3D"styled-by-prettify">// here, it guaranteed not to be x.end<=
/span><span style=3D"color: #000;" class=3D"styled-by-prettify"><br>&nbsp; =
</span><span style=3D"color: #660;" class=3D"styled-by-prettify">++</span><=
span style=3D"color: #000;" class=3D"styled-by-prettify">tmp &nbsp; &nbsp; =
&nbsp; &nbsp; &nbsp; </span><span style=3D"color: #800;" class=3D"styled-by=
-prettify">// tmp may now be x.end</span><span style=3D"color: #000;" class=
=3D"styled-by-prettify"><br>&nbsp; </span><span style=3D"color: #008;" clas=
s=3D"styled-by-prettify">if</span><span style=3D"color: #000;" class=3D"sty=
led-by-prettify"> </span><span style=3D"color: #660;" class=3D"styled-by-pr=
ettify">(</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> =
condition </span><span style=3D"color: #660;" class=3D"styled-by-prettify">=
)</span><span style=3D"color: #000;" class=3D"styled-by-prettify"><br>&nbsp=
; &nbsp; my_list</span><span style=3D"color: #660;" class=3D"styled-by-pret=
tify">.</span><span style=3D"color: #000;" class=3D"styled-by-prettify">spl=
ice</span><span style=3D"color: #660;" class=3D"styled-by-prettify">(</span=
><span style=3D"color: #000;" class=3D"styled-by-prettify"> my_list</span><=
span style=3D"color: #660;" class=3D"styled-by-prettify">.</span><span styl=
e=3D"color: #008;" class=3D"styled-by-prettify">begin</span><span style=3D"=
color: #660;" class=3D"styled-by-prettify">(),</span><span style=3D"color: =
#000;" class=3D"styled-by-prettify"> x</span><span style=3D"color: #660;" c=
lass=3D"styled-by-prettify">,</span><span style=3D"color: #000;" class=3D"s=
tyled-by-prettify"> it </span><span style=3D"color: #660;" class=3D"styled-=
by-prettify">);</span><span style=3D"color: #000;" class=3D"styled-by-prett=
ify"><br>&nbsp; </span><span style=3D"color: #008;" class=3D"styled-by-pret=
tify">else</span><span style=3D"color: #000;" class=3D"styled-by-prettify">=
<br>&nbsp; &nbsp; </span><span style=3D"color: #660;" class=3D"styled-by-pr=
ettify">++</span><span style=3D"color: #000;" class=3D"styled-by-prettify">=
it</span><span style=3D"color: #660;" class=3D"styled-by-prettify">;</span>=
<span style=3D"color: #000;" class=3D"styled-by-prettify"><br>&nbsp; it </s=
pan><span style=3D"color: #660;" class=3D"styled-by-prettify">=3D</span><sp=
an style=3D"color: #000;" class=3D"styled-by-prettify"> tmp</span><span sty=
le=3D"color: #660;" class=3D"styled-by-prettify">;</span><span style=3D"col=
or: #000;" class=3D"styled-by-prettify"><br></span><span style=3D"color: #6=
60;" class=3D"styled-by-prettify">}</span><span style=3D"color: #000;" clas=
s=3D"styled-by-prettify"><br></span></div></code></div><br>Although this co=
de works, there are some potential mistakes that the unaware programmer may=
 make, all involving when the temporary iterator is incremented. First, att=
empting to assign <span style=3D"color: rgb(0, 0, 255);">tmp</span> as some=
thing like<br><br><div class=3D"prettyprint" style=3D"background-color: rgb=
(250, 250, 250); border-color: rgb(187, 187, 187); border-style: solid; bor=
der-width: 1px; word-wrap: break-word;"><code class=3D"prettyprint"><div cl=
ass=3D"subprettyprint"><span style=3D"color: #000;" class=3D"styled-by-pret=
tify">&nbsp; </span><span style=3D"color: #008;" class=3D"styled-by-prettif=
y">auto</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> tm=
p </span><span style=3D"color: #660;" class=3D"styled-by-prettify">=3D</spa=
n><span style=3D"color: #000;" class=3D"styled-by-prettify"> </span><span s=
tyle=3D"color: #660;" class=3D"styled-by-prettify">++</span><span style=3D"=
color: #000;" class=3D"styled-by-prettify">it</span><span style=3D"color: #=
660;" class=3D"styled-by-prettify">;</span><span style=3D"color: #000;" cla=
ss=3D"styled-by-prettify"><br></span></div></code></div><br>will of course =
jump the loop iterator forward one extra position. Second, incrementing <sp=
an style=3D"color: rgb(0, 0, 255);">tmp</span> any time after the <span sty=
le=3D"color: rgb(0, 0, 255);">splice()</span> operation means that <span st=
yle=3D"color: rgb(0, 0, 255);">tmp</span> will then point into and iterate =
through <span style=3D"color: rgb(0, 0, 255);">my_list</span> instead of <s=
pan style=3D"color: rgb(0, 0, 255);">x</span>.<br><br>In the case of iterat=
ing through <span style=3D"color: rgb(0, 0, 255);">my_list</span> instead o=
f <span style=3D"color: rgb(0, 0, 255);">x</span>, but still transferring e=
lements from <span style=3D"color: rgb(0, 0, 255);">x</span> to <span style=
=3D"color: rgb(0, 0, 255);">my_list</span>, the return value would not be u=
sed by the calling function as elements would be inserted after <span style=
=3D"color: rgb(0, 0, 255);">position</span>, and <span style=3D"color: rgb(=
0, 0, 255);">position</span> would continue to iterate through <span style=
=3D"color: rgb(0, 0, 255);">my_list</span> after the transfer. Therefore, m=
y three primary arguments are that the proposed change would provide conven=
ience to the programmer, help the programmer avoid some potential logic err=
ors, and provide similar functionality to <span style=3D"color: rgb(0, 0, 2=
55);">std::list::erase()</span>.<br></div>

<p></p>

-- <br />
<br />
--- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals&quot; group.<br />
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to <a href=3D"mailto:std-proposals+unsubscribe@isocpp.org">std-proposa=
ls+unsubscribe@isocpp.org</a>.<br />
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org">std-proposals@isocpp.org</a>.<br />
Visit this group at <a href=3D"http://groups.google.com/a/isocpp.org/group/=
std-proposals/">http://groups.google.com/a/isocpp.org/group/std-proposals/<=
/a>.<br />

------=_Part_526_1749031692.1411506829526--

.