<?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: Nishant Shaligram</title>
    <description>The latest articles on DEV Community by Nishant Shaligram (@nishant_shaligram).</description>
    <link>https://dev.to/nishant_shaligram</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.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4119772%2F39b5e562-9625-4a11-b009-b836efad21b4.png</url>
      <title>DEV Community: Nishant Shaligram</title>
      <link>https://dev.to/nishant_shaligram</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/nishant_shaligram"/>
    <language>en</language>
    <item>
      <title>Building a Dynamic Tax &amp; Account Code Validation Engine for Financial Data Pipelines</title>
      <dc:creator>Nishant Shaligram</dc:creator>
      <pubDate>Sat, 24 Oct 2026 04:00:00 +0000</pubDate>
      <link>https://dev.to/nishant_shaligram/building-a-dynamic-tax-account-code-validation-engine-for-financial-data-pipelines-23nh</link>
      <guid>https://dev.to/nishant_shaligram/building-a-dynamic-tax-account-code-validation-engine-for-financial-data-pipelines-23nh</guid>
      <description>&lt;p&gt;When you're building software that interfaces with financial systems like Xero, schema validation is only half the battle. You can parse CSV syntax and format dates all day long, but your pipeline will still fail if the business logic layer encounters an unverified tax rate or a missing ledger account code.&lt;/p&gt;

&lt;p&gt;In this post, let's look at how we architected a robust validation and mapping layer for &lt;strong&gt;&lt;a href="https://sync2zero.com" rel="noopener noreferrer"&gt;Sync2Zero&lt;/a&gt;&lt;/strong&gt; to catch tax rate mismatches and account code errors &lt;em&gt;before&lt;/em&gt; files hit accounting software ingestion gates.&lt;/p&gt;




&lt;h3&gt;
  
  
  The Problem: Strict Financial Taxonomy Validation
&lt;/h3&gt;

&lt;p&gt;When users upload supplier invoices or generate CSV exports, software platforms enforce rigid foreign-key-style constraints on text fields. If a user inputs a custom string for a tax rate or account code that doesn't exist in their target Xero organization, the platform rejects the payload.&lt;/p&gt;

