<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Ben Villalobos</title>
    <description>The latest articles on DEV Community by Ben Villalobos (@benvillalobos).</description>
    <link>https://dev.to/benvillalobos</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F617711%2F41474b77-ae0a-4a88-a792-52987811eb47.jpeg</url>
      <title>DEV Community: Ben Villalobos</title>
      <link>https://dev.to/benvillalobos</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/benvillalobos"/>
    <language>en</language>
    <item>
      <title>Platform vs. PlatformTarget In Any .NET Build</title>
      <dc:creator>Ben Villalobos</dc:creator>
      <pubDate>Thu, 23 Sep 2021 01:37:31 +0000</pubDate>
      <link>https://dev.to/benvillalobos/platform-vs-platformtarget-in-any-net-build-252b</link>
      <guid>https://dev.to/benvillalobos/platform-vs-platformtarget-in-any-net-build-252b</guid>
      <description>&lt;p&gt;In any given .NET build, you might notice two properties that effectively have the same meaning, &lt;code&gt;Platform&lt;/code&gt; and &lt;code&gt;PlatformTarget&lt;/code&gt;. But what the heck is the difference between the two, and why does &lt;code&gt;PlatformTarget&lt;/code&gt; exist? Let’s go on this journey together.&lt;/p&gt;

&lt;p&gt;First of all, &lt;code&gt;PlatformTarget&lt;/code&gt; is important because it’s passed to the compiler (among other important tasks) in &lt;code&gt;Microsoft.Common.CurrentVersion.targets&lt;/code&gt; but that file does not define &lt;code&gt;PlatformTarget&lt;/code&gt;. Weird, right? &lt;code&gt;PlatformTarget&lt;/code&gt; being passed to these tasks has existed for 5+ years now, so &lt;code&gt;PlatformTarget&lt;/code&gt; isn’t a “recent” concept. It is, however, defined in any .NET Framework project file. The fact that it’s defined in these older projects (based on &lt;code&gt;Configuration|Platform&lt;/code&gt;) proves that it needs to be defined either in the project, or in some props/targets file before the &lt;code&gt;CoreCompile&lt;/code&gt; target runs (from the Roslyn targets).&lt;/p&gt;

&lt;p&gt;This answers how &lt;code&gt;PlatformTarget&lt;/code&gt; is set &amp;amp; used in legacy-style projects: &lt;code&gt;PlatformTarget&lt;/code&gt; is defined to a specific value when building under a particular &lt;code&gt;Configuration|Platform&lt;/code&gt;. It is then passed to the compiler and so on.&lt;/p&gt;

&lt;p&gt;This answers how &lt;code&gt;PlatformTarget&lt;/code&gt; is set &amp;amp; used in legacy-style projects: &lt;code&gt;PlatformTarget&lt;/code&gt; is defined to a specific value when building under a particular &lt;code&gt;Configuration|Platform&lt;/code&gt;. It is then passed to the compiler and so on.&lt;/p&gt;

&lt;p&gt;What about sdk-style projects?&lt;/p&gt;

