    <rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:sy="http://purl.org/rss/1.0/modules/syndication/" xmlns:admin="http://webns.net/mvcb/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:content="http://purl.org/rss/1.0/modules/content/">
     <channel>
        <title>ACCU  :: Functional Error-Handling with Optional and Expected</title>
        <link>https://members.accu.org/index.php/articles/2462</link>
        <description>Professionalism in Programming</description>
        <dc:language>en-us</dc:language> 
        <dc:creator>Administrator</dc:creator> 
        <admin:generatorAgent rdf:resource="http://www.xaraya.org" /> 
        <admin:errorReportsTo rdf:resource="mailto:webeditor@accu.org" />
       <sy:updatePeriod>hourly</sy:updatePeriod>
       <sy:updateFrequency>1</sy:updateFrequency>
       <docs>http://backend.userland.com/rss</docs>




<div class="xar-mod-head"><span class="xar-mod-title">Programming Topics + Overload Journal #143 - February 2018</span></div>

<table border="0" cellpadding="1" cellspacing="0">
    <tbody>
    <tr>
        <td valign="top">
            Browse in :
       </td>
       <td valign="top">

                                            <a href="https://members.accu.org/index.php/articles/">All</a>

                     &gt;                         <a href="https://members.accu.org/index.php/articles/c13/">Topics</a>

                     &gt;                         <a href="https://members.accu.org/index.php/articles/c65/">Programming</a>
<br />

                                            <a href="https://members.accu.org/index.php/articles/">All</a>

                     &gt;                         <a href="https://members.accu.org/index.php/articles/c76/">Journals</a>

                     &gt;                         <a href="https://members.accu.org/index.php/articles/c78/">Overload</a>

                     &gt;                         <a href="https://members.accu.org/index.php/articles/c382/">o143</a>
<br />

                                            <a href="https://members.accu.org/index.php/articles/c65-382/">Any of these categories</a>

                    -                        <a href="https://members.accu.org/index.php/articles/c65+382/">All of these categories</a>
<br />
</td>
   </tr>
   </tbody>
</table>




<div class="xar-error">
   <p>
 <strong>Note:</strong> when you create a new publication type,
the articles module will automatically use the templates
<em>user-display-[publicationtype].xt</em>
and <em>user-summary-[publicationtype].xt</em>.
If those templates do not exist when you try to preview or display a new article,
you'll get this warning :-)  Please place your own templates in themes/<em>yourtheme</em>/modules/articles . The templates will get the extension .xt there. </p>
</div>
<div class="xar-norm xar-standard-box-padding">
   <h1><strong>Title:</strong>&nbsp;Functional Error-Handling with Optional and Expected</h1>
<p><strong>Author:</strong>&nbsp;Bob Schmidt</p>
<p>
<strong>Date:</strong> 02 February 2018 16:17:18 +00:00 or Fri, 02 February 2018 16:17:18 +00:00</p>
<p><strong>Summary:</strong>&nbsp;Exceptions should be exceptional. Simon Brand shows modern alternatives from the standard library and ways to improve them.</p>
<p><strong>Body:</strong>&nbsp;<p>In software, things can go wrong. Sometimes we might expect them to go wrong. Sometimes itâ€™s a surprise. In most cases we want to build in some way of handling these misfortunes. Letâ€™s call them disappointments [<a href="#[Crowl15]">Crowl15</a>]. Iâ€™m going to exhibit how to use <code>std::optional</code> and the proposed <code>std::expected</code> to handle disappointments, and show how the types can be extended with concepts from functional programming to make the handling concise and expressive.</p>

<p>One way to express and handle disappointments is exceptions:</p>

<pre class="programlisting">
  void foo() {
    try {
      do_thing();
    }
      catch (...) {
        //oh no
      handle_error();
    }
  }</pre>
  
