<?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: Samy</title>
    <description>The latest articles on DEV Community by Samy (@samymassoud).</description>
    <link>https://dev.to/samymassoud</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%2F539438%2F48dc926a-74a0-4cb7-b292-3c737bad479a.jpeg</url>
      <title>DEV Community: Samy</title>
      <link>https://dev.to/samymassoud</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/samymassoud"/>
    <language>en</language>
    <item>
      <title>The Bits Inside a MAC Address (and What They Actually Tell You)</title>
      <dc:creator>Samy</dc:creator>
      <pubDate>Wed, 26 Aug 2026 04:35:26 +0000</pubDate>
      <link>https://dev.to/samymassoud/the-bits-inside-a-mac-address-and-what-they-actually-tell-you-45gm</link>
      <guid>https://dev.to/samymassoud/the-bits-inside-a-mac-address-and-what-they-actually-tell-you-45gm</guid>
      <description>&lt;p&gt;A MAC address looks like a random string of hex pairs, but it's not random at all. Every byte is doing a specific job, and once you know how to read them, a MAC address will tell you a surprising amount: who made the hardware, whether the address is even real, and how your OS derives an IPv6 address from it. Here's the breakdown, with a bit of Python to make it concrete.&lt;/p&gt;

&lt;h2&gt;
  
  
  The 48 bits
&lt;/h2&gt;

&lt;p&gt;A MAC address is 6 bytes (48 bits), usually written as 6 hex pairs: &lt;code&gt;00:03:93:AB:12:34&lt;/code&gt;. It splits into two halves:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Bytes 1-3 (the OUI)&lt;/strong&gt;: assigned by the IEEE Registration Authority to a specific organization&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Bytes 4-6&lt;/strong&gt;: assigned by that organization to a specific device, however it wants&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That's the theory, anyway. The two low-order bits of the very first byte break that clean split, and they're the most useful bits in the whole address.&lt;/p&gt;

&lt;h2&gt;
  
  
  The two bits that matter
&lt;/h2&gt;

&lt;p&gt;Look at the first byte in binary. The two least significant bits are flags, not part of any vendor identifier:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;I/G bit&lt;/strong&gt; (bit 0): 0 means unicast (one device), 1 means multicast (a group)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;U/L bit&lt;/strong&gt; (bit 1): 0 means universally administered (globally unique, IEEE-assigned), 1 means locally administered (made up on the spot, not guaranteed unique)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In Python:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;mac_flags&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mac&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;first_byte&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mac&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;:&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="mi"&gt;16&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;unicast&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="nf"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;first_byte&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="mb"&gt;0b0000_0001&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;universally_administered&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="nf"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;first_byte&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="mb"&gt;0b0000_0010&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nf"&gt;mac_flags&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;00:03:93:AB:12:34&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;# {'unicast': True, 'universally_administered': True}
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the U/L bit is set, don't bother looking up the OUI. There's no vendor to find. The address was generated locally, not assigned by the IEEE.&lt;/p&gt;

&lt;h2&gt;
  
  
  OUI, MA-M, MA-S, IAB, CID: the registry blocks
&lt;/h2&gt;

&lt;p&gt;"OUI" is the term everyone uses, but the IEEE Registration Authority actually issues five different kinds of blocks, and they matter if you're trying to figure out how big or how new a registration is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;MA-L&lt;/strong&gt; (MAC Address Block Large, the classic OUI): a 24-bit prefix, 16,777,216 addresses&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;MA-M&lt;/strong&gt; (Medium): a 28-bit prefix, 1,048,576 addresses&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;MA-S&lt;/strong&gt; (Small, replaced the old OUI-36): a 36-bit prefix, 4,096 addresses&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;IAB&lt;/strong&gt; (Individual Address Block): deprecated in 2014, replaced by MA-S, but still shows up in old hardware&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CID&lt;/strong&gt; (Company ID): same registry, same format, but explicitly not for building MAC addresses, used for protocol identifiers instead&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A vendor with a single IoT product line will often hold an MA-S block instead of a full MA-L, because 4,096 addresses is plenty and it's cheaper to register. If a lookup tool just says "OUI" for everything, you're losing that signal.&lt;/p&gt;

&lt;h2&gt;
  
  
  Randomization broke the "MAC = device" assumption
&lt;/h2&gt;

&lt;p&gt;For a long time, "look up the OUI" was a reasonable way to answer "what kind of device is this." Then iOS 14, and most modern Android and desktop Wi-Fi stacks, started randomizing the MAC address per network (and sometimes per connection), specifically to stop this kind of tracking.&lt;/p&gt;