&lt;p&gt;I found this in &lt;code&gt;Microsoft.NET.Sdk.props&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;* We cannot just set $(PlatformTarget) to $(Platform) here because $(Platform) can be set to anything
       at the solution level, but there are a fixed set valid $(PlatformTarget) values that can be passed
       to the compiler. It is up to the user to explicitly set PlatformTarget to non-AnyCPU (if desired)
       outside the 1:1 defaults below.
  --&amp;gt;
  &lt;span class="nt"&gt;&amp;lt;PropertyGroup&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;_PlatformWithoutConfigurationInference&amp;gt;&lt;/span&gt;$(Platform)&lt;span class="nt"&gt;&amp;lt;/_PlatformWithoutConfigurationInference&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/PropertyGroup&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;PropertyGroup&lt;/span&gt; &lt;span class="na"&gt;Condition=&lt;/span&gt;&lt;span class="s"&gt;" '$(_PlatformWithoutConfigurationInference)' == 'x64' "&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;PlatformTarget&lt;/span&gt; &lt;span class="na"&gt;Condition=&lt;/span&gt;&lt;span class="s"&gt;" '$(PlatformTarget)' == '' "&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;x64&lt;span class="nt"&gt;&amp;lt;/PlatformTarget&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/PropertyGroup&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;PropertyGroup&lt;/span&gt; &lt;span class="na"&gt;Condition=&lt;/span&gt;&lt;span class="s"&gt;" '$(_PlatformWithoutConfigurationInference)' == 'x86' "&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;PlatformTarget&lt;/span&gt; &lt;span class="na"&gt;Condition=&lt;/span&gt;&lt;span class="s"&gt;" '$(PlatformTarget)' == '' "&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;x86&lt;span class="nt"&gt;&amp;lt;/PlatformTarget&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/PropertyGroup&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;PropertyGroup&lt;/span&gt; &lt;span class="na"&gt;Condition=&lt;/span&gt;&lt;span class="s"&gt;" '$(_PlatformWithoutConfigurationInference)' == 'ARM' "&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;PlatformTarget&lt;/span&gt; &lt;span class="na"&gt;Condition=&lt;/span&gt;&lt;span class="s"&gt;" '$(PlatformTarget)' == '' "&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;ARM&lt;span class="nt"&gt;&amp;lt;/PlatformTarget&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/PropertyGroup&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It looks like &lt;code&gt;PlatformTarget&lt;/code&gt; is set based on &lt;code&gt;Platform&lt;/code&gt; when it doesn’t have a value already set, but doesn’t have a definition when &lt;code&gt;Platform&lt;/code&gt; is AnyCPU. So what happens when &lt;code&gt;Platform&lt;/code&gt; is &lt;code&gt;AnyCPU&lt;/code&gt;?&lt;/p&gt;

&lt;p&gt;The following snippet looks to answer my question. It defaults &lt;code&gt;PlatformTarget&lt;/code&gt; in &lt;code&gt;Microsoft.NET.RuntimeIdentifierInference.targets&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;! - Determine PlatformTarget (if not already set) from runtime identifier. →
 &amp;lt;Choose&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;When&lt;/span&gt; &lt;span class="na"&gt;Condition=&lt;/span&gt;&lt;span class="s"&gt;"'$(PlatformTarget)' != '' or '$(RuntimeIdentifier)' == ''"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;When&lt;/span&gt; &lt;span class="na"&gt;Condition=&lt;/span&gt;&lt;span class="s"&gt;"$(RuntimeIdentifier.EndsWith('-x86')) or $(RuntimeIdentifier.Contains('-x86-'))"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;PropertyGroup&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;PlatformTarget&amp;gt;&lt;/span&gt;x86&lt;span class="nt"&gt;&amp;lt;/PlatformTarget&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/PropertyGroup&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/When&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;When&lt;/span&gt; &lt;span class="na"&gt;Condition=&lt;/span&gt;&lt;span class="s"&gt;"$(RuntimeIdentifier.EndsWith('-x64')) or $(RuntimeIdentifier.Contains('-x64-'))"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;PropertyGroup&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;PlatformTarget&amp;gt;&lt;/span&gt;x64&lt;span class="nt"&gt;&amp;lt;/PlatformTarget&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/PropertyGroup&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/When&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;When&lt;/span&gt; &lt;span class="na"&gt;Condition=&lt;/span&gt;&lt;span class="s"&gt;"$(RuntimeIdentifier.EndsWith('-arm')) or $(RuntimeIdentifier.Contains('-arm-'))"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;PropertyGroup&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;PlatformTarget&amp;gt;&lt;/span&gt;arm&lt;span class="nt"&gt;&amp;lt;/PlatformTarget&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/PropertyGroup&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/When&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;When&lt;/span&gt; &lt;span class="na"&gt;Condition=&lt;/span&gt;&lt;span class="s"&gt;"$(RuntimeIdentifier.EndsWith('-arm64')) or $(RuntimeIdentifier.Contains('-arm64-'))"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;PropertyGroup&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;PlatformTarget&amp;gt;&lt;/span&gt;arm64&lt;span class="nt"&gt;&amp;lt;/PlatformTarget&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/PropertyGroup&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/When&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;Otherwise&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;PropertyGroup&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;PlatformTarget&amp;gt;&lt;/span&gt;AnyCPU&lt;span class="nt"&gt;&amp;lt;/PlatformTarget&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/PropertyGroup&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/Otherwise&amp;gt;&lt;/span&gt;
 &lt;span class="nt"&gt;&amp;lt;/Choose&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;PlatformTarget&lt;/code&gt; appears to be set here (if not already set) based off of the RuntimeIdentifier. And to confirm that this all happens before &lt;code&gt;M.C.CV.targets&lt;/code&gt;, see the order of imports:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--tuDHcGaL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/4691428/134433824-b8c1b915-acc2-4739-a47b-1880db47ef8f.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--tuDHcGaL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/4691428/134433824-b8c1b915-acc2-4739-a47b-1880db47ef8f.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So we know now that &lt;code&gt;PlatformTarget&lt;/code&gt; is defined in the sdk in both &lt;code&gt;Microsoft.NET.Sdk.props&lt;/code&gt; and &lt;code&gt;Microsoft.NET.RuntimeIdentifierInference.targets&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This answers my question for sdk-style projects: &lt;code&gt;PlatformTarget&lt;/code&gt; is defined based on specific values of Platform and &lt;code&gt;RuntimeIdentifier&lt;/code&gt;. And defaulted to AnyCPU when &lt;code&gt;Platform&lt;/code&gt; isn’t a predetermined value, or it couldn’t be parsed from the RID.&lt;/p&gt;