&lt;p&gt;Common edge cases that break production imports include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Unrecognized Tax Strings:&lt;/strong&gt; Mismatched casing, shorthand abbreviations, or regional tax variances (&lt;code&gt;20% (VAT)&lt;/code&gt; vs &lt;code&gt;Standard Rate&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Orphaned Account Codes:&lt;/strong&gt; Line items referencing ledger codes that haven't been provisioned in the organization's chart of accounts.&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  Implementing a Pre-Flight Validation Layer
&lt;/h3&gt;

&lt;p&gt;To prevent runtime failures during bulk imports, we implemented a pre-flight validation check that inspects and normalizes ledger mappings against organization schemas:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;TaxMappingRule&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;alias&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[];&lt;/span&gt;
  &lt;span class="nl"&gt;officialCode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;SUPPORTED_TAX_MAPS&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;TaxMappingRule&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;alias&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;vat&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;20% vat&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;standard vat&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="na"&gt;officialCode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;OUTPUT20&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;alias&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;zero rated&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;0% vat&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;exempt&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="na"&gt;officialCode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;EXEMPT&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;resolveTaxCode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rawInput&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;normalized&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;rawInput&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;trim&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;toLowerCase&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;match&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;SUPPORTED_TAX_MAPS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rule&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;rule&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;alias&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;normalized&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;match&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Unrecognized tax code identifier: "&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;rawInput&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;". Please verify your chart of accounts.`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;match&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;officialCode&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  1. Alias Matching &amp;amp; Normalization
&lt;/h4&gt;

&lt;p&gt;Instead of letting raw user strings pass through to the parser, our ingestion layer normalizes input strings and matches them against known regional tax aliases.&lt;/p&gt;

&lt;h4&gt;
  
  
  2. Hard Stop Warnings
&lt;/h4&gt;

&lt;p&gt;If a tax code or account code fails lookup resolution, the engine halts the export, flagging the exact row and column for the user to review in the dashboard UI rather than failing silently inside Xero.&lt;/p&gt;




&lt;h3&gt;
  
  
  Wrapping Up
&lt;/h3&gt;

&lt;p&gt;Building developer tools in the fintech space means designing systems that anticipate human data entry inconsistencies. Handling tax and account code mapping gracefully is key to high-conversion SaaS workflows.&lt;/p&gt;

&lt;p&gt;If you're building document parsers or invoice automation pipelines, check out what we're building at &lt;strong&gt;&lt;a href="https://sync2zero.com" rel="noopener noreferrer"&gt;sync2zero.com&lt;/a&gt;&lt;/strong&gt;. I'd love to hear how your teams handle taxonomy mapping in the comments!&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>typescript</category>
      <category>node</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Engineering a Resilient CSV Parsing &amp; Normalization Layer for Accounting Integrations</title>
      <dc:creator>Nishant Shaligram</dc:creator>
      <pubDate>Fri, 11 Sep 2026 04:00:00 +0000</pubDate>
      <link>https://dev.to/nishant_shaligram/engineering-a-resilient-csv-parsing-normalization-layer-for-accounting-integrations-3nj6</link>
      <guid>https://dev.to/nishant_shaligram/engineering-a-resilient-csv-parsing-normalization-layer-for-accounting-integrations-3nj6</guid>
      <description>&lt;h1&gt;
  
  
  Engineering a Resilient CSV Parsing &amp;amp; Normalization Layer for Accounting Integrations
&lt;/h1&gt;

&lt;p&gt;Building apps that connect to accounting software often seems simple at first.. Once you get to the data ingestion layer things get complicated. Financial platforms like Xero have unforgiving rules for CSV imports. If your data doesn’t match their expected schema— down to the smallest detail—your ingestion pipeline throws errors.. These errors are usually hard to understand.&lt;/p&gt;

&lt;p&gt;In this post I want to share how we built the data normalization and validation system at Sync2Zero. We made it to handle user inputs, date format differences across regions and the way Microsoft Excel changes data when you open and save files.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Problem: Why Standard CSV Parsers Fail in Finance
&lt;/h2&gt;

&lt;p&gt;When you build tools that take in spreadsheet data or export files for accounting systems standard CSV parsers like csv-parse or papaparse do the job of reading the file structure.. They don’t handle human errors or spreadsheet issues.&lt;/p&gt;

&lt;p&gt;The common problems that break systems in production include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;UTF-8 BOM (Byte Order Mark):&lt;/strong&gt; Some desktop apps add a hidden EF BB BF sequence at the start of the file. This breaks the parser when it tries to match the header field like &lt;code&gt;*ContactName&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Leading Zero Stripping:&lt;/strong&gt; Spreadsheet software treats numbers like account codes (example: &lt;code&gt;0400&lt;/code&gt; or &lt;code&gt;0021&lt;/code&gt;) as numbers. It removes the leading zeros. That breaks the account references in the ledger.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Regional Date Collisions:&lt;/strong&gt; Even if you use ISO format (&lt;code&gt;YYYY-MM-DD&lt;/code&gt;) files can still have issues. Regional formats like &lt;code&gt;DD/MM/YYYY&lt;/code&gt; get flipped when opened on operating systems.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Designing a Bulletproof Normalization Pipeline
&lt;/h2&gt;

&lt;p&gt;To make our ingestion engine work reliably we built a -stage preprocessing system. This runs before any mapping or exporting happens.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Conceptual schema validation pass for Xero CSV imports&lt;/span&gt;

&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;XeroBillRow&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;ContactName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;InvoiceNumber&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;InvoiceDate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Must strictly match regional settings&lt;/span&gt;
  &lt;span class="nl"&gt;DueDate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;Total&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;AccountCode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Must retain leading zeros as strings&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;sanitizeAndNormalizeRow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rawRow&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Record&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;XeroBillRow&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;ContactName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;sanitizeString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rawRow&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ContactName&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="na"&gt;InvoiceNumber&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;sanitizeString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rawRow&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;InvoiceNumber&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="na"&gt;InvoiceDate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;normalizeDateFormat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rawRow&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;InvoiceDate&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="na"&gt;DueDate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;normalizeDateFormat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rawRow&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;DueDate&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="na"&gt;Total&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;parseFloat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rawRow&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Total&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="mf"&gt;0.00&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;AccountCode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rawRow&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;AccountCode&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;padStart&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;0&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// Prevent leading zero stripping&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  1. Stripping Byte Order Marks (BOM)
&lt;/h3&gt;

&lt;p&gt;Before parsing our system checks for a UTF-8 BOM at the start of the file. If it finds one it removes it immediately. This ensures that column names like &lt;code&gt;*ContactName&lt;/code&gt; are matched correctly and don’t fail.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Enforcing String Types on Numeric Codes
&lt;/h3&gt;

&lt;p&gt;Account codes and tracking categories are stored as strings. We enforce zero-padding to make sure the leading zeros never get removed. That keeps the account codes valid and readable.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Automated Date Normalization
&lt;/h3&gt;

&lt;p&gt;Of letting the system fail because of regional date differences we check the target Xero organization’s date settings. Then we convert the date strings into the format they need. This way the data stays accurate across regions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrapping Up
&lt;/h2&gt;

&lt;p&gt;Building tools in fintech or accounting shows you something developer experience isn’t just about clean APIs. It’s about making software that can handle real-world messiness.&lt;/p&gt;

&lt;p&gt;If you’re curious about how we extract data from PDFs using AI and generate CSV files take a look, at &lt;a href="https://sync2zero.com" rel="noopener noreferrer"&gt;Sync2Zero&lt;/a&gt;. I’d love to hear how other developers deal with data ingestion challenges. Leave a comment below.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>webdev</category>
      <category>productivity</category>
      <category>sass</category>
    </item>
  </channel>
</rss>
