<?xml version="1.0" encoding="utf-8"?>
<rss xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:pingback="http://madskills.com/public/xml/rss/module/pingback/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:dc="http://purl.org/dc/elements/1.1/" version="2.0">
  <channel>
    <title>Felice Pollano Blog - Cron</title>
    <link>http://www.felicepollano.com/</link>
    <description>The official Fatica Labs Blog!</description>
    <language>en-us</language>
    <copyright>Felice Pollano</copyright>
    <lastBuildDate>Wed, 16 Jun 2010 15:52:39 GMT</lastBuildDate>
    <generator>newtelligence dasBlog 2.3.9074.18820</generator>
    <managingEditor>felice@felicepollano.com</managingEditor>
    <webMaster>felice@felicepollano.com</webMaster>
    <item>
      <trackback:ping>http://www.felicepollano.com/Trackback.aspx?guid=982dfdf2-cec1-462b-b160-0f8876ce7958</trackback:ping>
      <pingback:server>http://www.felicepollano.com/pingback.aspx</pingback:server>
      <pingback:target>http://www.felicepollano.com/PermaLink.aspx?guid=982dfdf2-cec1-462b-b160-0f8876ce7958</pingback:target>
      <dc:creator>Felice Pollano</dc:creator>
      <wfw:comment>http://www.felicepollano.com/CommentView.aspx?guid=982dfdf2-cec1-462b-b160-0f8876ce7958</wfw:comment>
      <wfw:commentRss>http://www.felicepollano.com/SyndicationService.asmx/GetEntryCommentsRss?guid=982dfdf2-cec1-462b-b160-0f8876ce7958</wfw:commentRss>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p align="justify">
Probabilmente vi sarà capitato di dovere eseguire qualche azione all’interno del vostro
software dipendentemente da trigger innescati da data e/o ora. Per esempio un certo
processo non si scatena del week-end, oppure un altro processo deve partire solo a
mezzanotte etc etc. Quando queste cose non siano attuabili esternamente con il task
scheduler di sistema, sarebbe bello poter avere una libreria pronto uso in .NET. Ebbene
questa libreria c’è, ed è il parser di <a href="http://en.wikipedia.org/wiki/CRON_expression" target="_blank">espressioni
Cron</a> che <a href="https://sourceforge.net/projects/cronnet/files/" target="_blank">trovate
qui</a>. Lungi dall’essere un concetto moderno, si tratta di un modo di esprimere
range temporali tramite una stringa che arriva da Unix. Oggi chiamiamo una cosa simile
“Domain Specific Language”, ma tant’è il concetto è il medesimo. Lungi anche dall’
essere originale il concetto in .NET, la <a href="https://sourceforge.net/projects/cronnet/" target="_blank">libreria
che propongo</a> è una estrapolazione di codice dalla più completa e complessa libreria <a href="http://quartznet.sourceforge.net/" target="_blank">Quartz.NET</a>,
a sua volta un porting della libreria Java <a href="http://www.quartz-scheduler.org/" target="_blank">Quartz</a>.
Se non volete introdurre troppa complessità al vostro deploy aggiungendo una nuova
libreria, potete “grabbare” le classi dalla dll di Cron.NET ( sono tre file… ) e compilarli
con il vostro progetto, ed avrete a disposizione tutta la potenza delle espressioni
Cron ;).
</p>
        <p align="justify">
Già, ma come funzionano le espressioni Cron ? Facciamo un paio di esempi:
</p>
        <p align="justify">
          <strong>"* * 10-11 L * ?" = </strong>questo trigger è valido l’ultimo del mese dalle
10-11
</p>
        <p align="justify">
          <strong>"* * * ? * MON-FRI" = </strong>questo trigger è valido tutti i giorni, a tutte
le ore, eccetto il week end.
</p>
        <p align="justify">
Ok, questo da l’idea delle potezialità della cosa, ma ovviamente serivirebbe una più
estesa…
</p>
        <h4>Documentazione
</h4>
        <p>
Una espressione Cron è composta da <strong>6 campi obbligatori</strong>, più <strong>uno
opzionale</strong>. Il significato dei campi è schematizzato nella tabella qui sotto:
</p>
        <table cellspacing="8">
          <tbody>
            <tr>
              <th align="left">
Campo</th>
              <th align="left">
 </th>
              <th align="left">
Valori permessi</th>
              <th align="left">
 </th>
              <th align="left">
