<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/css" href="/stylesheets/rss.css"?>
<rss xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/">
  <channel>
    <title>www.weisserth.net : Category Software Development, I work with software every day. I develop software for a living and in my spare time. From my point of view, Open Source software is the way to go. At work, I deal with the Java Enterprise world. In my free time it's mainly Ruby and PHP.</title>
    <link>http://www.weisserth.net</link>
    <atom:link type="application/rss+xml" href="http://www.weisserth.net/category/software-development.rss" rel="self"/>
    <language>en-us</language>
    <ttl>40</ttl>
    <description>on photography, gear and web technology</description>
    <item>
      <title>Tracking down your stolen camera? Not impossible!</title>
      <description>&lt;p&gt;Not discussing the recently uncovered privacy issues with Apple&amp;#8217;s mobile phones, one impressive feature of an iPhone is that if you&amp;#8217;re a MobileMe user, you can use the MobileMe service to track down your stolen iPhone using the &lt;span class="caps"&gt;GPS&lt;/span&gt; and connectivity integrated in the iPhone. If only something like this existed for cameras. I have never lost a camera to theft or otherwise &amp;#8211; yet. Nevertheless, I stumbled across a new service online that may help you retrieve your lost camera &amp;#8211; given someone else is bold enough to use it and post pictures taken with it on the Internet.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.stolencamerafinder.com/"&gt;www.stolencamerafinder.com&lt;/a&gt; is a new service developed and offered by &lt;a href="http://www.mattburns.co.uk/"&gt;Matt Burns&lt;/a&gt;. Matt&amp;#8217;s idea is simple yet effective. Most modern digital cameras store their serial number within the meta data in the images they capture. So when someone is putting images on the Internet, the meta data embedded in the image will contain the serial number. All you got to do is look for images on the Internet containing the serial number of the camera that you lost or that was stolen. So much for theory.&lt;/p&gt;
&lt;p&gt;As the Internet is vast place, Stolen Camera Finder (&lt;span class="caps"&gt;SCF&lt;/span&gt;) is limited to images published to Flickr &amp;#8211; for the time being at least. So, &lt;span class="caps"&gt;SCF&lt;/span&gt; will not notice images from lost cameras uploaded to places other than Flickr. Flickr is a good start though, as it&amp;#8217;s the premier photo sharing platform for photography enthusiasts. In terms of sheer volume, Facebook would be a good place to watch as well.&lt;/p&gt;
&lt;p&gt;How does the service work? Well, first you need to find out what the serial number of your lost camera is. You didn&amp;#8217;t write it down before your camera got lost? Not a problem, the number will likely be embedded in the &lt;span class="caps"&gt;EXIF&lt;/span&gt; metadata of one of your old pictures. Once you have opened the &lt;span class="caps"&gt;SCF&lt;/span&gt; page in your browser, you can either enter the serial number, provided you know it, or when using a supported browser, you can just drag and drop an image taken with your camera. The image must contain &lt;span class="caps"&gt;EXIF&lt;/span&gt; information with the serial number being part of it. A majority of cameras stores such information.&lt;/p&gt;
&lt;p&gt;What happens then is that &lt;span class="caps"&gt;SCF&lt;/span&gt; compares the provided serial number to a database of serial numbers found in images on Flickr. The database is being populated by crawling Flickr and mapping each newly found serial number from the available &lt;span class="caps"&gt;EXIF&lt;/span&gt; information against the &lt;span class="caps"&gt;URL&lt;/span&gt; of the image containing that information. Increasing the number of records in that database that is available to the search that happens when someone enters a serial number in &lt;span class="caps"&gt;SCF&lt;/span&gt;, is done by volunteers running the crawlers that work through Flickr and populate the database. At the moment, the database is still very limited and contains only a fraction of the serial numbers used in Flickr images. As time goes by, this number will increase, but chances are that you won&amp;#8217;t even find your own images you uploaded to Flickr yourself.&lt;/p&gt;
&lt;p&gt;Anyway, the idea is good. The project is limited by what Flickr allows in terms of automatic programs crawling its site and the fact that only Flickr is considered when searching for serial numbers. There are already reports of people having found images on Flickr from stolen cameras, which is impressively enough showing the use of this service.&lt;/p&gt;
&lt;p&gt;For a more technical background of the service, take a look at &lt;a href="http://code.google.com/p/stolencamerafinder/"&gt;the &lt;span class="caps"&gt;SCF&lt;/span&gt; page on Google Code&lt;/a&gt;.&lt;/p&gt;</description>
      <pubDate>Fri, 13 May 2011 16:51:00 -0000</pubDate>
      <guid isPermaLink="false">urn:uuid:a62e1581-448f-46c8-972a-7045e86f497c</guid>
      <comments>http://www.weisserth.net/2011/05/13/tracking-down-your-stolen-camera-not-impossible#comments</comments>
      <category>Photography</category>
      <category>Software Development</category>
      <category>camera</category>
      <category>scf</category>
      <category>stolen</category>
      <category>lost</category>
      <category>lostandfound</category>
      <category>Flickr</category>
      <trackback:ping>http://www.weisserth.net/trackbacks?article_id=35</trackback:ping>
      <link>http://www.weisserth.net/2011/05/13/tracking-down-your-stolen-camera-not-impossible</link>
    </item>
    <item>
      <title>Java Pattern: try things repeatedly until reaching a timeout</title>
      <description>&lt;p&gt;Nondeterministic tests are a common problem in test setups, especially with integration tests. For example, imagine you are doing an integration test of two components that exchange messages where receiving a message in one of the systems changes its internal state which you want to verify. However, the message exchange can be delayed due to external factors (network latency, load etc.). When running tests (for example using the excellent &lt;a href="http://cukes.info/"&gt;Cucumber&lt;/a&gt; framework), testing steps are usually run sequentially. It may happen that the tested system is lagging behind the testing steps, failing your test in some (but not all) cases. You need to make your tests more tolerant for these situations. Often, that means retrying for a couple of times.&lt;/p&gt;