&lt;p&gt;A randomized address almost always has the U/L bit set, which is exactly the bit from the flags above. So the same one-bit check that tells you "this isn't a registered vendor address" is also your best signal that you're looking at a randomized address, not a spoofed or malformed one. It's not a certainty (some real hardware legitimately uses locally administered addresses too), but it's a solid prior.&lt;/p&gt;

&lt;h2&gt;
  
  
  Deriving an EUI-64 / IPv6 link-local address
&lt;/h2&gt;

&lt;p&gt;If you've ever wondered how an interface without DHCPv6 still gets an IPv6 address, this is how, at least under SLAAC with the (now largely deprecated but still common) modified EUI-64 method:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Split the 48-bit MAC into two 24-bit halves&lt;/li&gt;
&lt;li&gt;Insert &lt;code&gt;FFFE&lt;/code&gt; between them, making it 64 bits&lt;/li&gt;
&lt;li&gt;Flip the U/L bit of the first byte
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;00:03:93:AB:12:34
to 00:03:93:FF:FE:AB:12:34   (insert FFFE)
to 02:03:93:FF:FE:AB:12:34   (flip the U/L bit: 0x00 to 0x02)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That becomes the interface identifier, appended to &lt;code&gt;fe80::/64&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;fe80::0203:93ff:feab:1234
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Same input, same deterministic output, every time. That's also exactly why privacy extensions (RFC 4941) exist: a stable EUI-64-derived address is as trackable as the MAC it came from.&lt;/p&gt;

&lt;h2&gt;
  
  
  Putting it together
&lt;/h2&gt;

&lt;p&gt;None of this requires a database. U/L bit, I/G bit, and EUI-64 derivation are pure bit math, no registry lookup needed. Where you do need a database is the vendor name itself, and that part changes: the IEEE adds and reassigns blocks continuously, so a hardcoded vendor table goes stale. For quick one-offs I usually just query a synced OUI database (I've been using &lt;a href="https://macadress.com" rel="noopener noreferrer"&gt;macadress.com&lt;/a&gt;'s API for this) rather than maintaining my own copy of the registry.&lt;/p&gt;

&lt;p&gt;If you want to try the bit math yourself, any MAC address will do, even a locally administered one will confirm the flags are working correctly, since it'll come back "not universally administered" instead of throwing a vendor name at you.&lt;/p&gt;

</description>
      <category>networking</category>
      <category>python</category>
      <category>security</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Build a Daily Tech-News Bot for Slack or Discord in 15 Minutes (Node.js + NewTqnia API)</title>
      <dc:creator>Samy</dc:creator>
      <pubDate>Mon, 17 Aug 2026 19:29:49 +0000</pubDate>
      <link>https://dev.to/samymassoud/build-a-daily-tech-news-bot-for-slack-or-discord-in-15-minutes-nodejs-newtqnia-api-5gmp</link>
      <guid>https://dev.to/samymassoud/build-a-daily-tech-news-bot-for-slack-or-discord-in-15-minutes-nodejs-newtqnia-api-5gmp</guid>
      <description>&lt;p&gt;Every team I've been on has a #general channel that goes quiet by 11am. A daily digest bot is the easiest way to give people a reason to glance back at it, and "today's tech headlines" is a low-effort, high-signal thing to post that nobody minds seeing every morning.&lt;/p&gt;

&lt;p&gt;Here's a complete Slack/Discord bot, built on &lt;a href="https://newtqnia.com" rel="noopener noreferrer"&gt;NewTqnia&lt;/a&gt;'s free public news API, that you can have running in about 15 minutes.&lt;/p&gt;

&lt;h2&gt;
  
  
  What we're building
&lt;/h2&gt;