Caratteri speciali ammessi</th>
            </tr>
            <tr>
              <td align="left">
Secondi</td>
              <td align="left">
 </td>
              <td align="left">
0-59</td>
              <td align="left">
 </td>
              <td align="left">
, - /</td>
            </tr>
            <tr>
              <td align="left">
Minuti</td>
              <td align="left">
 </td>
              <td align="left">
0-59</td>
              <td align="left">
 </td>
              <td align="left">
, - /</td>
            </tr>
            <tr>
              <td align="left">
Ore</td>
              <td align="left">
 </td>
              <td align="left">
0-23</td>
              <td align="left">
 </td>
              <td align="left">
, - /</td>
            </tr>
            <tr>
              <td align="left">
Giorno del mese</td>
              <td align="left">
 </td>
              <td align="left">
1-31</td>
              <td align="left">
 </td>
              <td align="left">
, - ? / L W C</td>
            </tr>
            <tr>
              <td align="left">
Mese</td>
              <td align="left">
 </td>
              <td align="left">
1-12 or JAN-DEC</td>
              <td align="left">
 </td>
              <td align="left">
, - /</td>
            </tr>
            <tr>
              <td align="left">
Giorno della settimana</td>
              <td align="left">
 </td>
              <td align="left">
1-7 or SUN-SAT</td>
              <td align="left">
 </td>
              <td align="left">
, - ? / L #</td>
            </tr>
            <tr>
              <td align="left">
Anno ( Opzionale )</td>
              <td align="left">
 </td>
              <td align="left">
vuoto, 1970-2099</td>
              <td align="left">
 </td>
              <td align="left">
, - /</td>
            </tr>
          </tbody>
        </table>
        <p>
 
</p>
        <p align="justify">
Il carattere jolly <strong>‘*’</strong> può sempre essere usato con il significato
di “tutti i valori”, per esempio se metto <strong>‘*’</strong> nel campo minuti significa
tutti i minuti.
</p>
        <p align="justify">
Il carattere<strong> ‘?’</strong> può essere usato solo come Giorno del mese o giorno
della settimana. Significa “nessun valore in particolare” e serve quando devo fissare
l’altro. Se per esempio fisso il giorno della settimana metterò<strong> ‘?’</strong> nel
giorno del mese, e viceversa.
</p>
        <p align="justify">
Il carattere<strong> ‘-‘</strong> lo utilizzo quando voglio specificare un range:
per esempio 10-12 nel campo ora significa dalle 10 a tutte le 12.
</p>
        <p align="justify">
Uso invece la <strong>‘,’</strong> quando voglio specificare singolarmente più valori
possibili: JAN,MAR significa il mese di Gennaio e di Marzo, ma non Febbraio ( e, ovviamente,
non tutti gli altri ).
</p>
        <p align="justify">
Per specificare dei periodi utilizzo<strong> ‘/’</strong>: per esempio se metto 0/15
nel campo secondi, significa “ogni 15 secondi”: sarà attivo il trigger quindi ai secondi
15,30,45 etc etc.
</p>
        <p align="justify">
Il carattere speciale<strong> ‘L’</strong> significa ultimo. Nel campo mese significa
semplicemente l’ultimo giorno del mese (30/31/28 o 29 ) in modo concorde con il mese
/ anno bisestile. Nel campo settimana significa semplicemente 7 ( cioè Sabato ), ma
se <strong>preceduto da un numero</strong> significa “l’ultimo xxxx del mese”. Per
esempio se scrivo <strong>6L</strong> significa <strong>l’ultimo Venerdì del mese</strong>. 
</p>
        <p align="justify">
Il carettere ‘W’ può essere specificato solo nel campo giorno del mese, preceduto
da un solo carattere, e significa “il giorno lavorativo più vicino a”. Per esempio
se scrivo <strong>1W</strong> significa <strong>il giorno lavorativo più vicino al
primo del mese</strong>. Se scrivo <strong>LW</strong> significa <strong>l’ultimo
giorno lavorativo del mese</strong>.
</p>
        <p align="justify">
Per ultimo il carattere ‘#’, utilizzabile solo nel giorno della settimana, indica
l’ennesimo xxxx del mese. Per esempio, se mi interessa il <strong>terzo venerdì del
mese</strong>, scriverò <strong>6#3</strong>.
</p>
        <p>