&lt;p&gt;How would you implement this pattern in Java? Well, here&amp;#8217;s how I did it. I am using a timed runner object that tries an action until it succeeds before it times out. You can define what should happen in case the action times out, by overwriting the abstract method.&lt;/p&gt;
&lt;div class="CodeRay"&gt;&lt;pre&gt;&lt;span class="CodeRay"&gt;&lt;span class="c"&gt;/**
 * Use this class to run actions with a timeout. 
 * Actions have to be wrapped within 
 * a yield method of the Yieldable
 * interface.
 */&lt;/span&gt;
&lt;span class="di"&gt;public&lt;/span&gt; &lt;span class="di"&gt;abstract&lt;/span&gt; &lt;span class="ty"&gt;class&lt;/span&gt; &lt;span class="cl"&gt;TimedRunner&lt;/span&gt; {
  
  &lt;span class="di"&gt;private&lt;/span&gt; &lt;span class="ty"&gt;int&lt;/span&gt; timoutLength;
  &lt;span class="di"&gt;private&lt;/span&gt; &lt;span class="ty"&gt;int&lt;/span&gt; elapsedTime;
  &lt;span class="di"&gt;private&lt;/span&gt; &lt;span class="ty"&gt;int&lt;/span&gt; checkRate = &lt;span class="i"&gt;250&lt;/span&gt;;

  &lt;span class="di"&gt;public&lt;/span&gt; TimedRunner(&lt;span class="ty"&gt;int&lt;/span&gt; length) {
    timoutLength = length;
    elapsedTime = &lt;span class="i"&gt;0&lt;/span&gt;;
  }

  &lt;span class="di"&gt;public&lt;/span&gt; TimedRunner() {
    timoutLength = &lt;span class="i"&gt;10000&lt;/span&gt;;
    elapsedTime = &lt;span class="i"&gt;0&lt;/span&gt;;
  }

  &lt;span class="di"&gt;public&lt;/span&gt; &lt;span class="di"&gt;synchronized&lt;/span&gt; &lt;span class="ty"&gt;void&lt;/span&gt; reset() {
    elapsedTime = &lt;span class="i"&gt;0&lt;/span&gt;;
  }

  &lt;span class="di"&gt;public&lt;/span&gt; &lt;span class="ty"&gt;void&lt;/span&gt; run(Yieldable runMe) {
    &lt;span class="kw"&gt;for&lt;/span&gt; (; ;) {
      &lt;span class="kw"&gt;try&lt;/span&gt; {
        &lt;span class="pt"&gt;Thread&lt;/span&gt;.sleep(checkRate);
      }
      &lt;span class="kw"&gt;catch&lt;/span&gt; (&lt;span class="ex"&gt;InterruptedException&lt;/span&gt; ioe) {
        &lt;span class="kw"&gt;continue&lt;/span&gt;;
      }

      &lt;span class="ty"&gt;boolean&lt;/span&gt; success = runMe.yield();

      elapsedTime += checkRate;

      &lt;span class="kw"&gt;if&lt;/span&gt; (success) {
        &lt;span class="kw"&gt;break&lt;/span&gt;;
      }

      &lt;span class="kw"&gt;if&lt;/span&gt; (elapsedTime &amp;gt; timoutLength) {
        timeout();
        &lt;span class="kw"&gt;break&lt;/span&gt;;
      }
    }
  }

  &lt;span class="c"&gt;// just overwrite this method to perform the timeout action&lt;/span&gt;
  &lt;span class="di"&gt;public&lt;/span&gt; &lt;span class="di"&gt;abstract&lt;/span&gt; &lt;span class="ty"&gt;void&lt;/span&gt; timeout();
}&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;Now, in other languages, like &lt;a href="http://www.ruby-lang.org/en/"&gt;Ruby&lt;/a&gt; or &lt;a href="http://www.python.org/"&gt;Python&lt;/a&gt; you could just call a method and pass it a block of instructions. As that&amp;#8217;s not possible in Java, you need to wrap the actions you want to pass within a method belonging to an object you can pass along. That object will be an instance implementing the Yieldable interface:&lt;/p&gt;
&lt;div class="CodeRay"&gt;&lt;pre&gt;&lt;span class="CodeRay"&gt;&lt;span class="c"&gt;/**
 * Implement this interface when you want 
 * to use TimedRunner. TimedRunner 
 * expects a Yieldable object, class its yield
 * method and calls it until 
 * it succeeds or a timeout is reached.
 */&lt;/span&gt;