&lt;p&gt;A small Node script that:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Fetches today's tech headlines (AI, robotics, space, health, energy, and a few other beats) from NewTqnia's API&lt;/li&gt;
&lt;li&gt;Formats them as a Slack or Discord message&lt;/li&gt;
&lt;li&gt;Posts them to a webhook&lt;/li&gt;
&lt;li&gt;Runs on a schedule via GitHub Actions, so there's no server to keep alive&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Step 1: Install the SDK
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install &lt;/span&gt;newtqnia-node
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It's a small, typed client around NewTqnia's REST API. No API key is required for this.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2: The script
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// digest-bot.mjs&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;NewTqniaClient&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;newtqnia-node&lt;/span&gt;&lt;span class="dl"&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;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;NewTqniaClient&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;application&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;tech-news-digest-bot&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getDigest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;locale&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;en&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;limit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// "today" can be empty early in the day (it resets on the Asia/Dubai&lt;/span&gt;
  &lt;span class="c1"&gt;// boundary), so fall back to "latest" if there's nothing yet.&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;today&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;news&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;today&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;locale&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;limit&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="nx"&gt;today&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;articles&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&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;today&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;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;news&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;latest&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;locale&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;limit&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;toDiscordPayload&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;digest&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;lines&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;digest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;articles&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;`• [&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;](&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;)`&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="dl"&gt;"&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;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`**Today in Tech, via [NewTqnia](&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;digest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;publisher&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;)**\n\n&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;lines&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&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;toSlackPayload&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;digest&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;lines&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;digest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;articles&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;`• &amp;lt;&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;|&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;gt;`&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="dl"&gt;"&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;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`*Today in Tech, via &amp;lt;&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;digest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;publisher&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;|NewTqnia&amp;gt;*\n\n&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;lines&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;postDigest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;webhookUrl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;kind&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;discord&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;locale&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;en&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;const&lt;/span&gt; &lt;span class="nx"&gt;digest&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;getDigest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;locale&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;payload&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;kind&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;slack&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nf"&gt;toSlackPayload&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;digest&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;toDiscordPayload&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;digest&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;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;webhookUrl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;headers&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="s2"&gt;Content-Type&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="s2"&gt;application/json&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;),&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;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ok&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;`Webhook post failed: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;text&lt;/span&gt;&lt;span class="p"&gt;()}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&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;const&lt;/span&gt; &lt;span class="nx"&gt;webhookUrl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;DISCORD_WEBHOOK_URL&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;SLACK_WEBHOOK_URL&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;kind&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;SLACK_WEBHOOK_URL&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;slack&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="s2"&gt;discord&lt;/span&gt;&lt;span class="dl"&gt;"&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;webhookUrl&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Set DISCORD_WEBHOOK_URL or SLACK_WEBHOOK_URL&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nf"&gt;postDigest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;webhookUrl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;kind&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&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;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&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;p&gt;A couple of things worth calling out:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;today&lt;/code&gt; vs &lt;code&gt;latest&lt;/code&gt;&lt;/strong&gt;: NewTqnia's &lt;code&gt;today&lt;/code&gt; endpoint resets on the &lt;em&gt;Asia/Dubai&lt;/em&gt; day boundary and can legitimately return an empty array if nothing's published yet when your job runs. Falling back to &lt;code&gt;latest&lt;/code&gt; avoids posting an empty digest.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Attribution&lt;/strong&gt;: NewTqnia's API terms ask that you keep a visible link back when you display its content and preserve the article URLs it returns. Both formatters above do that by linking the publisher name, so you get this right by default rather than as an afterthought.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Step 3: Get a webhook URL
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Discord&lt;/strong&gt;: Server Settings &amp;gt; Integrations &amp;gt; Webhooks &amp;gt; New Webhook &amp;gt; copy the URL.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Slack&lt;/strong&gt;: create an &lt;a href="https://api.slack.com/messaging/webhooks" rel="noopener noreferrer"&gt;Incoming Webhook&lt;/a&gt; for the channel you want and copy the URL it gives you.&lt;/p&gt;

&lt;p&gt;Test locally:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;DISCORD_WEBHOOK_URL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"https://discord.com/api/webhooks/..."&lt;/span&gt; node digest-bot.mjs
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 4: Run it on a schedule, for free
&lt;/h2&gt;

&lt;p&gt;No server needed. A scheduled GitHub Action does the job:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# .github/workflows/digest.yml&lt;/span&gt;
&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Post daily tech digest&lt;/span&gt;
&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;schedule&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;cron&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;0&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;6&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;*&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;*&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;*"&lt;/span&gt; &lt;span class="c1"&gt;# 06:00 UTC daily, adjust to your team's morning&lt;/span&gt;
  &lt;span class="na"&gt;workflow_dispatch&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{}&lt;/span&gt;