&lt;h3&gt;
  
  
  TL;DR
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;PlatformTarget&lt;/code&gt; is derived from &lt;code&gt;Platform&lt;/code&gt; in a .NET Framework project file when &lt;code&gt;Platform&lt;/code&gt; falls under a set of predetermined values. Otherwise it’s defined in the .NET Sdk based on &lt;code&gt;Platform&lt;/code&gt; or &lt;code&gt;RuntimeIdentifier&lt;/code&gt;.&lt;/p&gt;

</description>
      <category>msbuild</category>
      <category>dotnet</category>
      <category>csharp</category>
      <category>netcore</category>
    </item>
    <item>
      <title>Stop Windows Defender From Scanning Your Source Code</title>
      <dc:creator>Ben Villalobos</dc:creator>
      <pubDate>Fri, 30 Apr 2021 01:22:17 +0000</pubDate>
      <link>https://dev.to/benvillalobos/stop-windows-defender-from-scanning-your-source-code-26n3</link>
      <guid>https://dev.to/benvillalobos/stop-windows-defender-from-scanning-your-source-code-26n3</guid>
      <description>&lt;p&gt;I was fortunate enough to receive a laptop for development work during quarantine. It works well so far except for one important issue, development work is slow! Turns out it can be difficult to program when the simple act of running visual studio grinds the machine down to a halt. At first I thought it was VS itself, until I opened up the task manager and saw the nightmare pictured below:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--TKpEAz8t--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/whssjreqn99qk3m8po1j.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--TKpEAz8t--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/whssjreqn99qk3m8po1j.jpg" alt="defender-scanning-01"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;The root of this problem turned out to be Defender scanning my &lt;code&gt;c:/src&lt;/code&gt; folder. Y'know, the folder that contains dozens of repositories and tens of thousands of files, many of which containing tens of thousands of lines of text?&lt;/p&gt;