&lt;span class="di"&gt;public&lt;/span&gt; &lt;span class="ty"&gt;interface&lt;/span&gt; &lt;span class="cl"&gt;Yieldable&lt;/span&gt; {
  &lt;span class="di"&gt;public&lt;/span&gt; &lt;span class="ty"&gt;boolean&lt;/span&gt; yield();
}&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;The yield() method needs to return a status of success or failure so that the TimedRunner knows when to stop calling it. You could extend/modify this pattern by changing the signature of yield() to match your specific needs.&lt;/p&gt;
&lt;p&gt;What should be done in case of a timeout? The most common thing to do would be to fail the test (assuming usage of &lt;a href="http://www.junit.org/"&gt;JUnit&lt;/a&gt; 4):&lt;/p&gt;
&lt;div class="CodeRay"&gt;&lt;pre&gt;&lt;span class="CodeRay"&gt;&lt;span class="kw"&gt;import&lt;/span&gt; &lt;span class="ic"&gt;junit.framework.Assert&lt;/span&gt;;

&lt;span class="di"&gt;public&lt;/span&gt; &lt;span class="ty"&gt;class&lt;/span&gt; &lt;span class="cl"&gt;FailRunner&lt;/span&gt; &lt;span class="di"&gt;extends&lt;/span&gt; TimedRunner {
  &lt;span class="at"&gt;@Override&lt;/span&gt;
  &lt;span class="di"&gt;public&lt;/span&gt; &lt;span class="ty"&gt;void&lt;/span&gt; timeout() {
    Assert.fail(&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;Timed out without success.&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;);
  }

  &lt;span class="di"&gt;public&lt;/span&gt; FailRunner(&lt;span class="ty"&gt;int&lt;/span&gt; timeout) {
    &lt;span class="lv"&gt;super&lt;/span&gt;(timeout);    
  }
}&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;In your test code, you would put the nondeterministic code within a yield method and pass it to a TimedRunner instance:&lt;/p&gt;
&lt;div class="CodeRay"&gt;&lt;pre&gt;&lt;span class="CodeRay"&gt;&lt;span class="c"&gt;// ... within your test code...&lt;/span&gt;

Yieldable runMe = &lt;span class="kw"&gt;new&lt;/span&gt; Yieldable(){
  &lt;span class="di"&gt;public&lt;/span&gt; &lt;span class="ty"&gt;boolean&lt;/span&gt; yield() {
    &lt;span class="c"&gt;// do something here and return true &lt;/span&gt;
    &lt;span class="c"&gt;// if it succeeded or false otherwise&lt;/span&gt;
  }
};

&lt;span class="kw"&gt;new&lt;/span&gt; FailRunner(&lt;span class="i"&gt;30000&lt;/span&gt;).run(runMe);