&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;post&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v4&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/setup-node@v4&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;node-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;20&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm install newtqnia-node&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;node digest-bot.mjs&lt;/span&gt;
        &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;DISCORD_WEBHOOK_URL&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.DISCORD_WEBHOOK_URL }}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add &lt;code&gt;DISCORD_WEBHOOK_URL&lt;/code&gt; (or &lt;code&gt;SLACK_WEBHOOK_URL&lt;/code&gt;) as a repo secret, push, and you're done. &lt;code&gt;workflow_dispatch&lt;/code&gt; is there so you can trigger a test run by hand from the Actions tab instead of waiting for the cron.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where to take it from here
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Filter by beat with &lt;code&gt;category&lt;/code&gt; (e.g. &lt;code&gt;client.news.today({ category: "artificial-intelligence" })&lt;/code&gt;) if your team only wants AI news, not space and health too.&lt;/li&gt;
&lt;li&gt;Post in Arabic by passing &lt;code&gt;locale: "ar"&lt;/code&gt;. The API and SDK are bilingual by default.&lt;/li&gt;
&lt;li&gt;If you'd rather not run a script at all, NewTqnia also has a &lt;a href="https://newtqnia.com/en/widget" rel="noopener noreferrer"&gt;drop-in embeddable widget&lt;/a&gt; for putting the same feed directly on a webpage instead of a chat channel.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Full API reference and the PHP SDK are on the &lt;a href="https://newtqnia.com/en/developers" rel="noopener noreferrer"&gt;developer page&lt;/a&gt; if you want to build something more involved than a digest bot.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>node</category>
      <category>api</category>
      <category>automation</category>
    </item>
    <item>
      <title>Add Live Bilingual Tech News to Your Portfolio Site in One Line</title>
      <dc:creator>Samy</dc:creator>
      <pubDate>Sun, 02 Aug 2026 20:46:41 +0000</pubDate>
      <link>https://dev.to/samymassoud/add-live-bilingual-tech-news-to-your-portfolio-site-in-one-line-5co</link>
      <guid>https://dev.to/samymassoud/add-live-bilingual-tech-news-to-your-portfolio-site-in-one-line-5co</guid>
      <description>&lt;p&gt;Every portfolio site has the same problem: it's static. A grid of projects, a bio, a contact form — nothing on the page ever changes, which means nothing on the page proves you can work with live data. Recruiters and reviewers skim past it because there's nothing to skim.&lt;/p&gt;

&lt;p&gt;The fastest fix isn't building your own API — it's embedding someone else's, and picking one that's actually interesting to look at. Here's how to drop a live, auto-updating tech news feed into any site with a single script tag, using &lt;a href="https://newtqnia.com" rel="noopener noreferrer"&gt;NewTqnia&lt;/a&gt;, a bilingual (English/Arabic) tech newsroom with a free embeddable widget.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why this is a good portfolio move, not just decoration
&lt;/h2&gt;

&lt;p&gt;A static "About Me" page tells someone you can write HTML. A page with a live-updating feed tells them you can integrate a third-party service, handle async content, and think about internationalization (this one supports English and Arabic out of the box) — all real, hireable skills, for the cost of one script tag.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1: Build your embed
&lt;/h2&gt;

&lt;p&gt;Go to &lt;a href="https://newtqnia.com/en/widget" rel="noopener noreferrer"&gt;newtqnia.com/en/widget&lt;/a&gt;. It's a live configurator, not a docs page — every option you touch updates a preview instantly:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Content:&lt;/strong&gt; custom heading, number of articles, language (English or Arabic), category filter (Artificial Intelligence, Robotics, Space, Health, and others), and ordering (latest first or most popular)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Appearance:&lt;/strong&gt; card / list / compact layout, horizontal or vertical orientation, light / dark / automatic theme, accent color, and toggles for images and summaries
Pick settings that match your site — a compact, dark-themed, "Artificial Intelligence"-filtered list looks noticeably more intentional than the default.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Step 2: Copy the generated snippet
&lt;/h2&gt;

&lt;p&gt;Once you're happy with the preview, the page generates a ready-to-paste embed code block for you — copy it as-is. It'll look roughly like a single &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; tag referencing your chosen configuration, something like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;script
  &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://newtqnia.com/embed/widget.js"&lt;/span&gt;
  &lt;span class="na"&gt;data-lang=&lt;/span&gt;&lt;span class="s"&gt;"en"&lt;/span&gt;
  &lt;span class="na"&gt;data-category=&lt;/span&gt;&lt;span class="s"&gt;"artificial-intelligence"&lt;/span&gt;
  &lt;span class="na"&gt;data-count=&lt;/span&gt;&lt;span class="s"&gt;"5"&lt;/span&gt;
  &lt;span class="na"&gt;data-theme=&lt;/span&gt;&lt;span class="s"&gt;"dark"&lt;/span&gt;
  &lt;span class="na"&gt;async&lt;/span&gt;