<p>There are a myriad of discussions, resources, rants, tirades, debates about the value of exceptions [<a href="#[Douglas17]">Douglas17</a>] [<a href="#[Halder16]">Halder16</a>] [<a href="#[Kirk15] )">Kirk15</a>] [<a href="#[MusingMortoray12] )">MusingMortoray12</a>] [<a href="#[Stackoverflow]">Stackoverflow</a>], and I will not repeat them here. Suffice to say that there are cases in which exceptions are not the best tool for the job. For the sake of being uncontroversial, Iâ€™ll take the example of disappointments which are expected within reasonable use of an API.</p>

<table class="sidebartable">
	<tr>
		<td class="title">Improvements upon improvements</td>
	</tr>
	<tr>
		<td>
			<table class="journaltable">
				<tr>
					<td>
						<p>As C++ programmers, weâ€™re constantly finding new ways to leverage the power of the language to make expressive libraries, thus improving the quality of the code we write day to day. Letâ€™s apply this to <code>std::optional</code> and <code>std::expected</code>. They deserve it.</p>
						<p>With these two functions, weâ€™ve successfully pushed the error handling off to the side, allowing us to express a series of operations which may fail without interrupting the flow of logic to test an optional.</p>
					</td>
				</tr>
			</table>
		</td>
	</tr>
</table>

<p>The internet loves cats. The hypothetical you and I are involved in the business of producing the cutest images of cats the world has ever seen. We have produced a high-quality C++ library geared towards this sole aim, and we want it to be at the bleeding edge of modern C++.</p>

<p>A common operation in feline cutification programs is to locate cats in a given image. How should we express this in our API? One option is exceptions:</p>

<pre class="programlisting">
  // Throws no_cat_found if a cat is not found.
  image_view find_cat (image_view img);</pre>
  
<p>This function takes a view of an image and returns a smaller view which contains the first cat it finds. If it does not find a cat, then it throws an exception. If weâ€™re going to be giving this function a million images, half of which do not contain cats, then thatâ€™s a lot of exceptions being thrown. In fact, weâ€™re pretty much using exceptions for control flow at that point, which is A Bad Thingâ„¢ [<a href="#[Stroustrup18]">Stroustrup18</a>].</p>

<p>What we really want to express is a function which either returns a cat if it finds one, or it returns nothing. Enter <code>std::optional</code>.</p>

<pre class="programlisting">
  std::optional&lt;image_view&gt; find_cat
    (image_view img);</pre>

<p><code>std::optional</code> was introduced in C++17 [<a href="#[cppreference]">cppreference</a>] for representing a value which may or may not be present. It is intended to be a vocabulary type â€“ i.e. the canonical choice for expressing some concept in your code. The difference between this signature and the last is powerful; weâ€™ve moved the description of what happens on an error from the documentation into the type system. Now itâ€™s impossible for the user to forget to read the docs, because the compiler is reading them for us, and you can be sure that itâ€™ll shout at you if you use the type incorrectly.</p>

<p>The most common operations on a <code>std::optional</code> are shown in Listing 1.</p>

<table class="sidebartable">
	<tr>
		<td>
			<pre class="programlisting">
std::optional&lt;image_view&gt; full_view = my_view;
std::optional&lt;image_view&gt; empty_view;
std::optional&lt;image_view&gt; another_empty_view 
  = std::nullopt;
full_view.has_value();  //true
empty_view.has_value(); //false
if (full_view) { this_works(); }
my_view = full_view.value();
my_view = *full_view;
my_view = empty_view.value(); //throws bad_optional_access
my_view = *empty_view; //undefined behaviour
			</pre>
		</td>
	</tr>
	<tr>
		<td class="title">Listing 1</td>
	</tr>
</table>

<p>Now weâ€™re ready to use our <code>find_cat</code> function along with some other friends from our library to make embarrassingly adorable pictures of cats (see Listing 2).</p>

<table class="sidebartable">
	<tr>
		<td>
			<pre class="programlisting">
std::optional&lt;image_view&gt; get_cute_cat (image_view img) {
    auto cropped = find_cat(img);
    if (!cropped) {
      return std::nullopt;
    }
    auto with_tie = add_bow_tie(*cropped);
    if (!with_tie) {
      return std::nullopt;
    }
    auto with_sparkles =
      make_eyes_sparkle(*with_tie);
    if (!with_sparkles) {
      return std::nullopt;
    }
    return
      add_rainbow(make_smaller(*with_sparkles));
}
			</pre>
		</td>
	</tr>
	<tr>
		<td class="title">Listing 2</td>
	</tr>