&lt;span class="c"&gt;// ...&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;Feel free to leave feedback in the comments. I would be interested to learn how you handle testing issues such as this one.&lt;/p&gt;</description>
      <pubDate>Thu, 26 Aug 2010 06:59:00 -0000</pubDate>
      <guid isPermaLink="false">urn:uuid:158041e3-18cc-4f29-ba11-50ebcb30596a</guid>
      <comments>http://www.weisserth.net/2010/08/26/java-pattern-try-things-repeatedly-until-reaching-a-timeout#comments</comments>
      <category>Software Development</category>
      <category>Java</category>
      <category>deterministic</category>
      <category>integration</category>
      <category>nondeterministic</category>
      <category>pattern</category>
      <category>testing</category>
      <category>timeout</category>
      <category>yield</category>
      <category>yieldable</category>
      <trackback:ping>http://www.weisserth.net/trackbacks?article_id=25</trackback:ping>
      <link>http://www.weisserth.net/2010/08/26/java-pattern-try-things-repeatedly-until-reaching-a-timeout</link>
    </item>
    <item>
      <title>Java, arrays, autoboxing and Arrays.asList</title>
      <description>&lt;p&gt;Yesterday, I had some fun with Java again. Since Java 1.5 it has become so natural to mix primitive datatypes with their object based counter parts as Java boxes and unboxes expressions as necessary without the need to make any explicit casts &amp;#8211; or so I thought.&lt;/p&gt;
&lt;p&gt;Take a look at the code below:&lt;/p&gt;
&lt;div class="CodeRay"&gt;&lt;pre&gt;&lt;span class="CodeRay"&gt;&lt;span class="ty"&gt;byte&lt;/span&gt;&lt;span class="ty"&gt;[]&lt;/span&gt; testBytes1 = {&lt;span class="i"&gt;1&lt;/span&gt;, &lt;span class="i"&gt;2&lt;/span&gt;, &lt;span class="i"&gt;3&lt;/span&gt;, &lt;span class="i"&gt;4&lt;/span&gt;, &lt;span class="i"&gt;5&lt;/span&gt;};
&lt;span class="pt"&gt;List&lt;/span&gt;&amp;lt;&lt;span class="pt"&gt;Byte&lt;/span&gt;&amp;gt; list1 = &lt;span class="pt"&gt;Arrays&lt;/span&gt;.asList(testBytes1);&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;br/&gt;
If you expected that you can create a list of Byte objects from a byte[] array, then you&amp;#8217;re sadly mistaken. As Java cannot autobox arrays (which are backed up by a separate type, not equal to the respective primitive elements within), &lt;em&gt;&lt;a href="http://java.sun.com/javase/6/docs/api/java/util/Arrays.html#asList(T...)"&gt;Arrays.asList&lt;/a&gt;&lt;/em&gt; will not accept &lt;em&gt;testBytes1&lt;/em&gt; since its type is &lt;em&gt;byte[]&lt;/em&gt; which is not autoboxed into &lt;em&gt;Byte[]&lt;/em&gt;. So above example code is not valid without changes.&lt;/p&gt;
&lt;p&gt;It would compile like this:&lt;/p&gt;
&lt;div class="CodeRay"&gt;&lt;pre&gt;&lt;span class="CodeRay"&gt;&lt;span class="ty"&gt;byte&lt;/span&gt;&lt;span class="ty"&gt;[]&lt;/span&gt; testBytes1 = {&lt;span class="i"&gt;1&lt;/span&gt;, &lt;span class="i"&gt;2&lt;/span&gt;, &lt;span class="i"&gt;3&lt;/span&gt;, &lt;span class="i"&gt;4&lt;/span&gt;, &lt;span class="i"&gt;5&lt;/span&gt;};
&lt;span class="pt"&gt;List&lt;/span&gt;&amp;lt;&lt;span class="ty"&gt;byte&lt;/span&gt;&lt;span class="ty"&gt;[]&lt;/span&gt;&amp;gt; list1 = &lt;span class="pt"&gt;Arrays&lt;/span&gt;.asList(testBytes1);&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;br/&gt;
So, now you expect that you will end up with a list of five &lt;em&gt;Byte&lt;/em&gt; objects? Wrong again. Look at the expression and its type. The type is still &lt;em&gt;byte[]&lt;/em&gt;. So, &lt;em&gt;list1&lt;/em&gt; contains exactly one element, which is an array with five &lt;em&gt;byte&lt;/em&gt; literals.&lt;/p&gt;
&lt;p&gt;Long story, short answer: before using &lt;em&gt;&lt;a href="http://java.sun.com/javase/6/docs/api/java/util/Arrays.html#asList(T...)"&gt;Arrays.asList&lt;/a&gt;&lt;/em&gt; loop over a primitive array and copy the elements to an object based array.&lt;/p&gt;</description>
      <pubDate>Thu, 06 May 2010 16:54:00 -0000</pubDate>
      <guid isPermaLink="false">urn:uuid:a17dca68-4cc5-4dbe-9ef6-374889feff19</guid>
      <comments>http://www.weisserth.net/2010/05/06/java-arrays-autoboxing-and-arrays-aslist#comments</comments>
      <category>Software Development</category>
      <category>Java</category>
      <category>arrays</category>
      <category>autoboxing</category>
      <category>collections</category>
      <trackback:ping>http://www.weisserth.net/trackbacks?article_id=18</trackback:ping>
      <link>http://www.weisserth.net/2010/05/06/java-arrays-autoboxing-and-arrays-aslist</link>
    </item>
    <item>
      <title>Using the MySQL encrypt function in Ruby</title>
      <description>&lt;p&gt;If you&amp;#8217;re dealing with a legacy MySQL database schema where your users&amp;#8217; passwords are encrypted using &lt;a href="http://dev.mysql.com/doc/refman/5.1/en/encryption-functions.html#function_encrypt"&gt;MySQL&amp;#8217;s encrypt function&lt;/a&gt; within your schema and you want to create new records like that using Ruby rather than calling the MySQL function, you can easily do that with Ruby. Ruby supplies a &lt;a href="http://ruby-doc.org/docs/ProgrammingRuby/html/ref_c_string.html#String.crypt"&gt;crypt function&lt;/a&gt; that does just what the MySQL encrypt function provides. Both implementations use the &lt;span class="caps"&gt;UNIX&lt;/span&gt; C function crypt(3) so you can replace the use of one with another.&lt;/p&gt;