&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;(Use the exact snippet the configurator gives you — it encodes the specific options you picked, so don't hand-type this one from memory.)&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3: Drop it into your site
&lt;/h2&gt;

&lt;p&gt;Paste the snippet wherever you want the feed to appear — a sidebar, a footer section, a dedicated "Now Reading" panel on your homepage. The widget renders inside an isolated Shadow DOM, so it won't inherit or clash with your site's existing CSS, and it won't leak its own styles back into your page either. That's one less thing to debug.&lt;/p&gt;

&lt;p&gt;One thing to check if your site enforces a Content Security Policy: you'll need to allow &lt;code&gt;newtqnia.com&lt;/code&gt; for &lt;code&gt;script-src&lt;/code&gt;, &lt;code&gt;connect-src&lt;/code&gt;, and &lt;code&gt;img-src&lt;/code&gt;, or the widget will silently fail to load.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 4: Make it yours
&lt;/h2&gt;

&lt;p&gt;A few ways to push this past "I copied a script tag":&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Toggle the language dynamically.&lt;/strong&gt; Add a small button on your page that swaps &lt;code&gt;data-lang&lt;/code&gt; between &lt;code&gt;en&lt;/code&gt; and &lt;code&gt;ar&lt;/code&gt; and re-mounts the widget — a tiny but real demonstration of handling i18n on the client.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Match it to your site's theme.&lt;/strong&gt; If you already have a dark-mode toggle, wire it to the widget's theme option so the feed switches with the rest of the page.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Filter by what you're into.&lt;/strong&gt; If your portfolio is robotics-focused, filter the widget to the Robotics category instead of leaving it on "All categories" — small detail, but it shows you're not just pasting boilerplate.
## Want to go further than the widget?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;NewTqnia also ships a public REST API with an OpenAPI 3.1 spec, official PHP and Node SDKs, and an MCP server for AI agents — worth a look at &lt;a href="https://newtqnia.com/en/developers" rel="noopener noreferrer"&gt;newtqnia.com/en/developers&lt;/a&gt; if you'd rather build your own feed UI from scratch instead of using the pre-built widget. That's a meaningfully bigger project, but a great follow-up once the one-line version is live.&lt;/p&gt;

&lt;p&gt;Either way, it's a five-minute change that turns a static portfolio into one with something actually happening on it.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>api</category>
      <category>backend</category>
      <category>webdev</category>
    </item>
    <item>
      <title>I Built a News API Before I Had Users. Here's What I'm Learning.</title>
      <dc:creator>Samy</dc:creator>
      <pubDate>Fri, 24 Jul 2026 04:44:01 +0000</pubDate>
      <link>https://dev.to/samymassoud/i-built-a-news-api-before-i-had-users-heres-what-im-learning-1206</link>
      <guid>https://dev.to/samymassoud/i-built-a-news-api-before-i-had-users-heres-what-im-learning-1206</guid>
      <description>&lt;p&gt;The API went live on a Tuesday. I had no idea who would use it.&lt;/p&gt;

&lt;p&gt;I was building &lt;a href="https://newtqnia.com/en" rel="noopener noreferrer"&gt;NewTqnia&lt;/a&gt;, a bilingual technology publication in English and Arabic, and the requirements kept expanding. Website, RSS, JSON API, embeddable widget, browser new-tab page, structured timelines—each one wanted the same content delivered differently.&lt;/p&gt;

&lt;p&gt;That raised a question I still don’t have a clean answer to:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How do you support six delivery surfaces without building six disconnected products?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This is not a success story. It’s a set of tradeoffs, some working, some questionable, and a few I’m actively looking to undo.&lt;/p&gt;




&lt;h2&gt;
  
  
  The API: small on purpose
&lt;/h2&gt;

&lt;p&gt;The first public version of the Daily Digest API does almost nothing.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="s2"&gt;"https://newtqnia.com/v1/news/today?locale=en&amp;amp;limit=5"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That’s it. &lt;code&gt;today&lt;/code&gt;, &lt;code&gt;latest&lt;/code&gt;, two query params, no API key. Sixty requests per minute, ETag support, sensible &lt;code&gt;Cache-Control&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;I could have shipped categories, tags, search, recommendations, and analytics endpoints on day one. But a large API with unstable contracts is just a private API that happens to have public documentation. I wanted the opposite: a small surface that would not embarrass me if someone actually built against it.&lt;/p&gt;

&lt;p&gt;The awkward part? Developers can’t ask for endpoints they don’t know are possible. So “wait for demand” is a safe strategy, but maybe not the &lt;em&gt;right&lt;/em&gt; one. I’m still figuring out where the line is between “prudently small” and “uselessly small.”&lt;/p&gt;




&lt;h2&gt;
  
  
  The widget problem: isolation is expensive
&lt;/h2&gt;

&lt;p&gt;Some people just want headlines on their site without writing HTTP clients. So I built a script:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;script
  &lt;/span&gt;&lt;span class="na"&gt;async&lt;/span&gt;
  &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://newtqnia.com/news-widget.js"&lt;/span&gt;
  &lt;span class="na"&gt;data-count=&lt;/span&gt;&lt;span class="s"&gt;"5"&lt;/span&gt;
  &lt;span class="na"&gt;data-locale=&lt;/span&gt;&lt;span class="s"&gt;"en"&lt;/span&gt;
  &lt;span class="na"&gt;data-layout=&lt;/span&gt;&lt;span class="s"&gt;"cards"&lt;/span&gt;
  &lt;span class="na"&gt;data-orientation=&lt;/span&gt;&lt;span class="s"&gt;"horizontal"&lt;/span&gt;
  &lt;span class="na"&gt;data-theme=&lt;/span&gt;&lt;span class="s"&gt;"auto"&lt;/span&gt;
  &lt;span class="na"&gt;data-accent=&lt;/span&gt;&lt;span class="s"&gt;"#03c0f9"&lt;/span&gt;
  &lt;span class="na"&gt;data-order=&lt;/span&gt;&lt;span class="s"&gt;"latest"&lt;/span&gt;
  &lt;span class="na"&gt;data-show-image=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt;
  &lt;span class="na"&gt;data-show-summary=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;a href="https://newtqnia.com/en/widget" rel="noopener noreferrer"&gt;widget builder&lt;/a&gt; generates this and shows a live preview.&lt;/p&gt;

&lt;p&gt;Here is the part nobody warned me about: &lt;strong&gt;every isolation strategy moves complexity somewhere else.&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Iframe?&lt;/strong&gt; Strong style isolation, but responsive sizing becomes a negotiation with the host page.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Shadow DOM?&lt;/strong&gt; Protects against CSS leaks, but theming and accessibility traversal get weird.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Plain script with scoped CSS?&lt;/strong&gt; Familiar to embedders, but one &lt;code&gt;!important&lt;/code&gt; rule on the host side and your layout collapses.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I went with the simple script and &lt;code&gt;data-*&lt;/code&gt; attributes for now. I’m not convinced it’s the long-term answer. If you’ve shipped an embeddable widget, I’d genuinely like to know: did you regret not using Web Components from the start?&lt;/p&gt;




&lt;h2&gt;
  
  
  Timelines are not articles
&lt;/h2&gt;

&lt;p&gt;A news article describes a moment. A timeline has to explain how moments relate across years.&lt;/p&gt;

&lt;p&gt;We publish timelines on things like &lt;a href="https://newtqnia.com/en/timelines/from-gans-to-ai-agents-the-evolution-of-generative-ai" rel="noopener noreferrer"&gt;the evolution of generative AI&lt;/a&gt; and &lt;a href="https://newtqnia.com/en/timelines/how-the-internet-was-built-from-four-computers-to-a-global-network" rel="noopener noreferrer"&gt;the history of the Internet&lt;/a&gt;. Internally, these are not long articles. They are collections of events with fields like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Exact or approximate dates&lt;/li&gt;
&lt;li&gt;Event types and importance levels&lt;/li&gt;
&lt;li&gt;Primary and secondary sources&lt;/li&gt;
&lt;li&gt;Related links&lt;/li&gt;
&lt;li&gt;Event-specific media&lt;/li&gt;
&lt;li&gt;Bilingual captions and alt text&lt;/li&gt;
&lt;li&gt;Attribution and licensing&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This makes the content reusable, but it also introduces editorial problems that code can’t solve. What do you do when two reputable sources disagree on a date? How do you mark a timeline as &lt;em&gt;incomplete&lt;/em&gt; without undermining it? How do you represent a source that is credible but secondary?&lt;/p&gt;

&lt;p&gt;I’m also unsure about the public format. Custom JSON is easy to design. JSON-LD or an existing event vocabulary is harder but more interoperable. If you were consuming timeline data from an API, which would you prefer?&lt;/p&gt;




&lt;h2&gt;
  
  
  Bilingual support starts in the data model
&lt;/h2&gt;

&lt;p&gt;Arabic is not “English with different words.” It needs RTL layout, different typography, localized dates, and interface decisions that don’t always mirror the English side.&lt;/p&gt;

&lt;p&gt;For structured content, the simplest model is explicit bilingual fields:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"title_en"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"The Transformer rewrites the architecture of language AI"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"title_ar"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"بنية المحولات تعيد صياغة هندسة الذكاء الاصطناعي اللغوي"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is easy to query and validate when you have exactly two languages. It becomes ugly at five or ten. A normalized translation table scales better, but it adds joins, fallback logic, and publishing-state complexity that I don’t need yet.&lt;/p&gt;

&lt;p&gt;My current rule: &lt;strong&gt;reconsider the model before adding a third language, not before.&lt;/strong&gt; Premature normalization is still premature optimization.&lt;/p&gt;




&lt;h2&gt;
  
  
  Media became a subsystem by accident
&lt;/h2&gt;

&lt;p&gt;Once timelines started using event-specific images, storing a single URL wasn’t enough. A useful media record now needs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A stable internal ID&lt;/li&gt;
&lt;li&gt;Processing status and responsive variants&lt;/li&gt;
&lt;li&gt;Dimensions and file type&lt;/li&gt;
&lt;li&gt;Bilingual alt text and captions&lt;/li&gt;
&lt;li&gt;Original source, attribution, and licensing&lt;/li&gt;
&lt;li&gt;A relationship to either a timeline or an individual event&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Images are processed into multiple sizes and formats. Events reference the internal asset, not an external URL. This keeps accessibility metadata attached to the thing it describes, and it avoids tying published pages to the uptime of some third-party host.&lt;/p&gt;

&lt;p&gt;The part I can’t automate: whether the alt text is actually &lt;em&gt;good&lt;/em&gt;. Validation checks for presence. It does not check for usefulness.&lt;/p&gt;




&lt;h2&gt;
  
  
  Distribution creates an attribution boundary
&lt;/h2&gt;

&lt;p&gt;The more portable you make content, the less control you have over how it’s used.&lt;/p&gt;

&lt;p&gt;Return only a title and URL, and the API is barely useful. Return full articles, and you’re inviting unattributed republication. Summaries are a middle ground, but even summaries get aggregated into faceless feeds.&lt;/p&gt;

&lt;p&gt;Right now the API asks consumers to preserve article URLs and display visible attribution. That is a social contract, not a technical one. I’ve looked at signed content, stricter terms, metered access, and API keys. Each one raises the cost of legitimate experimentation.&lt;/p&gt;

&lt;p&gt;If you’ve designed a public content API, how did you decide how much to give away?&lt;/p&gt;




&lt;h2&gt;
  
  
  What I would do differently
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Start with the timeline data model earlier.&lt;/strong&gt; Treating timelines as articles first meant a migration I could have avoided.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Question the embed strategy harder.&lt;/strong&gt; A script tag feels like the easy path until you’re debugging CSS specificity on a site you don’t control.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Document the API’s philosophy, not just its endpoints.&lt;/strong&gt; Developers need to know &lt;em&gt;why&lt;/em&gt; it’s small before they decide whether to build on it.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Questions I’m stuck on
&lt;/h2&gt;

&lt;p&gt;If you were reviewing this system, I’d value your take on:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Scope creep:&lt;/strong&gt; At what point does a small REST API &lt;em&gt;need&lt;/em&gt; categories, tags, or search?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Push vs. pull:&lt;/strong&gt; Would webhooks for new stories be useful, or does RSS already solve that?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Embed interfaces:&lt;/strong&gt; Is a &lt;code&gt;data-*&lt;/code&gt; script still a good integration format in 2026?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Web Components:&lt;/strong&gt; Do they actually solve the widget isolation problem, or just shift it?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Timeline formats:&lt;/strong&gt; How would you represent sourced historical events in a public API?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Multilingual models:&lt;/strong&gt; What is the least complicated model that still supports future expansion?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Content boundaries:&lt;/strong&gt; How much article content should a public news API return?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Versioning:&lt;/strong&gt; Which caching or contract mistakes should I fix &lt;em&gt;before&lt;/em&gt; the API grows?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;You can poke at the current implementation through the &lt;a href="https://newtqnia.com/en/developers" rel="noopener noreferrer"&gt;developer page&lt;/a&gt;, the &lt;a href="https://newtqnia.com/en/widget" rel="noopener noreferrer"&gt;widget builder&lt;/a&gt;, and the live &lt;a href="https://newtqnia.com/en/timelines" rel="noopener noreferrer"&gt;timeline collection&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If one part of this system deserves to be simplified, replaced, or avoided entirely, which one is it?&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;


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

&lt;/div&gt;

</description>
      <category>ai</category>
      <category>webdev</category>
      <category>programming</category>
      <category>automation</category>
    </item>
    <item>
      <title>2000 public APIs for your Next Project</title>
      <dc:creator>Samy</dc:creator>
      <pubDate>Tue, 03 Jan 2023 06:49:44 +0000</pubDate>
      <link>https://dev.to/samymassoud/2000-public-apis-for-your-next-project-bkk</link>
      <guid>https://dev.to/samymassoud/2000-public-apis-for-your-next-project-bkk</guid>
      <description>&lt;p&gt;Consuming API is a crucial part of learning any programming language. There is a need to integrate different systems almost in any programming project.&lt;/p&gt;

&lt;p&gt;Mobile Apps, Websites, CRM, ... and the list is long, all require integration with other 3rd party or even internal APIs.&lt;/p&gt;

&lt;p&gt;Practicing such will require an API to work with, and in this post, I'm shedding light on my recent work, the &lt;a href="https://apislist.com" rel="noopener noreferrer"&gt;Public API Directory&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In this directory (&lt;a href="https://apislist.com" rel="noopener noreferrer"&gt;APIsList&lt;/a&gt;) , I've compiled more than 2000 public APIs from the community and also by the direct share of the API owners, to make it easier for any one looking for his next project idea, or even integrating with an existing system.&lt;/p&gt;

&lt;p&gt;The directory list some decisive information about each API with powerful search engine to make it easier for you to choose the correct API for your need. It does also come with pre-defiend lists such as &lt;a href="https://apislist.com/apis/open-source" rel="noopener noreferrer"&gt;Open Source APis list&lt;/a&gt;, &lt;a href="https://apislist.com/apis/no-key" rel="noopener noreferrer"&gt;Free APIs&lt;/a&gt; and &lt;a href="https://apislist.com/apis/cors" rel="noopener noreferrer"&gt;APIs with CORS support&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I hope you will enjoy it, and please drop any suggestion or critisism to make it better in the comments below.&lt;/p&gt;

</description>
      <category>emptystring</category>
    </item>
    <item>
      <title>The IBAN API</title>
      <dc:creator>Samy</dc:creator>
      <pubDate>Sun, 22 Aug 2021 09:52:42 +0000</pubDate>
      <link>https://dev.to/samymassoud/the-iban-api-3pe6</link>
      <guid>https://dev.to/samymassoud/the-iban-api-3pe6</guid>
      <description>&lt;p&gt;I wanted to share my latest product with the community, which is the IBAN validation API.&lt;/p&gt;

&lt;p&gt;This product offers a way of validating the IBAN and getting the bank metadata from it, such as Bank Name, Branch, address and BIC, ...&lt;/p&gt;

&lt;p&gt;The product is growing daily by the usage of its customer whereas of today it covers more than 100 countries around the world.&lt;/p&gt;

&lt;p&gt;I would like to share the product with the community where it will benefit you if you are in the Fintech, e-commerce, accounting, or any related sector and you require your customer IBAN where this API will boost and enhance your user experience and your system acceptance rate.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://ibanapi.com"&gt;IBAN API&lt;/a&gt; can be accessed through this URL.&lt;/p&gt;

&lt;p&gt;Please let me know your thoughts and suggestions.&lt;/p&gt;

</description>
      <category>banking</category>
      <category>fintech</category>
    </item>
    <item>
      <title>I've created the online tools platform</title>
      <dc:creator>Samy</dc:creator>
      <pubDate>Sun, 13 Dec 2020 07:49:34 +0000</pubDate>
      <link>https://dev.to/samymassoud/i-ve-created-the-online-tools-platform-ipg</link>
      <guid>https://dev.to/samymassoud/i-ve-created-the-online-tools-platform-ipg</guid>
      <description>&lt;p&gt;So, as many other developers, I've many tools to be used daily, such as &lt;a href="https://devtools360.com/en/json/viewer"&gt;JSON Viewer&lt;/a&gt; or hashing strings :)&lt;/p&gt;

&lt;p&gt;My list of daily used tools is growing with some limitation on some tools online, as a result, I've decided to build my own tool and share it with the community.&lt;/p&gt;

&lt;p&gt;After a few days of work, I've launched the initial version of devtools360.com intending to provide more than 100 useful tools for different use cases.&lt;/p&gt;

&lt;p&gt;Since then I'm adding tools every week, for instance, the most recent tool was the &lt;a href="https://devtools360.com/en/ocr/choose"&gt;OCR Tools&lt;/a&gt;, &lt;a href="http://localhost/devtools360/public/en/macaddress/lookup"&gt;Mac address Lookup&lt;/a&gt; tool, and &lt;a href="https://devtools360.com/en/websites/dns"&gt;website DNS checker&lt;/a&gt; tool.&lt;/p&gt;

&lt;p&gt;I thought it would be better to get dev. community feedback on what has been done, and what should be done next to make this platform more convenient and easier to use.&lt;/p&gt;

&lt;p&gt;So please let me know your thoughts :)&lt;/p&gt;

</description>
      <category>ocr</category>
      <category>macaddress</category>
      <category>qr</category>
      <category>pdf</category>
    </item>
  </channel>
</rss>