&lt;p&gt;"Great!" I thought, "Can I even get around this?" Work computers generally have strict policies to keep them well protected. After attempting to get Defender to ignore my source folder to no avail, I did the next best thing: I grumbled to coworkers hoping they knew of a workaround. Turns out, they did! I was sent &lt;a href="https://docs.microsoft.com/en-us/windows/security/threat-protection/microsoft-defender-antivirus/configure-extension-file-exclusions-microsoft-defender-antivirus#use-group-policy-to-configure-folder-or-file-extension-exclusions"&gt;this handy guide&lt;/a&gt; that resolved my issue. Note that you'll need admin privileges to do this. Obligatory: You're responsible for whatever you do with your PC.&lt;/p&gt;

&lt;p&gt;The steps from the guide are as follows: In windows search, find and open "Edit Group Policy." Now navigate to Computer Configuration → Administrative Templates → Windows Components → Microsoft Defender Antivirus → Exclusions. Enable it then click "Show" next to Path Exclusions. Add a path under &lt;code&gt;Value Name&lt;/code&gt; and set &lt;code&gt;0&lt;/code&gt; as its value. I've added &lt;code&gt;C:/src&lt;/code&gt; to ignore all source code on my machine.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--R-QF6QTJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/a6221i1sx0a5v3f6d27a.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--R-QF6QTJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/a6221i1sx0a5v3f6d27a.png" alt="defender-scanning-02"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;It's been about a month since I've made this change and Defender no longer chokeholds my laptop during dev work. Now about Teams...&lt;/p&gt;

</description>
      <category>windowsdefender</category>
      <category>guides</category>
      <category>windows</category>
    </item>
    <item>
      <title>Clean &amp; Speed Up Your Local Git Repo With Three Commands</title>
      <dc:creator>Ben Villalobos</dc:creator>
      <pubDate>Tue, 20 Apr 2021 08:27:37 +0000</pubDate>
      <link>https://dev.to/benvillalobos/clean-speed-up-your-local-git-repo-with-three-commands-5dnd</link>
      <guid>https://dev.to/benvillalobos/clean-speed-up-your-local-git-repo-with-three-commands-5dnd</guid>
      <description>&lt;p&gt;Sometimes ya gotta force push or rebase and leave some commits behind. On a large repo with many commits and remotes, your git commands could actually slow down with too many objects floating around. Consider running these commands to help keep things in tip top shape.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://git-scm.com/docs/git-gc"&gt;git gc&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Compresses and removes orphaned objects, thus speeding up commands in your local repo. Nice!&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--1GsKiZwq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cb5hr4zezeppwg87c6s8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--1GsKiZwq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cb5hr4zezeppwg87c6s8.png" alt="image"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://git-scm.com/docs/git-fsck"&gt;git fsck&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Yes, I misread that too. &lt;code&gt;git fsck&lt;/code&gt; shows you all orphan or dangling objects in your local repo. I cleaned up recently so mine isn't too bad.&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--7YtCXTk7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3i5l2hitr5xw5u6sn0dv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--7YtCXTk7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3i5l2hitr5xw5u6sn0dv.png" alt="image"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://git-scm.com/docs/git-prune"&gt;git prune&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;If you don't plan on doing anything with the objects you saw using fsck, run &lt;code&gt;git prune&lt;/code&gt; to clear them out. If you'd like to see what would be cleaned out without actually deleting them, run &lt;code&gt;git prune -n&lt;/code&gt; for a dry-run.&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--uqXKNzVK--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/evk0n3wrxhjgtajsbmtk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--uqXKNzVK--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/evk0n3wrxhjgtajsbmtk.png" alt="image"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In theory, cleanup happens somewhat regularly when running some of git's main commands. I haven't noticed, or is it just good at its job. In any case, I hope this helped!&lt;/p&gt;

&lt;p&gt;I learned about these commands from the amazing &lt;a href="https://github.com/pluralsight/git-internals-pdf"&gt;Git Internals pdf&lt;/a&gt;. Every dev should read it.&lt;/p&gt;

</description>
      <category>git</category>
      <category>github</category>
      <category>productivity</category>
      <category>tips</category>
    </item>
  </channel>
</rss>