&lt;p&gt;The function expects a salt value of two characters. If none is provided, a random string will be used. Take a look at this simple example:&lt;/p&gt;
&lt;div class="CodeRay"&gt;&lt;pre&gt;&lt;span class="CodeRay"&gt;  &lt;span class="c"&gt;#!/usr/bin/env ruby -wKU&lt;/span&gt;

  &lt;span class="r"&gt;def&lt;/span&gt; &lt;span class="fu"&gt;mysql_encrypt&lt;/span&gt;(pw)
    
    &lt;span class="c"&gt;# compute a random salt value&lt;/span&gt;
    &lt;span class="c"&gt;# (will end up to be a Base64 encoded string &lt;/span&gt;
    &lt;span class="c"&gt;# of random characters)&lt;/span&gt;
    salt = [&lt;span class="co"&gt;Array&lt;/span&gt;.new(&lt;span class="i"&gt;2&lt;/span&gt;){rand(&lt;span class="i"&gt;256&lt;/span&gt;).chr}.join].pack(&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;m&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;).chomp
    &lt;span class="r"&gt;return&lt;/span&gt; pw.crypt(salt)
  &lt;span class="r"&gt;end&lt;/span&gt;

  encrypted_password = mysql_encrypt(&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;test&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;)

  puts &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;Encrypted password could be &lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; + encrypted_password

  &lt;span class="c"&gt;# we take the first two characters of the already&lt;/span&gt;
  &lt;span class="c"&gt;# encrypted password as salt value&lt;/span&gt;
  &lt;span class="c"&gt;# for the re-encryption so we end up with the same value&lt;/span&gt;
  
  compared_password = &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;test&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;.crypt(encrypted_password[&lt;span class="i"&gt;0&lt;/span&gt;,&lt;span class="i"&gt;2&lt;/span&gt;])

  puts &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;The re-encrypted 'test' string is now &lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; + compared_password&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Creating hashed passwords using crypt(3) cannot be regarded as secure though. Take a look at the &lt;a href="http://en.wikipedia.org/wiki/Crypt_(Unix)"&gt;Wikipedia entry on crypt&lt;/a&gt;. If you&amp;#8217;re implementing any kind of user authentication from scratch, consider using other means of hashing passwords.&lt;/p&gt;</description>
      <pubDate>Sun, 14 Feb 2010 17:48:00 -0000</pubDate>
      <guid isPermaLink="false">urn:uuid:69d660a3-e5cb-4166-8009-e2fe39b9cc87</guid>
      <comments>http://www.weisserth.net/2010/02/14/using-the-mysql-encrypt-function-in-ruby#comments</comments>
      <category>Software Development</category>
      <category>MySQL</category>
      <category>Rails</category>
      <category>Ruby</category>
      <category>encrypt</category>
      <category>hashing</category>
      <category>password</category>
      <category>passwords</category>
      <trackback:ping>http://www.weisserth.net/trackbacks?article_id=11</trackback:ping>
      <link>http://www.weisserth.net/2010/02/14/using-the-mysql-encrypt-function-in-ruby</link>
    </item>
  </channel>
</rss>