</table>

<p>Well this isâ€¦ okay. The user is made to explicitly handle what happens in case of an error, so they canâ€™t forget about it, which is good. But there are two issues with this:</p>

<ol>
	<li>Thereâ€™s no information about why the operations failed.</li>
	<li>Thereâ€™s too much noise; error handling dominates the logic of the code.</li>
</ol>

<p>Iâ€™ll address these two points in turn.</p>

<h2>Why did something fail?</h2>

<p><code>std::optional</code> is great for expressing that some operation produced no value, but it gives us no information to help us understand why this occurred; weâ€™re left to use whatever context we have available, or (God forbid) output parameters. What we want is a type which either contains a value, or contains some information about why the value isnâ€™t there. This is called <code>std::expected</code>.</p>

<p>Now donâ€™t go rushing off to cppreference to find out about <code>std::expected</code>; you wonâ€™t find it there yet, because itâ€™s currently a standards proposal [<a href="#[P0323r3]">P0323r3</a>] rather than a part of C++ proper. However, its interface follows <code>std::optional</code> pretty closely, so you already understand most of it. Listing 3 shows the most common operations.</p>

<table class="sidebartable">
	<tr>
		<td>
			<pre class="programlisting">
std::expected&lt;image_view,error_code&gt; full_view =
  my_view;
std::expected&lt;image_view,error_code&gt; empty_view =
  std::unexpected(that_is_a_dog);
full_view.has_value();  //true
empty_view.has_value(); //false
if (full_view) { this_works(); }
my_view = full_view.value();
my_view = *full_view;
my_view = empty_view.value(); //throws bad_expected_access
my_view = *empty_view; //undefined behaviour
auto code = empty_view.error();
auto oh_no = full_view.error(); //undefined
                                //behaviour
			</pre>
		</td>
	</tr>
	<tr>
		<td class="title">Listing 3</td>
	</tr>
</table>

<p>With <code>std::expected</code> our code might look like Listing 4.</p>

<table class="sidebartable">
	<tr>
		<td>
			<pre class="programlisting">
std::expected&lt;image_view, error_code&gt;
  get_cute_cat (image_view img) {
    auto cropped = find_cat(img);p
    if (!cropped) {
      return no_cat_found;
    }
    auto with_tie = add_bow_tie(*cropped);
    if (!with_tie) {
      return cannot_see_neck;
    }
    auto with_sparkles =
      make_eyes_sparkle(*with_tie);
    if (!with_sparkles) {
      return cat_has_eyes_shut;
    }
    return
      add_rainbow(make_smaller(*with_sparkles));
}
			</pre>
		</td>
	</tr>
	<tr>
		<td class="title">Listing 4</td>
	</tr>
</table>

<p>Now when we call <code>get_cute_cat</code> and donâ€™t get a lovely image back, we have some useful information to report to the user as to why we got into this situation.</p>

<h2>Noisy error handling</h2>

<p>Unfortunately, with both the <code>std::optional</code> and <code>std::expected</code> versions, thereâ€™s still a lot of noise. This is a disappointing solution to handling disappointments. Itâ€™s also the limit of what C++17â€™s <code>std::optional</code> and the most recent proposed <code>std::expected</code> give us.</p>

<p>What we really want is a way to express the operations we want to carry out while pushing the disappointment handling off to the side. As is becoming increasingly trendy in the world of C++, weâ€™ll look to the world of functional programming for help. In this case, the help comes in the form of what Iâ€™ll call <code>map</code> and <code>and_then</code>.</p>

<p>If we have some <code>std::optional</code> and we want to carry out some operation on it if and only if thereâ€™s a value stored, then we can use <code>map</code>:</p>

<pre class="programlisting">
  widget do_thing (const widget&amp;);
  std::optional&lt;widget&gt; result =
    maybe_get_widget().map(do_thing);
  auto result = maybe_get_widget().map(do_thing); 
    //or with auto</pre>
	