Per utilizzare una cron expression basta creare un istanza dell’ogegtto CronExpression,
passando la stringa sul costruttore. Ecco un esempio:
</p>
        <div class="csharpcode">
          <pre class="alt">
            <span class="lnum"> 1: </span> [Test]</pre>
          <pre>
            <span class="lnum"> 2: </span>
            <span class="kwrd">public</span>
            <span class="kwrd">void</span> LastOfTheMonth()</pre>
          <pre class="alt">
            <span class="lnum"> 3: </span> {</pre>
          <pre>
            <span class="lnum"> 4: </span> var
exp = <span class="kwrd">new</span> CronExpression(<span class="str">"* * * L * ?"</span>);</pre>
          <pre class="alt">
            <span class="lnum"> 5: </span> Assert.IsTrue(exp.IsSatisfiedBy(<span class="kwrd">new</span> DateTime(2000,
1, 31)));</pre>
          <pre>
            <span class="lnum"> 6: </span> Assert.IsTrue(exp.IsSatisfiedBy(<span class="kwrd">new</span> DateTime(2000,
2, 29)));</pre>
          <pre class="alt">
            <span class="lnum"> 7: </span> Assert.IsFalse(exp.IsSatisfiedBy(<span class="kwrd">new</span> DateTime(2000,
2, 28)));</pre>
          <pre>
            <span class="lnum"> 8: </span> }</pre>
        </div>
        <style type="text/css">.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }
</style>
        <img width="0" height="0" src="http://www.felicepollano.com/aggbug.ashx?id=982dfdf2-cec1-462b-b160-0f8876ce7958" />
      </body>
      <title>Cron.NET: un DSL per il tempo…</title>
      <guid isPermaLink="false">http://www.felicepollano.com/PermaLink.aspx?guid=982dfdf2-cec1-462b-b160-0f8876ce7958</guid>
      <link>http://www.felicepollano.com/2010/06/16/CronNETUnDSLPerIlTempo.aspx</link>
      <pubDate>Wed, 16 Jun 2010 15:52:39 GMT</pubDate>
      <description>&lt;p align="justify"&gt;