<p>This code is roughly equivalent to:</p>

<pre class="programlisting">
  widget do_thing (const widget&amp;);
  auto opt_widget = maybe_get_widget();
  if (opt_widget) {
    widget result = do_thing(*opt_widget);
  }</pre>
  
<p>If we want to carry out some operation which could itself fail then we can use <code>and_then</code>:</p>

<pre class="programlisting">
  std::optional&lt;widget&gt; maybe_do_thing 
    (const widget&amp;);
  std::optional&lt;widget&gt; result =
    maybe_get_widget().and_then(maybe_do_thing);
  auto result =
    maybe_get_widget().and_then(maybe_do_thing); 
      //or with auto</pre>
	  
<p>This code is roughly equivalent to:</p>

<pre class="programlisting">
  std::optional&lt;widget&gt; maybe_do_thing 
    (const widget&amp;);
  auto opt_widget = maybe_get_widget();
  if (opt_widget) {
    std::optional&lt;widget&gt; result =
      maybe_do_thing(*opt_widget);
  }</pre>
  
<p><code>and_then</code> and <code>map</code> for <code>expected</code> acts in much the same way an for <code>optional</code>: if there is an expected value then the given function will be called with that value, otherwise the stored unexpected value will be returned. Additionally, we could add a <code>map_error</code> function which allows mapping functions over unexpected values.</p>

<p>The real power of these functions comes when we begin to chain operations together. Letâ€™s look at that original <code>get_cute_cat</code> implementation again in Listing 2.</p>

<p>With map and <code>and_then</code>, our code transforms into this:</p>

<pre class="programlisting">
  tl::optional&lt;image_view&gt; get_cute_cat 
    (image_view img) {
      return crop_to_cat(img)
        .and_then(add_bow_tie)
        .and_then(make_eyes_sparkle)
        .map(make_smaller)
        .map(add_rainbow);
  }</pre>
  
<p>With these two functions weâ€™ve successfully pushed the error handling off to the side, allowing us to express a series of operations which may fail without interrupting the flow of logic to test an <code>optional</code>. For more discussion about this code and the equivalent exception-based code, Iâ€™d recommend reading Vittorio Romeoâ€™s â€˜Why choose sum types over exceptions?â€™ article [<a href="#[Romeo17]">Romeo17</a>].</p>

<h2>A theoretical aside</h2>

<p>I didnâ€™t make up <code>map</code> and <code>and_then</code> off the top of my head; other languages have had equivalent features for a long time, and the theoretical concepts are common subjects in Category Theory [<a href="#[Milewski14]">Milewski14</a>].</p>

<p>I wonâ€™t attempt to explain all the relevant concepts in this post, as others have done it far better than I could. The basic idea is that <code>map</code> comes from the concept of a <em>functor</em>, and <code>and_then</code> comes from <em>monads</em>. These two functions are called <code>fmap</code> and <code>&gt;&gt;=</code> (bind) in Haskell. The best description of these concepts which I have read is â€˜Functors, Applicativesâ€™ And Monads In Picturesâ€™ by Aditya Bhargava [<a href="#[Bhargava13]">Bhargava13</a>]. Give it a read if youâ€™d like to learn more about these ideas.</p>

<h2>A note on overload sets</h2>

<p>One use-case which is annoyingly verbose is passing overloaded functions to <code>map</code> or <code>and_then</code>. For example:</p>

<pre class="programlisting">
  int foo (int);
  tl::optional&lt;int&gt; o;
  o.map(foo);</pre>
  
<p>The above code works fine. But as soon as we add another overload to <code>foo</code>:</p>

<pre class="programlisting">
  int foo (int);
  int foo (double);
  tl::optional&lt;int&gt; o;
  o.map(foo);</pre>
  
<p>then it fails to compile, complaining that template arguments couldnâ€™t be inferred.</p>

<p>One solution for this is to use a generic lambda:</p>

<pre class="programlisting">
  tl::optional&lt;int&gt; o;
  o.map([](auto x){return foo(x);});</pre>
  
<p>Another is a <code>LIFT</code> macro:</p>

<pre class="programlisting">
  #define FWD(...) \
   std::forward&lt;decltype(__VA_ARGS__)&gt;(__VA_ARGS__)
  #define LIFT(f) [](auto&amp;&amp;... xs) \
   noexcept(noexcept(f(FWD(xs)...))) -&gt; \
   decltype(f(FWD(xs)...)) \
   { return f(FWD(xs)...); }
  tl::optional&lt;int&gt; o;
  o.map(LIFT(foo));</pre>
  
<p>Personally I hope to see overload set lifting get into the standard so that we donâ€™t need to bother with the above solutions.</p>

<h2>Current status</h2>

<p>Maybe Iâ€™ve persuaded you that these extensions to <code>std::optional</code> and <code>std::expected</code> are useful and you would like to use them in your code. Fortunately I have written implementations of both with the extensions shown in this post, among others. <code>tl::optional</code> [<a href="#[GH1]">GH1</a>] and <code>tl::expected</code> [<a href="#[GH2]">GH2</a>] are on GitHub as single-header libraries under the CC0 [<a href="#[CC]">CC</a>] license, so they should be easy to integrate with projects new and old.</p>

<p>As far as the standard goes, there are a few avenues being entertained for adding this functionality. I have a proposal [<a href="#[P0798r0]">P0798r0</a>] to extend <code>std::optional</code> with new member functions. Vicente EscribÃ¡ has a proposal [<a href="#[P0650r1]">P0650r1</a>] for a generalised monadic interface for C++. Niall Douglasâ€™ <code>operator try()</code> paper [<a href="#[P0779r0]">P0779r0</a>] suggests an analogue to Rustâ€™s try! macro [<a href="#[Rust]">Rust</a>] for removing some of the boilerplate associated with this style of programming. It turns out that you can use coroutines  [<a href="#[GH3]">GH3</a>] for doing this stuff, although my gut feeling puts this more to the â€˜abuseâ€™ end of the spectrum. Iâ€™d also be interested in evaluating how Ranges [<a href="#[N4685]">N4685</a>] could be leveraged for these goals.</p>

<p>Ultimately I donâ€™t care how we achieve this as a community so long as we have some standardised solution available. As C++ programmers weâ€™re constantly finding new ways to leverage the power of the language to make expressive libraries, thus improving the quality of the code we write day to day. Letâ€™s apply this to <code>std::optional</code> and <code>std::expected</code>. They deserve it.</p>

<h2>References</h2>

<p class="bibliomixed"><a id="[Bhargava13]"></a>[Bhargava13] <a href="http://adit.io/posts/2013-04-17-functors,_applicatives,_and_monads_in_pictures.html">http://adit.io/posts/2013-04-17-functors,_applicatives,_and_monads_in_pictures.html</a></p>

<p class="bibliomixed"><a id="[CC]"></a>[CC] <a href="https://creativecommons.org/share-your-work/public-domain/cc0/">https://creativecommons.org/share-your-work/public-domain/cc0/</a></p>

<p class="bibliomixed"><a id="[cppreference]"></a>[cppreference] <a href="http://en.cppreference.com/w/cpp/utility/optional">http://en.cppreference.com/w/cpp/utility/optional</a></p>

<p class="bibliomixed"><a id="[Crowl15]"></a>[Crowl15] <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p0157r0.html">http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p0157r0.html</a></p>

<p class="bibliomixed"><a id="[Douglas17]"></a>[Douglas17] Niall Douglas (2017) â€˜Mongrel Monads, Dirty, Dirty, Dirtyâ€™, ACCU 2017: <a href="https://www.youtube.com/watch?v=XVofgKH-uu4">https://www.youtube.com/watch?v=XVofgKH-uu4</a></p>

<p class="bibliomixed"><a id="[GH1]"></a>[GH1] <a href="https://github.com/TartanLlama/optional">https://github.com/TartanLlama/optional</a></p>

<p class="bibliomixed"><a id="[GH2]"></a>[GH2] <a href="https://github.com/TartanLlama/expected">https://github.com/TartanLlama/expected</a></p>