Probabilmente vi sarà capitato di dovere eseguire qualche azione all’interno del vostro
software dipendentemente da trigger innescati da data e/o ora. Per esempio un certo
processo non si scatena del week-end, oppure un altro processo deve partire solo a
mezzanotte etc etc. Quando queste cose non siano attuabili esternamente con il task
scheduler di sistema, sarebbe bello poter avere una libreria pronto uso in .NET. Ebbene
questa libreria c’è, ed è il parser di &lt;a href="http://en.wikipedia.org/wiki/CRON_expression" target="_blank"&gt;espressioni
Cron&lt;/a&gt; che &lt;a href="https://sourceforge.net/projects/cronnet/files/" target="_blank"&gt;trovate
qui&lt;/a&gt;. Lungi dall’essere un concetto moderno, si tratta di un modo di esprimere
range temporali tramite una stringa che arriva da Unix. Oggi chiamiamo una cosa simile
“Domain Specific Language”, ma tant’è il concetto è il medesimo. Lungi anche dall’
essere originale il concetto in .NET, la &lt;a href="https://sourceforge.net/projects/cronnet/" target="_blank"&gt;libreria
che propongo&lt;/a&gt; è una estrapolazione di codice dalla più completa e complessa libreria &lt;a href="http://quartznet.sourceforge.net/" target="_blank"&gt;Quartz.NET&lt;/a&gt;,
a sua volta un porting della libreria Java &lt;a href="http://www.quartz-scheduler.org/" target="_blank"&gt;Quartz&lt;/a&gt;.
Se non volete introdurre troppa complessità al vostro deploy aggiungendo una nuova
libreria, potete “grabbare” le classi dalla dll di Cron.NET ( sono tre file… ) e compilarli
con il vostro progetto, ed avrete a disposizione tutta la potenza delle espressioni
Cron ;).
&lt;/p&gt;
&lt;p align="justify"&gt;
Già, ma come funzionano le espressioni Cron ? Facciamo un paio di esempi:
&lt;/p&gt;
&lt;p align="justify"&gt;
&lt;strong&gt;"* * 10-11 L * ?" = &lt;/strong&gt;questo trigger è valido l’ultimo del mese dalle
10-11
&lt;/p&gt;
&lt;p align="justify"&gt;
&lt;strong&gt;"* * * ? * MON-FRI" = &lt;/strong&gt;questo trigger è valido tutti i giorni, a tutte
le ore, eccetto il week end.
&lt;/p&gt;
&lt;p align="justify"&gt;
Ok, questo da l’idea delle potezialità della cosa, ma ovviamente serivirebbe una più
estesa…
&lt;/p&gt;
&lt;h4&gt;Documentazione
&lt;/h4&gt;
&lt;p&gt;
Una espressione Cron è composta da &lt;strong&gt;6 campi obbligatori&lt;/strong&gt;, più &lt;strong&gt;uno
opzionale&lt;/strong&gt;. Il significato dei campi è schematizzato nella tabella qui sotto:
&lt;/p&gt;
&lt;table cellspacing="8"&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;th align="left"&gt;
Campo&lt;/th&gt;
&lt;th align="left"&gt;
&amp;nbsp;&lt;/th&gt;
&lt;th align="left"&gt;
Valori permessi&lt;/th&gt;
&lt;th align="left"&gt;
&amp;nbsp;&lt;/th&gt;
&lt;th align="left"&gt;
Caratteri speciali ammessi&lt;/th&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align="left"&gt;
Secondi&lt;/td&gt;
&lt;td align="left"&gt;
&amp;nbsp;&lt;/td&gt;
&lt;td align="left"&gt;
0-59&lt;/td&gt;
&lt;td align="left"&gt;
&amp;nbsp;&lt;/td&gt;
&lt;td align="left"&gt;
, - /&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align="left"&gt;
Minuti&lt;/td&gt;
&lt;td align="left"&gt;
&amp;nbsp;&lt;/td&gt;
&lt;td align="left"&gt;
0-59&lt;/td&gt;
&lt;td align="left"&gt;
&amp;nbsp;&lt;/td&gt;
&lt;td align="left"&gt;
, - /&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align="left"&gt;
Ore&lt;/td&gt;
&lt;td align="left"&gt;
&amp;nbsp;&lt;/td&gt;
&lt;td align="left"&gt;
0-23&lt;/td&gt;
&lt;td align="left"&gt;
&amp;nbsp;&lt;/td&gt;
&lt;td align="left"&gt;
, - /&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align="left"&gt;
Giorno del mese&lt;/td&gt;
&lt;td align="left"&gt;
&amp;nbsp;&lt;/td&gt;
&lt;td align="left"&gt;
1-31&lt;/td&gt;
&lt;td align="left"&gt;
&amp;nbsp;&lt;/td&gt;
&lt;td align="left"&gt;
, - ? / L W C&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align="left"&gt;
Mese&lt;/td&gt;
&lt;td align="left"&gt;
&amp;nbsp;&lt;/td&gt;
&lt;td align="left"&gt;
1-12 or JAN-DEC&lt;/td&gt;
&lt;td align="left"&gt;
&amp;nbsp;&lt;/td&gt;
&lt;td align="left"&gt;
, - /&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align="left"&gt;
Giorno della settimana&lt;/td&gt;
&lt;td align="left"&gt;
&amp;nbsp;&lt;/td&gt;
&lt;td align="left"&gt;
1-7 or SUN-SAT&lt;/td&gt;
&lt;td align="left"&gt;
&amp;nbsp;&lt;/td&gt;
&lt;td align="left"&gt;
, - ? / L #&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align="left"&gt;
Anno ( Opzionale )&lt;/td&gt;
&lt;td align="left"&gt;
&amp;nbsp;&lt;/td&gt;
&lt;td align="left"&gt;
vuoto, 1970-2099&lt;/td&gt;
&lt;td align="left"&gt;
&amp;nbsp;&lt;/td&gt;
&lt;td align="left"&gt;
, - /&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p align="justify"&gt;
Il carattere jolly &lt;strong&gt;‘*’&lt;/strong&gt; può sempre essere usato con il significato
di “tutti i valori”, per esempio se metto &lt;strong&gt;‘*’&lt;/strong&gt; nel campo minuti significa
tutti i minuti.
&lt;/p&gt;
&lt;p align="justify"&gt;
Il carattere&lt;strong&gt; ‘?’&lt;/strong&gt; può essere usato solo come Giorno del mese o giorno
della settimana. Significa “nessun valore in particolare” e serve quando devo fissare
l’altro. Se per esempio fisso il giorno della settimana metterò&lt;strong&gt; ‘?’&lt;/strong&gt; nel
giorno del mese, e viceversa.
&lt;/p&gt;
&lt;p align="justify"&gt;
Il carattere&lt;strong&gt; ‘-‘&lt;/strong&gt; lo utilizzo quando voglio specificare un range:
per esempio 10-12 nel campo ora significa dalle 10 a tutte le 12.
&lt;/p&gt;
&lt;p align="justify"&gt;
Uso invece la &lt;strong&gt;‘,’&lt;/strong&gt; quando voglio specificare singolarmente più valori
possibili: JAN,MAR significa il mese di Gennaio e di Marzo, ma non Febbraio ( e, ovviamente,
non tutti gli altri ).
&lt;/p&gt;
&lt;p align="justify"&gt;
Per specificare dei periodi utilizzo&lt;strong&gt; ‘/’&lt;/strong&gt;: per esempio se metto 0/15
nel campo secondi, significa “ogni 15 secondi”: sarà attivo il trigger quindi ai secondi
15,30,45 etc etc.
&lt;/p&gt;
&lt;p align="justify"&gt;
Il carattere speciale&lt;strong&gt; ‘L’&lt;/strong&gt; significa ultimo. Nel campo mese significa
semplicemente l’ultimo giorno del mese (30/31/28 o 29 ) in modo concorde con il mese
/ anno bisestile. Nel campo settimana significa semplicemente 7 ( cioè Sabato ), ma
se &lt;strong&gt;preceduto da un numero&lt;/strong&gt; significa “l’ultimo xxxx del mese”. Per
esempio se scrivo &lt;strong&gt;6L&lt;/strong&gt; significa &lt;strong&gt;l’ultimo Venerdì del mese&lt;/strong&gt;. 
&lt;/p&gt;
&lt;p align="justify"&gt;
Il carettere ‘W’ può essere specificato solo nel campo giorno del mese, preceduto
da un solo carattere, e significa “il giorno lavorativo più vicino a”. Per esempio
se scrivo &lt;strong&gt;1W&lt;/strong&gt; significa &lt;strong&gt;il giorno lavorativo più vicino al
primo del mese&lt;/strong&gt;. Se scrivo &lt;strong&gt;LW&lt;/strong&gt; significa &lt;strong&gt;l’ultimo
giorno lavorativo del mese&lt;/strong&gt;.
&lt;/p&gt;
&lt;p align="justify"&gt;
Per ultimo il carattere ‘#’, utilizzabile solo nel giorno della settimana, indica
l’ennesimo xxxx del mese. Per esempio, se mi interessa il &lt;strong&gt;terzo venerdì del
mese&lt;/strong&gt;, scriverò &lt;strong&gt;6#3&lt;/strong&gt;.
&lt;/p&gt;
&lt;p&gt;
Per utilizzare una cron expression basta creare un istanza dell’ogegtto CronExpression,
passando la stringa sul costruttore. Ecco un esempio:
&lt;/p&gt;
&lt;div class="csharpcode"&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt; 1: &lt;/span&gt; [Test]&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt; 2: &lt;/span&gt; &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; LastOfTheMonth()&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt; 3: &lt;/span&gt; {&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt; 4: &lt;/span&gt; var
exp = &lt;span class="kwrd"&gt;new&lt;/span&gt; CronExpression(&lt;span class="str"&gt;"* * * L * ?"&lt;/span&gt;);&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt; 5: &lt;/span&gt; Assert.IsTrue(exp.IsSatisfiedBy(&lt;span class="kwrd"&gt;new&lt;/span&gt; DateTime(2000,
1, 31)));&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt; 6: &lt;/span&gt; Assert.IsTrue(exp.IsSatisfiedBy(&lt;span class="kwrd"&gt;new&lt;/span&gt; DateTime(2000,
2, 29)));&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt; 7: &lt;/span&gt; Assert.IsFalse(exp.IsSatisfiedBy(&lt;span class="kwrd"&gt;new&lt;/span&gt; DateTime(2000,
2, 28)));&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt; 8: &lt;/span&gt; }&lt;/pre&gt;
&lt;/div&gt;
&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }
&lt;/style&gt;
&lt;img width="0" height="0" src="http://www.felicepollano.com/aggbug.ashx?id=982dfdf2-cec1-462b-b160-0f8876ce7958" /&gt;</description>
      <comments>http://www.felicepollano.com/CommentView.aspx?guid=982dfdf2-cec1-462b-b160-0f8876ce7958</comments>
      <category>Cron</category>
      <category>Programmin</category>
      <category>Recipes</category>
    </item>
  </channel>
</rss>