<p class="bibliomixed"><a id="[GH3]"></a>[GH3] <a href="https://github.com/toby-allsopp/coroutine_monad">https://github.com/toby-allsopp/coroutine_monad</a></p>

<p class="bibliomixed"><a id="[Halder16]"></a>[Halder16] Deb Haldar (2016) â€˜Top 15 C++ Exception handling mistakes and how to avoid themâ€™ <a href="http://www.acodersjourney.com/2016/08/top-15-c-exception-handling-mistakes-avoid/">http://www.acodersjourney.com/2016/08/top-15-c-exception-handling-mistakes-avoid/</a></p>

<p class="bibliomixed"><a id="[Kirk15] "></a>[Kirk15] Shane Kirk (2015) â€˜C++ Exceptions: The Good, The Bad, And The Uglyâ€™ <a href="http://www.shanekirk.com/2015/06/c-exceptions-the-good-the-bad-and-the-ugly/">http://www.shanekirk.com/2015/06/c-exceptions-the-good-the-bad-and-the-ugly/</a></p>

<p class="bibliomixed"><a id="[Milewski14]"></a>[Milewski14] Bartosz Milewski (2014) <a href="https://bartoszmilewski.com/2014/10/28/category-theory-for-programmers-the-preface/">https://bartoszmilewski.com/2014/10/28/category-theory-for-programmers-the-preface/</a></p>

<p class="bibliomixed"><a id="[MusingMortoray12] "></a>[MusingMortoray12] â€˜Everything wrong with exceptionsâ€™ (2012)<a href="https://mortoray.com/2012/04/02/everything-wrong-with-exceptions/">https://mortoray.com/2012/04/02/everything-wrong-with-exceptions/</a></p>

<p class="bibliomixed"><a id="[N4685]"></a>[N4685] <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/n4685.pdf">http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/n4685.pdf</a></p>

<p class="bibliomixed"><a id="[P0323r3]"></a>[P0323r3] <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0323r3.pdf">http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0323r3.pdf</a></p>

<p class="bibliomixed"><a id="[P0650r1]"></a>[P0650r1] <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0650r1.pdf">http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0650r1.pdf</a></p>

<p class="bibliomixed"><a id="[P0779r0]"></a>[P0779r0] <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0779r0.pdf">http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0779r0.pdf</a></p>

<p class="bibliomixed"><a id="[P0798r0]"></a>[P0798r0] <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0798r0.html">http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0798r0.html</a></p>

<p class="bibliomixed"><a id="[Romeo17]"></a>[Romeo17] Vittorio Romeo (2017) â€˜Why choose sum types over exceptions?â€™ <a href="https://vittorioromeo.info/index/blog/adts_over_exceptions.html">https://vittorioromeo.info/index/blog/adts_over_exceptions.html</a></p>

<p class="bibliomixed"><a id="[Rust]"></a>[Rust] <a href="https://doc.rust-lang.org/1.9.0/std/macro.try!.html">https://doc.rust-lang.org/1.9.0/std/macro.try!.html</a></p>

<p class="bibliomixed"><a id="[Stackoverflow]"></a>[Stackoverflow] â€˜Why is exception handling bad?â€™(<a href="https://stackoverflow.com/questions/1736146/why-is-exception-handling-bad">https://stackoverflow.com/questions/1736146/why-is-exception-handling-bad</a>) and â€˜Are Exceptions in C++ really slowâ€™ (<a href="https://stackoverflow.com/questions/13835817/are-exceptions-in-c-really-slow">https://stackoverflow.com/questions/13835817/are-exceptions-in-c-really-slow</a>)</p>

<p class="bibliomixed"><a id="[Stroustrup18]"></a>[Stroustrup18] Bjarne Stroustrup and Herb Sutter (eds)<a href="https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#e3-use-exceptions-for-error-handling-only">https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#e3-use-exceptions-for-error-handling-only</a></p>
</p>
<p><strong>Notes:</strong>&nbsp;</p>
<p><em>More fields may be available via dynamicdata ..</em></p>
</div>
</channel>
</rss>
