
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	xmlns:georss="http://www.georss.org/georss"
	xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#"
>
  <channel>
    <atom:link href="http://rsblog.us.kg/rss.xml" rel="self" type="application/rss+xml" />
    <title>Rasel Shikdar</title>
    <link>https://rsinfo.vercel.app</link>
    <description>I'm a developer aiming to build things that spark joy. I build fun stuff on the web, and sometimes write about it.</description>
    <image>
      <url>https://rsinfo.vercel.app/favicons/favicon-32x32.png</url>
      <title>Rasel Shikdar</title>
      <link>https://rsinfo.vercel.app</link>
      <width>32</width>
      <height>32</height>
    </image>
    
        <item>
          <guid>https://rsinfo.vercel.app/ai-seo-blog-writing-guide</guid>
          <title>AI ব্যবহার করে এসইও-ফ্রেন্ডলি ব্লগ লেখার সেরা উপায়: EEAT গাইডলাইন</title>
          <description>AI-এর সহায়তায় অভিজ্ঞতা, কর্তৃত্ব ও নির্ভরযোগ্যতা (EEAT Guidelines) অনুসরণ
করে এসইও-ফ্রেন্ডলি ব্লগ লেখার সহজ ও কার্যকর গাইড।
</description>
          <link>https://rsinfo.vercel.app/ai-seo-blog-writing-guide</link>
          <pubDate>Tue, 04 Mar 2025 09:58:06 +0000</pubDate>
          
          <content:encoded><![CDATA[
            <div style="margin: 50px 0; font-style: italic;">
              If anything looks wrong, 
              <strong>
                <a href="https://rsinfo.vercel.app/ai-seo-blog-writing-guide">
                  read on the site!
                </a>
              </strong>
            </div>

            <h2 id="1-ভূমিকা-introduction">1. ভূমিকা (Introduction)</h2>
<p>আজকের ডিজিটাল যুগে হাজারো ব্লগ নিবন্ধ প্রকাশিত হচ্ছে, তবে সত্যিকার অর্থে পাঠকের মনে ছাপ ফেলা একটি নিবন্ধ তৈরি করা অনেক কঠিন কাজ। আপনার যদি লক্ষ্য থাকে এমন একটি নিবন্ধ তৈরি করার যা SEO-বান্ধব ও তথ্যবহুল, তাহলে সঠিক কৌশল, প্রামাণিকতা ও AI-এর সহায়তা অপরিহার্য।</p>
<p>আপনি কি কখনো ভেবেছেন – কিভাবে AI-এর সহায়তায় একটি নিবন্ধ লেখার মাধ্যমে আপনি আপনার পাঠকের আস্থা অর্জন করতে পারেন? এই নিবন্ধে আমরা বিস্তারিতভাবে আলোচনা করবো কিভাবে AI ব্যবহার করে আপনার ব্লগ নিবন্ধকে আরও পেশাদার, তথ্যসমৃদ্ধ এবং SEO অপ্টিমাইজ করা যায়।</p>
<p>নিবন্ধটি এমনভাবে রচিত যাতে প্রতিটি ধাপে আপনার নিজস্ব অভিজ্ঞতা, গবেষণা ও প্রাসঙ্গিক তথ্যের সংযোজন করা যায়। এটি পাঠকের সাথে সরাসরি যোগাযোগ স্থাপন করে এবং তাদের প্রয়োজনীয় প্রশ্নের উত্তর প্রদান করে। এছাড়া, লেখাটি এমনভাবে সাজানো হয়েছে যাতে পাঠকেরা সহজেই বিষয়টি অনুধাবন করতে পারে ও নিজেরা প্রয়োগ করতে পারে।</p>
<p>ডিজিটাল মার্কেটিং ও ব্লগিংয়ের জগতে প্রতিদিন নতুন নতুন কৌশল আবিষ্কার হচ্ছে। তাই আপনার ব্লগে সর্বদা সর্বশেষ ও প্রাসঙ্গিক তথ্য থাকতে হবে। এই নিবন্ধে আমরা আলোচনা করবো কিভাবে AI এবং আধুনিক SEO কৌশল ব্যবহার করে আপনার ব্লগ নিবন্ধকে আরও আকর্ষণীয় ও তথ্যসমৃদ্ধ করা যায়।</p>
<h2 id="2-অভিজ্ঞতা-ও-কর্তৃত্ব-বজায়-রেখে-ব্লগ-লেখার-কৌশল">2. অভিজ্ঞতা ও কর্তৃত্ব বজায় রেখে ব্লগ লেখার কৌশল</h2>
<p>একটি সফল ব্লগের মূল উপাদান হলো লেখকের নিজস্ব অভিজ্ঞতা ও দক্ষতা। যখন পাঠক বুঝতে পারে যে আপনি বিষয়টির সাথে গভীরভাবে পরিচিত এবং আপনার অভিজ্ঞতা ও গবেষণার ভিত্তিতে তথ্য সরবরাহ করছেন, তখন তারা নিবন্ধের প্রতি আরও আস্থা পায়।</p>
<p>এই অংশে নিম্নলিখিত বিষয়গুলোকে গুরুত্ব দিন:</p>
<ul>
<li>ব্যক্তিগত অভিজ্ঞতা: আপনার নিজস্ব কাজ, প্রকল্প বা কেস স্টাডির মাধ্যমে পাঠকের সাথে সরাসরি সম্পর্ক তৈরি করুন।</li>
<li>বিশেষজ্ঞ মতামত: প্রাসঙ্গিক বিষয়ে বিশেষজ্ঞদের মতামত ও গবেষণালব্ধ তথ্য অন্তর্ভুক্ত করুন। এতে করে নিবন্ধের প্রামাণিকতা ও গ্রহণযোগ্যতা বৃদ্ধি পায়।</li>
<li>তথ্যসূত্র ও গবেষণা: সঠিক তথ্য, পরিসংখ্যান এবং গবেষণার ফলাফল শেয়ার করুন, যাতে নিবন্ধটি তথ্যগতভাবে দৃঢ় হয়।</li>
<li>স্বচ্ছতা ও নিরাপত্তা: লেখায় তথ্যের উৎস এবং আপনার অভিজ্ঞতা স্পষ্টভাবে উল্লেখ করুন। এতে করে পাঠকের আস্থা অর্জিত হয় এবং ব্লগটি আরও বিশ্বাসযোগ্য হয়।</li>
</ul>
<p>যখন আপনি ব্যক্তিগত অভিজ্ঞতা ও প্রামাণিক তথ্য যোগ করেন, তখন পাঠকের মনে এক ধরনের বিশ্বাসের বীজ ফুটে ওঠে। এই বিশ্বাসই আপনাকে আপনার ব্লগিং ক্যারিয়ারে এগিয়ে নিয়ে যায় এবং নতুন পাঠকদের আকর্ষণ করে।</p>
<h2 id="3-বিষয়-নির্বাচন-ও-কীওয়ার্ড-গবেষণা-topic--keyword-research">3. বিষয় নির্বাচন ও কীওয়ার্ড গবেষণা (Topic &amp; Keyword Research)</h2>
<p>একটি সফল নিবন্ধের জন্য সঠিক বিষয় নির্বাচন ও কীওয়ার্ড গবেষণা অপরিহার্য। এটি আপনাকে সাহায্য করে ট্রেন্ডিং বিষয় ও সেইসাথে পাঠকের প্রকৃত প্রশ্নের উত্তর খুঁজে পেতে।</p>
<p>কিছু মূল পয়েন্ট:</p>
<ul>
<li>AI টুলস ব্যবহার: Google Trends, AnswerThePublic, SEMrush এবং Ahrefs-এর মতো টুলস ব্যবহার করে আপনার নিস সম্পর্কিত জনপ্রিয় বিষয়গুলো খুঁজে বের করুন।</li>
<li>লং-টেইল কীওয়ার্ড: সাধারণ কীওয়ার্ডের পাশাপাশি লং-টেইল কীওয়ার্ড নির্বাচন করুন যা নির্দিষ্ট পাঠকের প্রশ্নের উত্তর দিতে সহায়ক।</li>
<li>কীওয়ার্ড ইন্টেন্ট: NLP (Natural Language Processing) প্রযুক্তি ব্যবহার করে বুঝুন পাঠকের আসল চাহিদা কী। তারা তথ্যমূলক, কেনাকাটা-সম্পর্কিত বা সিদ্ধান্তমূলক তথ্য খুঁজছেন।</li>
</ul>
<p>সঠিক কীওয়ার্ড গবেষণা নিশ্চিত করে যে আপনার নিবন্ধ সার্চ ইঞ্জিনে সহজেই খুঁজে পাওয়া যাবে। এটি শুধুমাত্র পাঠকের সংখ্যা বৃদ্ধি করে না, বরং পাঠকের সাথে সঠিক তথ্যের মাধ্যমে যোগাযোগও নিশ্চিত করে।</p>
<p>প্রতিদিন লক্ষ লক্ষ মানুষ অনলাইনে অনুসন্ধান করে থাকে। তাই আপনার ব্লগ নিবন্ধে যদি প্রাসঙ্গিক ও ট্রেন্ডিং বিষয়ের অন্তর্ভুক্তি থাকে, তবে এটি পাঠকের আস্থা ও ট্রাফিক দুইই বৃদ্ধি পায়।</p>
<h2 id="4-আউটলাইন-তৈরি-outline-creation">4. আউটলাইন তৈরি (Outline Creation)</h2>
<p>একটি সুসংগঠিত আউটলাইন আপনার নিবন্ধের ভিত্তি হিসেবে কাজ করে। একটি ভাল আউটলাইন লিখনপ্রক্রিয়াকে সহজ ও সুচারু করে তোলে এবং নিশ্চিত করে যে কোন গুরুত্বপূর্ণ তথ্য বাদ পড়বে না।</p>
<ul>
<li>লজিক্যাল ফ্লো: নিবন্ধের শিরোনাম (H1), উপশিরোনাম (H2, H3) ও সাব-হেডিংগুলো সুস্পষ্টভাবে সাজান।</li>
<li>বিষয়বস্তু সজ্জা: প্রতিটি বিভাগে কি আলোচনা হবে তা স্পষ্টভাবে নির্ধারণ করুন। এতে করে পাঠক সহজেই নিবন্ধের প্রবাহ বুঝতে পারে।</li>
<li>পাঠক কেন্দ্রিকতা: এমন আউটলাইন তৈরি করুন যা পাঠকের প্রয়োজনীয় তথ্য অনুসন্ধানে সহায়ক হয়।</li>
</ul>
<p>উন্নত আউটলাইন তৈরির মাধ্যমে আপনি নিবন্ধটি লেখার সময় একটি নির্দিষ্ট রূপরেখা অনুসরণ করতে পারবেন যা আপনার লেখাকে আরও সংগঠিত এবং আকর্ষণীয় করে তোলে।</p>
<h2 id="5-বিষয়বস্তু-তৈরি-content-creation">5. বিষয়বস্তু তৈরি (Content Creation)</h2>
<p>নিবন্ধের মূল অংশ হলো বিষয়বস্তু। এটি আপনার পাঠকের সাথে সরাসরি যোগাযোগের সেতু হিসেবে কাজ করে। AI-এর সহায়তায় মানব সম্পাদিত কন্টেন্টের সংমিশ্রণ ব্যবহার করলে লেখাটি আরও প্রামাণিক ও প্রাঞ্জল হয়।</p>
<p>কিছু গুরুত্বপূর্ণ দিক:</p>
<ul>
<li>AI ও মানব-সম্পাদনা: প্রথমে AI টুলস যেমন Jasper, Copy.ai, Writesonic অথবা OpenAI ChatGPT ব্যবহার করে প্রাথমিক ড্রাফট তৈরি করুন। এরপর মানব সম্পাদনা করে তা আরও প্রামাণিক ও সাবলীল করুন।</li>
<li>ডেটা ও চার্ট সংযোজন: প্রাসঙ্গিক ডেটা, চার্ট ও গবেষণার ফলাফল যুক্ত করুন যা নিবন্ধের তথ্যগত মান উন্নত করে এবং পাঠককে বিষয়টি গভীরভাবে বোঝার সুযোগ করে দেয়।</li>
<li>সাহিত্যিক স্টাইল: সহজ, সাবলীল ও প্রাঞ্জল ভাষায় লিখুন যাতে পাঠকের মনোযোগ ধরে রাখা যায়।</li>
<li>দৈর্ঘ্য ও গভীরতা: নিবন্ধের দৈর্ঘ্য অবশ্যই 1500+ শব্দ হওয়া উচিত যাতে বিষয়টি সম্পূর্ণভাবে কাভার করা যায়।</li>
</ul>
<p>একটি ভালভাবে রচিত নিবন্ধ শুধুমাত্র তথ্য প্রদান করে না, বরং পাঠকের সাথে একটি ব্যক্তিগত সম্পর্কও তৈরি করে। আপনার লেখা যদি সত্যি ও প্রামাণিক হয়, তবে পাঠকেরা তা তাদের দৈনন্দিন জীবনে প্রয়োগ করতে সক্ষম হবে।</p>
<p>সাধারণত, নিবন্ধের প্রতিটি প্যারাগ্রাফে পাঠকের সাথে যোগাযোগের একটি ছোট গল্প বা উদাহরণ অন্তর্ভুক্ত করা যেতে পারে। এটি লেখাটিকে আরও মানবিক করে তোলে এবং পাঠকের সাথে সম্পর্ক তৈরি করে।</p>
<h2 id="51-ব্যবহারিক-উদাহরণ-ও-কেস-স্টাডিজ">5.1. ব্যবহারিক উদাহরণ ও কেস স্টাডিজ</h2>
<p>একটি নিবন্ধের প্রামাণিকতা বৃদ্ধি পেতে ব্যবহারিক উদাহরণ ও কেস স্টাডিজ অত্যন্ত গুরুত্বপূর্ণ। আপনি যদি বাস্তব জীবনের উদাহরণ যুক্ত করেন, তবে পাঠক সহজেই আপনার বক্তব্য গ্রহণ করতে পারবেন।</p>
<p>উদাহরণস্বরূপ, যদি আপনি আপনার নিজের ব্লগিং অভিজ্ঞতা নিয়ে কথা বলেন, তবে আপনি নিম্নলিখিত বিষয়গুলো শেয়ার করতে পারেন:</p>
<ul>
<li>কিভাবে একটি বিশেষ কীওয়ার্ড গবেষণা আপনার নিবন্ধের ট্রাফিক বৃদ্ধি করেছে।</li>
<li>কিভাবে আপনার ব্লগে অভিজ্ঞতা ও বিশেষজ্ঞ মতামতের সংমিশ্রণ পাঠকের আস্থা বৃদ্ধি করেছে।</li>
<li>কিভাবে সঠিক লিঙ্কিং ও মাল্টিমিডিয়া ব্যবহার করে আপনার ব্লগের এনগেজমেন্ট উন্নত হয়েছে।</li>
</ul>
<p>এই ধরনের উদাহরণ পাঠকের কাছে আরও প্রাসঙ্গিক ও গ্রহণযোগ্য হয়ে ওঠে। এছাড়া, আপনি যদি কেস স্টাডিজ যুক্ত করেন যা দেখায় কিভাবে অন্য সফল ব্লগাররা একই কৌশল ব্যবহার করে সফল হয়েছে, তবে তা আপনার নিবন্ধের মান আরও বাড়িয়ে দেয়।</p>
<h2 id="6-চিত্র-ও-মাল্টিমিডিয়া-image--multimedia-integration">6. চিত্র ও মাল্টিমিডিয়া (Image &amp; Multimedia Integration)</h2>
<p>একটি আকর্ষণীয় নিবন্ধ শুধুমাত্র লিখিত বিষয়বস্তু দিয়ে নয়, বরং চিত্র, ভিডিও এবং অন্যান্য মাল্টিমিডিয়া উপাদানের মাধ্যমে পাঠকের মনোযোগ আকর্ষণ করে। মাল্টিমিডিয়া ব্যবহারে পাঠকের অভিজ্ঞতা আরও সমৃদ্ধ হয়।</p>
<ul>
<li>উৎপাদিত চিত্র: DALL·E, Canva, Midjourney-এর মতো AI টুলস ব্যবহার করে ইউনিক ও প্রাসঙ্গিক চিত্র তৈরি করুন।</li>
<li>চিত্র অপ্টিমাইজেশন: চিত্রের Alt Text, কম ফাইল সাইজ এবং স্কিমা মার্কআপ ব্যবহার করে চিত্রগুলোকে SEO-বান্ধব করুন।</li>
<li>ভিডিও ও ইনফোগ্রাফিক্স: প্রয়োজন অনুযায়ী ভিডিও, ইনফোগ্রাফিক্স এবং অন্যান্য ইন্টারঅ্যাক্টিভ উপাদান যোগ করুন যা নিবন্ধের এনগেজমেন্ট বাড়ায় এবং তথ্য স্পষ্টভাবে উপস্থাপন করে।</li>
</ul>
<p>মাল্টিমিডিয়া উপাদান ব্যবহার করে আপনি শুধু পাঠকের মনোযোগ আকর্ষণ করেন না, বরং তাদেরকে বিষয়টির গভীরে যেতে উৎসাহিত করেন। এতে করে আপনার ব্লগের ব্যাকলিঙ্ক ও শেয়ারিংয়ের সম্ভাবনাও বৃদ্ধি পায়।</p>
<h2 id="7-অভ্যন্তরীণ-ও-বাহ্যিক-লিঙ্কিং-internal--external-linking">7. অভ্যন্তরীণ ও বাহ্যিক লিঙ্কিং (Internal &amp; External Linking)</h2>
<p>সঠিক অভ্যন্তরীণ ও বাহ্যিক লিঙ্কিং ব্যবহার করে আপনার নিবন্ধে অতিরিক্ত মূল্য যোগ করা যায়। এটি কেবল SEO উন্নত করে না, পাঠকদের প্রাসঙ্গিক তথ্য প্রদান করেও সহায়ক হয়।</p>
<ul>
<li>অভ্যন্তরীণ লিঙ্ক: আপনার ব্লগের অন্যান্য প্রাসঙ্গিক নিবন্ধ বা পেজের লিঙ্ক যুক্ত করুন, যাতে পাঠক সহজেই আরও তথ্য পেতে পারেন এবং আপনার সাইটে তাদের সময় বৃদ্ধি পায়।</li>
<li>বাহ্যিক লিঙ্ক: সরকারি বা প্রামাণিক উৎস থেকে তথ্যের লিঙ্ক প্রদান করুন যা আপনার নিবন্ধকে আরও নির্ভরযোগ্য করে তোলে।</li>
<li>অ্যাঙ্কর টেক্সট: প্রতিটি লিঙ্কে প্রাসঙ্গিক এবং SEO-বান্ধব অ্যাঙ্কর টেক্সট ব্যবহার করুন, যা পাঠকের জন্য বিষয়টি আরও স্পষ্ট করে তোলে।</li>
</ul>
<p>লিঙ্কিং কৌশল অনুসরণ করলে, আপনার নিবন্ধটি শুধু সার্চ ইঞ্জিনে ভাল র‍্যাঙ্ক করবে না, বরং পাঠকদেরও মূল্যবান তথ্য উপস্থাপন করে যা তাদের জন্য সহায়ক হবে।</p>
<h2 id="8-প্রুফরিডিং-ও-সম্পাদনা-proofreading--editing">8. প্রুফরিডিং ও সম্পাদনা (Proofreading &amp; Editing)</h2>
<p>নিবন্ধ প্রকাশের পূর্বে প্রুফরিডিং ও সম্পাদনা করা অত্যন্ত গুরুত্বপূর্ণ। এতে করে ব্যাকরণগত ভুল, বানান ত্রুটি ও তথ্যের অসামঞ্জস্য দূর করা যায়।</p>
<ul>
<li>গ্রামার চেক: Grammarly, Hemingway App ইত্যাদি টুল ব্যবহার করে লেখাটি যাচাই করুন।</li>
<li>তথ্য যাচাই: ফ্যাক্ট-চেক করে নিশ্চিত করুন যে প্রতিটি তথ্য সঠিক ও আপ-টু-ডেট।</li>
<li>পাঠযোগ্যতা: ছোট অনুচ্ছেদ, সহজ ভাষা ও স্ক্যানযোগ্য ফরম্যাট ব্যবহার করে নিবন্ধকে আরও পাঠযোগ্য করে তুলুন।</li>
</ul>
<p>একটি নিখুঁত নিবন্ধ তৈরির জন্য প্রুফরিডিং ও সম্পাদনা অপরিহার্য। এতে করে আপনার লেখার মান বৃদ্ধি পায় এবং পাঠকরা তথ্যের নির্ভুলতা ও প্রামাণিকতা অনুভব করে।</p>
<h2 id="9-seo-অপ্টিমাইজেশন-seo-optimization">9. SEO অপ্টিমাইজেশন (SEO Optimization)</h2>
<p>SEO অপ্টিমাইজেশন একটি নিবন্ধকে সার্চ ইঞ্জিনে উচ্চতর র‍্যাঙ্কিং দিতে সাহায্য করে। এটি বেশ কয়েকটি দিক থেকে করা যায়:</p>
<h3 id="on-page-seo">On-Page SEO</h3>
<ul>
<li>কীওয়ার্ড-সমৃদ্ধ H1, H2, H3 শিরোনাম ব্যবহার</li>
<li>সঠিকভাবে মেটা ট্যাগ ও মেটা বিবরণ তৈরি</li>
<li>Structured Data ও Schema Markup সংযোজন</li>
</ul>
<h3 id="technical-seo">Technical SEO</h3>
<ul>
<li>দ্রুত লোডিং গতি নিশ্চিত করা (Page Speed Optimization)</li>
<li>মোবাইল-ফ্রেন্ডলি ডিজাইন ও রেসপন্সিভ লেআউট</li>
<li>Core Web Vitals অনুযায়ী অপ্টিমাইজেশন করা</li>
</ul>
<h3 id="user-experience-ux-optimization">User Experience (UX) Optimization</h3>
<ul>
<li>আকর্ষণীয় CTA বোতাম সংযোজন</li>
<li>সহজ নেভিগেশন ও স্ক্যানযোগ্য কন্টেন্ট</li>
</ul>
<p>সঠিক SEO অপ্টিমাইজেশন কৌশল ব্যবহার করে, আপনার নিবন্ধটি শুধু সার্চ ইঞ্জিনের কাছে নয়, পাঠকের চোখেও আকর্ষণীয় হয়ে ওঠে। এটি আপনার ব্লগের ট্রাফিক ও পাঠকের এনগেজমেন্ট বৃদ্ধিতে সহায়ক হয়।</p>
<h2 id="91-উন্নত-seo-কৌশল-ও-ট্রেন্ডস">9.1. উন্নত SEO কৌশল ও ট্রেন্ডস</h2>
<p>আজকের সময়ে, শুধুমাত্র প্রাথমিক SEO টিপস অনুসরণ করা যথেষ্ট নয়। উন্নত SEO কৌশল যেমন মোবাইল অপ্টিমাইজেশন, সাইটের নিরাপত্তা, এবং ইউজার ইন্টারঅ্যাকশনকে কেন্দ্র করে নিবন্ধের গুণমান নিশ্চিত করতে হবে।</p>
<p>উন্নত SEO কৌশলগুলো অন্তর্ভুক্ত করে:</p>
<ul>
<li>Core Web Vitals: সাইটের লোডিং স্পিড, ইন্টারঅ্যাকটিভিটি এবং ভিজুয়াল স্টেবিলিটি উন্নত করা।</li>
<li>মোবাইল-ফ্রেন্ডলি ডিজাইন: অধিকাংশ পাঠক মোবাইল ব্যবহার করে, তাই একটি রেসপন্সিভ ও মোবাইল-অপ্টিমাইজড ডিজাইন অপরিহার্য।</li>
<li>ইউজার এনগেজমেন্ট: কমেন্ট সেকশন, শেয়ার বাটন ও অন্যান্য ইন্টারঅ্যাকটিভ উপাদানের মাধ্যমে পাঠকের সাথে যোগাযোগ বৃদ্ধি করা।</li>
<li>Structured Data: নিবন্ধের বিভিন্ন অংশকে সঠিকভাবে মার্কআপ করে সার্চ ইঞ্জিনের কাছে পাঠ্যকে আরও প্রাসঙ্গিক করে তোলা।</li>
</ul>
<p>এই উন্নত কৌশলগুলো ব্যবহার করে, আপনি শুধু সার্চ ইঞ্জিন র‍্যাঙ্ক বৃদ্ধি করবেন না, বরং আপনার পাঠকদের অভিজ্ঞতাও সমৃদ্ধ করবেন।</p>
<h2 id="10-উপসংহার-conclusion">10. উপসংহার (Conclusion)</h2>
<p>সফল ব্লগ লেখার জন্য উপরে আলোচনা করা প্রতিটি ধাপ অপরিহার্য। সঠিক পরিকল্পনা, গভীর গবেষণা এবং AI-এর সহায়তায় মানবিক স্পর্শের সমন্বয়ে আপনি একটি অসাধারণ, SEO-বান্ধব নিবন্ধ তৈরি করতে পারবেন।</p>
<p>এই নিবন্ধে আমরা আলোচনা করেছি কিভাবে:</p>
<ul>
<li>একটি শক্তিশালী হুক ও পরিচিতির মাধ্যমে পাঠকের মনোযোগ আকর্ষণ করা যায়,</li>
<li>নিজস্ব অভিজ্ঞতা ও গবেষণালব্ধ তথ্যের মাধ্যমে নিবন্ধের প্রামাণিকতা বৃদ্ধি করা যায়,</li>
<li>সঠিক বিষয় নির্বাচন ও কীওয়ার্ড গবেষণা করে নিবন্ধের সার্চ ইঞ্জিন অপ্টিমাইজেশন নিশ্চিত করা যায়,</li>
<li>বিষয়বস্তু তৈরি থেকে শুরু করে চিত্র, লিঙ্কিং, প্রুফরিডিং ও সম্পাদনা পর্যন্ত প্রতিটি ধাপ সুন্দরভাবে রচিত হয়,</li>
<li>উন্নত SEO কৌশল ও ইউজার এক্সপেরিয়েন্স টিপস ব্যবহার করে নিবন্ধকে সম্পূর্ণ SEO-বান্ধব করা যায়।</li>
</ul>
<p>আপনার ব্লগে এই কৌশলগুলো বাস্তবায়ন করলে নিশ্চিতভাবেই আপনি উচ্চমানের এবং পাঠকের আস্থা অর্জনকারী নিবন্ধ তৈরি করতে পারবেন। নিবন্ধটি নিয়মিত আপডেট করে নতুন তথ্য সংযোজন, পাঠকদের সাথে সরাসরি যোগাযোগ এবং সোশ্যাল মিডিয়ায় শেয়ার করার মাধ্যমে আপনার ব্লগের জনপ্রিয়তা ও ট্রাফিক বৃদ্ধি পাবে।</p>
<p>আজকের এই নিবন্ধটি আপনার ব্লগ লেখার প্রক্রিয়াকে একটি সুসংগঠিত ও প্রামাণিক রূপরেখা প্রদান করে। প্রতিটি ধাপে বিস্তারিত নির্দেশনা ও কৌশল আলোচনা করা হয়েছে যাতে আপনি সহজেই তা বাস্তবায়ন করতে পারেন।</p>
<h2 id="11-অতিরিক্ত-টিপস-additional-tips">11. অতিরিক্ত টিপস (Additional Tips)</h2>
<ul>
<li>নিয়মিত আপডেট: পুরনো নিবন্ধ আপডেট করুন এবং নতুন তথ্য সংযোজন করুন যাতে তা সর্বদা প্রাসঙ্গিক থাকে।</li>
<li>পাঠক এনগেজমেন্ট: পাঠকদের মন্তব্য, প্রশ্ন ও পরামর্শের উত্তর দিন। এতে করে পাঠকের সাথে সম্পর্ক স্থাপনে সহায়ক হবে।</li>
<li>সোশ্যাল মিডিয়া প্রচার: আপনার নিবন্ধকে Facebook, Twitter, LinkedIn-এর মত সোশ্যাল মিডিয়া প্ল্যাটফর্মে শেয়ার করুন।</li>
<li>পারফরম্যান্স অ্যানালিটিক্স: Google Analytics ও Search Console-এর মতো টুলস ব্যবহার করে নিবন্ধের কার্যকারিতা পর্যবেক্ষণ করুন।</li>
<li>কন্টেন্ট রিফ্রেশ: কিছু সময় পর পুরনো নিবন্ধের তথ্য যাচাই করে তা আপডেট করুন যাতে পাঠকের সর্বশেষ তথ্য পাওয়া যায়।</li>
</ul>
<p>অতিরিক্ত টিপস হিসেবে, আপনি আপনার নিবন্ধে নতুন প্রযুক্তির উদাহরণ বা ভবিষ্যতের ট্রেন্ড সম্পর্কে আলোচনা করতে পারেন যা পাঠকদের ভবিষ্যৎ পরিকল্পনা করতে সহায়তা করবে।</p>
<p>একটি ভালো নিবন্ধ তৈরির ক্ষেত্রে সব থেকে গুরুত্বপূর্ণ হলো পাঠকের প্রয়োজন ও সমস্যাকে বোঝা এবং সেই অনুযায়ী তথ্য প্রদান করা।</p>
<p>এখন সময় এসেছে আপনার ব্লগে এই কৌশলগুলো বাস্তবায়ন করার। আপনার অভিজ্ঞতা, গবেষণা ও AI-এর সহায়তায় তৈরি করা নিবন্ধের মাধ্যমে আপনার ব্লগকে এক নতুন উচ্চতায় নিয়ে যান এবং পাঠকদের সাথে একটি দৃঢ় সম্পর্ক তৈরি করুন। আপনার ব্লগের উন্নতির জন্য প্রতিটি পদক্ষেপ গুরুত্ব সহকারে গ্রহণ করুন এবং নিয়মিত আপডেট করতে ভুলবেন না।</p>
<h2 id="12-ভবিষ্যতের-দিকনির্দেশনা-ও-সমাপ্তি">12. ভবিষ্যতের দিকনির্দেশনা ও সমাপ্তি</h2>
<p>প্রযুক্তির দ্রুত পরিবর্তন এবং অনলাইনের প্রতিযোগিতা দিন দিন বৃদ্ধি পাচ্ছে। এ কারণে, একটি সফল ব্লগার হতে হলে শুধুমাত্র প্রাথমিক SEO টিপস জানা যথেষ্ট নয়; আপনাকে নিয়মিত নতুন নতুন প্রযুক্তি, কৌশল ও মার্কেট ট্রেন্ড সম্পর্কে জাগরণ রাখতে হবে।</p>
<p>AI এবং আধুনিক SEO কৌশল আপনার ব্লগকে নতুন দিগন্তে নিয়ে যেতে পারে। আপনি যদি সঠিকভাবে বিষয়বস্তু তৈরি করেন, প্রাসঙ্গিক তথ্য উপস্থাপন করেন এবং পাঠকের সাথে যোগাযোগ স্থাপন করেন, তাহলে আপনার ব্লগের জনপ্রিয়তা ও আস্থা স্বয়ংক্রিয়ভাবে বৃদ্ধি পাবে।</p>
<p>ভবিষ্যতে, আপনি আরও উন্নত SEO কৌশল, ভিডিও কন্টেন্ট, এবং ইন্টারঅ্যাক্টিভ উপাদান ব্যবহার করে আপনার ব্লগকে আরও কার্যকর ও তথ্যবহুল করে তুলতে পারবেন। এ ধরণের ধারাবাহিক উন্নতি আপনার ব্র্যান্ডকে দীর্ঘস্থায়ী করে তুলবে এবং পাঠকদের সাথে এক নতুন সম্পর্ক গড়ে তুলবে।</p>
<p>সর্বোপরি, প্রযুক্তি ও মানবিক স্পর্শের সংমিশ্রণে আপনি একটি সঠিক ও কার্যকরী ব্লগ লিখতে পারবেন যা শুধুমাত্র তথ্য প্রদান করে না, বরং পাঠকদের অনুপ্রাণিত করে এবং তাদের জীবনে ইতিবাচক পরিবর্তন এনে দেয়।</p>
<h2 id="faq">FAQ</h2>
<p>নিচে কিছু সাধারণ প্রশ্নের উত্তর দেওয়া হলো, যা এই নিবন্ধের বিষয়বস্তু ও SEO অপ্টিমাইজেশন সম্পর্কিত:</p>
<ul>
<li>প্রশ্ন: AI ব্যবহার করে ব্লগ লেখা কি সহজ?
উত্তর: সঠিক টুলস ও পরিকল্পনা থাকলে AI ব্যবহার করে ব্লগ লেখা অনেক সহজ হয়ে যায়, তবে মানব সম্পাদনা ও অভিজ্ঞতা নিশ্চিত করা আবশ্যক।</li>
<li>প্রশ্ন: কীভাবে আমি আমার নিবন্ধের SEO উন্নত করতে পারি?
উত্তর: সঠিক কীওয়ার্ড গবেষণা, অভ্যন্তরীণ ও বাহ্যিক লিঙ্কিং, এবং প্রুফরিডিং ও সম্পাদনার মাধ্যমে SEO উন্নত করা সম্ভব।</li>
<li>প্রশ্ন: নিবন্ধ লেখার জন্য কোন AI টুল ব্যবহার করা উচিত?
উত্তর: Jasper, Copy.ai, Writesonic এবং OpenAI ChatGPT-এর মতো টুলস প্রাথমিক ড্রাফট তৈরি করতে সহায়ক, তবে মানব সম্পাদনা অত্যন্ত গুরুত্বপূর্ণ।</li>
<li>প্রশ্ন: কিভাবে নিবন্ধে অভিজ্ঞতা ও কর্তৃত্ব প্রদর্শন করা যায়?
উত্তর: ব্যক্তিগত অভিজ্ঞতা, বিশেষজ্ঞ মতামত, সঠিক তথ্যসূত্র ও গবেষণার ফলাফল শেয়ার করে নিবন্ধে অভিজ্ঞতা ও কর্তৃত্ব স্পষ্টভাবে প্রকাশ করা যায়।</li>
</ul>
<h4 id="original-article-source-it-dorpon--আইটি-দর্পণ">Original Article Source: <a href="https://www.itdorpon.news">iT Dorpon | আইটি দর্পণ</a></h4>

          ]]></content:encoded>
          <media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://rsinfo.vercel.app/images/posts/2025-03-04-ai-seo-blog-writing-guide/cover.avif"/>
          <media:content xmlns:media="http://search.yahoo.com/mrss/" medium="image" url="https://rsinfo.vercel.app/images/posts/2025-03-04-ai-seo-blog-writing-guide/cover.avif"/>          
        </item>
      
        <item>
          <guid>https://rsinfo.vercel.app/the-seven-wonders-of-the-world</guid>
          <title>বিশ্বের সপ্তাশ্চর্য: ইতিহাস, ঐতিহ্য, গুরুত্ব ও সাংস্কৃতিক প্রভাব</title>
          <description>আজকে আমরা কথা বলতে যাচ্ছি বিশ্বের সপ্তাশ্চর্য নিয়ে যা প্রজন্মের পর প্রজন্ম ধরে মানুষের মধ্যে কৌতূহলের সৃষ্টি করেছে। আজ সেই ইতিহাস সম্পর্কে জানব।</description>
          <link>https://rsinfo.vercel.app/the-seven-wonders-of-the-world</link>
          <pubDate>Wed, 25 Dec 2024 07:04:39 +0000</pubDate>
          
          <content:encoded><![CDATA[
            <div style="margin: 50px 0; font-style: italic;">
              If anything looks wrong, 
              <strong>
                <a href="https://rsinfo.vercel.app/the-seven-wonders-of-the-world">
                  read on the site!
                </a>
              </strong>
            </div>

            <h2 id="সপ্তাশ্চর্য-কি">সপ্তাশ্চর্য কি?</h2>
<p>বিশ্বের সপ্তাশ্চর্য বলতে আমরা সাতটি ঐতিহাসিক এবং স্থাপত্যের অসাধারণ নিদর্শনকে বুঝি, যা মানব সভ্যতার সৃষ্টিশীলতা এবং দক্ষতার প্রতীক। এই সপ্তাশ্চর্যগুলি প্রাচীন এবং আধুনিক সময়ে নির্মিত হয়েছে এবং প্রতিটি স্থাপনা তার নিজস্ব ইতিহাস, ঐতিহ্য এবং সাংস্কৃতিক গুরুত্ব বহন করে।</p>
<h2 id="এটি-কিভাবে-নির্বাচিত-হয়">এটি কিভাবে নির্বাচিত হয়?</h2>
<p>সপ্তাশ্চর্যগুলির নির্বাচন একটি দীর্ঘ প্রক্রিয়া। প্রাচীন সময়ে, গ্রিক ইতিহাসবিদ হেরোডোটাস এবং অন্যান্য লেখকরা বিভিন্ন স্থাপনার তালিকা তৈরি করেছিলেন। তবে আধুনিক সময়ে, ২০০৭ সালে &quot;নিউ ৭ ওন্ডার্স&quot; প্রকল্পের মাধ্যমে একটি নতুন তালিকা তৈরি করা হয়। এই প্রকল্পের উদ্দেশ্য ছিল বিশ্বের বিভিন্ন স্থাপনার মধ্যে থেকে সাতটি অসাধারণ স্থাপনা নির্বাচন করা। ভোটিং প্রক্রিয়ার মাধ্যমে, বিশ্বের বিভিন্ন দেশের মানুষ তাদের পছন্দের স্থাপনাগুলির জন্য ভোট দিতে পারেন।</p>
<h2 id="কার-দ্বারা-নির্বাচিত-হয়">কার দ্বারা নির্বাচিত হয়?</h2>
<p>সপ্তাশ্চর্যগুলির নির্বাচন সাধারণত একটি আন্তর্জাতিক প্যানেল বা সংগঠনের দ্বারা করা হয়। ২০০৭ সালে &quot;নিউ ৭ ওন্ডার্স&quot; প্রকল্পের জন্য, একটি সুইস সংস্থা &quot;নিউ ৭ ওন্ডার্স ফাউন্ডেশন&quot; এই নির্বাচন পরিচালনা করে। তারা বিশ্বের বিভিন্ন স্থাপনার উপর গবেষণা করে এবং জনগণের ভোটের মাধ্যমে সাতটি স্থাপনা নির্বাচন করে।</p>
<h2 id="১-পিরামিড-অফ-গিজা">১. পিরামিড অফ গিজা</h2>
<h3 id="ইতিহাস-ও-নির্মাণ">ইতিহাস ও নির্মাণ</h3>
<p>মিশরের গিজার পিরামিড, যা &#39;গ্রেট পিরামিড&#39; নামেও পরিচিত, এটি বিশ্বের সপ্তাশ্চর্যের মধ্যে একমাত্র স্থাপনা যা এখনও টিকে আছে। এটি খেফরো নামক ফারাওয়ের জন্য নির্মিত হয়েছিল এবং এর নির্মাণকাল প্রায় ২৫০০ খ্রিস্টপূর্বাব্দ। পিরামিডটি প্রায় ২.৩ মিলিয়ন পাথরের ব্লক দিয়ে তৈরি, যার প্রতিটির ওজন ২.৫ টন। এই পিরামিডের উচ্চতা ছিল প্রায় 146.6 মিটার, যা প্রাচীন সময়ে পৃথিবীর সবচেয়ে উঁচু মানবনির্মিত কাঠামো ছিল।</p>
<h3 id="ঐতিহ্য-ও-সাংস্কৃতিক-গুরুত্ব">ঐতিহ্য ও সাংস্কৃতিক গুরুত্ব</h3>
<p>পিরামিডটি মিশ রের প্রাচীন সভ্যতার প্রতীক। এটি মৃতদের জন্য একটি সমাধি হিসেবে ব্যবহৃত হত এবং মিশরের ধর্মীয় বিশ্বাসের প্রতিফলন ঘটায়। পিরামিডের অভ্যন্তরে বিভিন্ন ধরনের চিত্রকর্ম এবং হায়ারোগ্লিফিক্স রয়েছে, যা প্রাচীন মিশরের জীবনযাত্রা এবং বিশ্বাসের চিত্র তুলে ধরে। পিরামিডের নির্মাণ প্রক্রিয়া এবং এর স্থাপত্য কৌশল আজও গবেষকদের জন্য একটি রহস্য।</p>
<h2 id="২-হ্যাংগিং-গার্ডেনস-অফ-বাবিলন">২. হ্যাংগিং গার্ডেনস অফ বাবিলন</h2>
<h3 id="ইতিহাস-ও-নির্মাণ-1">ইতিহাস ও নির্মাণ</h3>
<p>হ্যাংগিং গার্ডেনস অফ বাবিলন, যা প্রাচীন বাবিলনের একটি কিংবদন্তি উদ্যান হিসেবে পরিচিত, এটি সম্ভবত নবুকাদনেজার দ্বিতীয়ের সময়ে নির্মিত হয়েছিল। যদিও এর সঠিক অবস্থান এবং অস্তিত্ব নিয়ে বিতর্ক রয়েছে, তবে এটি একটি অসাধারণ স্থাপত্য নিদর্শন হিসেবে বিবেচিত হয়। এই উদ্যানটি স্তরবদ্ধভাবে নির্মিত হয়েছিল, যেখানে বিভিন্ন স্তরে বিভিন্ন ধরনের গাছপালা এবং ফুলের বাগান ছিল।</p>
<h3 id="ঐতিহ্য-ও-সাংস্কৃতিক-গুরুত্ব-1">ঐতিহ্য ও সাংস্কৃতিক গুরুত্ব</h3>
<p>এই উদ্যানটি প্রাচীন বিশ্বের একটি চমৎকার উদাহরণ, যা মানব সৃষ্টির সৌন্দর্য এবং প্রকৃতির সাথে মানুষের সম্পর্ককে তুলে ধরে। এটি প্রাচীন সভ্যতার উদ্যানবিদ্যা এবং কৃষির উন্নতির প্রতীক। হ্যাংগিং গার্ডেনসের সৌন্দর্য এবং স্থাপত্যের নৈপুণ্য আজও মানুষের কল্পনাকে আকৃষ্ট করে।</p>
<h2 id="৩-স্ট্যাচু-অফ-জিউস">৩. স্ট্যাচু অফ জিউস</h2>
<h3 id="ইতিহাস-ও-নির্মাণ-2">ইতিহাস ও নির্মাণ</h3>
<p>স্ট্যাচু অফ জিউস, যা গ্রীসের অলিম্পিয়ায় অবস্থিত ছিল, এটি প্রাচীন গ্রীক শিল্পের একটি অসাধারণ নিদর্শন। এটি প্রায় 435 খ্রিস্টপূর্বাব্দে নির্মিত হয়েছিল এবং এটি জিউসের একটি বিশাল মূর্তি ছিল, যা সোনার এবং হাতির দাঁতের তৈরি। মূর্তিটি প্রায় 12 মিটার উচ্চ ছিল এবং এটি অলিম্পিয়ার মন্দিরের কেন্দ্রে স্থাপন করা হয়েছিল।</p>
<h3 id="ঐতিহ্য-ও-সাংস্কৃতিক-গুরুত্ব-2">ঐতিহ্য ও সাংস্কৃতিক গুরুত্ব</h3>
<p>এই মূর্তিটি গ্রীক ধর্মীয় বিশ্বাসের প্রতীক এবং অলিম্পিক গেমসের সাথে সম্পর্কিত। এটি গ্রীক শিল্পের উৎকর্ষতা এবং ধর্মীয় আচার-অনুষ্ঠানের গুরুত্বকে তুলে ধরে। জিউসের মূর্তিটি প্রাচীন গ্রীসের ধর্মীয় জীবনের একটি গুরুত্বপূর্ণ অংশ ছিল এবং এটি দর্শকদের মধ্যে গভীর শ্রদ্ধা এবং awe সৃষ্টি করত।</p>
<h2 id="৪-টেম্পল-অফ-আর্টেমিস">৪. টেম্পল অফ আর্টেমিস</h2>
<h3 id="ইতিহাস-ও-নির্মাণ-3">ইতিহাস ও নির্মাণ</h3>
<p>টেম্পল অফ আর্টেমিস, যা এফেসাসে অবস্থিত, এটি প্রাচীন গ্রীসের একটি গুরুত্বপূর্ণ মন্দির। এটি আর্টেমিস দেবীর উদ্দেশ্যে নির্মিত হয়েছিল এবং এর নির্মাণকাল প্রায় 550 খ্রিস্টপূর্বাব্দ। এই মন্দিরটি 127টি কলাম দ্বারা সমর্থিত ছিল, প্রতিটি কলাম ছিল 18 মিটার উচ্চ।</p>
<h3 id="ঐতিহ্য-ও-সাংস্কৃতিক-গুরুত্ব-3">ঐতিহ্য ও সাংস্কৃতিক গুরুত্ব</h3>
<p>এই মন্দিরটি প্রাচীন গ্রীক স্থাপত্যের একটি চমৎকার উদাহরণ এবং এটি ধর্মীয় আচার-অনুষ্ঠানের কেন্দ্রবিন্দু ছিল। এটি প্রাচীন গ্রীসের ধর্মীয় এবং সাংস্কৃতিক জীবনের একটি গুরুত্বপূর্ণ অংশ। মন্দিরের অভ্যন্তরে আর্টেমিসের বিভিন্ন চিত্র এবং মূর্তি ছিল, যা দেবীর প্রতি মানুষের শ্রদ্ধা এবং ভক্তির প্রতিফলন ঘটায়। এই মন্দিরটি প্রাচীন বিশ্বের অন্যতম বৃহৎ এবং সুন্দর স্থাপনা হিসেবে বিবেচিত হয়।</p>
<h2 id="৫-মাউসোলিয়াম-অফ-হালিকারনাসাস">৫. মাউসোলিয়াম অফ হালিকারনাসাস</h2>
<h3 id="ইতিহাস-ও-নির্মাণ-4">ইতিহাস ও নির্মাণ</h3>
<p>মাউসোলিয়াম অফ হালিকারনাসাস, যা বর্তমান তুরস্কের বড্রাম শহরে অবস্থিত, এটি মাউসোলাস নামক এক শাসকের সমাধি। এটি প্রায় 350 খ্রিস্টপূর্বাব্দে নির্মিত হয়েছিল এবং এর উচ্চতা ছিল প্রায় 45 মিটার। এই সমাধিটি তিনটি স্তরে নির্মিত ছিল, যেখানে প্রতিটি স্তর অলঙ্কৃত ছিল বিভিন্ন ধরনের ভাস্কর্য এবং শিল্পকর্ম দ্বারা।</p>
<h3 id="ঐতিহ্য-ও-সাংস্কৃতিক-গুরুত্ব-4">ঐতিহ্য ও সাংস্কৃতিক গুরুত্ব</h3>
<p>এই সমাধিটি স্থাপত্যের একটি অসাধারণ উদাহরণ এবং এটি প্রাচীন বিশ্বের একটি গুরুত্বপূর্ণ স্থাপনা। এটি স্থাপত্যের ইতিহাসে &#39;মাউসোলিয়াম&#39; শব্দটির উৎপত্তি ঘটায়, যা পরবর্তীতে সমাধির জন্য ব্যবহৃত হয়। মাউসোলিয়ামের নকশা এবং অলঙ্করণ প্রাচীন স্থাপত্যের উৎকর্ষতা এবং শিল্পের প্রতি মানুষের শ্রদ্ধা প্রকাশ করে। এটি প্রাচীন সভ্যতার স্মৃতিচিহ্ন হিসেবে আজও গুরুত্বপূর্ণ।</p>
<h2 id="৬-কলোসাস-অফ-রোডস">৬. কলোসাস অফ রোডস</h2>
<h3 id="ইতিহাস-ও-নির্মাণ-5">ইতিহাস ও নির্মাণ</h3>
<p>কলোসাস অফ রোডস, যা প্রাচীন গ্রীসের রোডস দ্বীপে অবস্থিত ছিল, এটি একটি বিশাল ব্রোঞ্জের মূর্তি ছিল যা সূর্য দেবতা হেলিয়াসকে প্রতিনিধিত্ব করত। এটি প্রায় 280 খ্রিস্টপূর্বাব্দে নির্মিত হয়েছিল এবং এর উচ্চতা ছিল প্রায় 33 মিটার। এই মূর্তিটি রোডসের প্রবেশপথে স্থাপন করা হয়েছিল, যা সমুদ্রযাত্রার জন্য একটি নির্দেশক হিসেবে কাজ করত।</p>
<h3 id="ঐতিহ্য-ও-সাংস্কৃতিক-গুরুত্ব-5">ঐতিহ্য ও সাংস্কৃতিক গুরুত্ব</h3>
<p>এই মূর্তিটি রোডসের স্বাধীনতার প্রতীক এবং এটি সমুদ্রযাত্রার জন্য একটি নির্দেশক হিসেবে কাজ করত। কলোসাসের নির্মাণ প্রাচীন গ্রীক স্থাপত্যের উদাহরণ এবং শিল্পের প্রতি মানুষের শ্রদ্ধা প্রকাশ করে। এটি প্রাচীন গ্রীসের সাংস্কৃতিক জীবনের একটি গুরুত্বপূর্ণ অংশ ছিল এবং এটি দর্শকদের মধ্যে গভীর প্রভাব ফেলত।</p>
<h2 id="৭-লাইটহাউস-অফ-আলেকজান্দ্রিয়া">৭. লাইটহাউস অফ আলেকজান্দ্রিয়া</h2>
<h3 id="ইতিহাস-ও-নির্মাণ-6">ইতিহাস ও নির্মাণ</h3>
<p>লাইটহাউস অফ আলেকজান্দ্রিয়া, যা ফারোস লাইটহাউস নামেও পরিচিত, এটি প্রাচীন মিশরের আলেকজান্দ্রিয়া শহরে অবস্থিত ছিল। এটি প্রায় 280 খ্রিস্টপূর্বাব্দে নির্মিত হয়েছিল এবং এর উচ্চতা ছিল প্রায় 100 মিটার। এই লাইটহাউসটি তিনটি স্তরে নির্মিত ছিল, যার শীর্ষে একটি আলোকবর্তিকা ছিল যা সমুদ্রযাত্রীদের জন্য নির্দেশক হিসেবে কাজ করত।</p>
<h3 id="ঐতিহ্য-ও-সাংস্কৃতিক-গুরুত্ব-6">ঐতিহ্য ও সাংস্কৃতিক গুরুত্ব</h3>
<p>এই লাইটহাউসটি সমুদ্রযাত্রার জন্য একটি গুরুত্বপূর্ণ নির্দেশক ছিল এবং এটি প্রাচীন বিশ্বের একটি প্রযুক্তিগত চমক। এটি স্থাপত্যের ইতিহাসে একটি গুরুত্বপূর্ণ স্থান অধিকার করে এবং আলেকজান্দ্রিয়ার সাংস্কৃতিক ঐতিহ্যের প্রতীক। লাইটহাউসের নকশা এবং নির্মাণ প্রক্রিয়া প্রাচীন প্রযুক্তির উৎকর্ষতা এবং মানুষের উদ্ভাবনী ক্ষমতার পরিচয় দেয়।</p>
<h1 id="উপসংহার">উপসংহার</h1>
<p>বিশ্বের সপ্তাশ্চর্যগুলি মানব সভ্যতার সৃষ্টিশীলতা, দক্ষতা এবং সাংস্কৃতিক ঐতিহ্যের প্রতীক। প্রতিটি স্থাপনা তার নিজস্ব ইতিহাস এবং গুরুত্ব বহন করে, যা আমাদের প্রাচীন সভ্যতার প্রতি শ্রদ্ধা জানায়। এই সপ্তাশ্চর্যগুলি আমাদের স্মরণ করিয়ে দেয় যে, মানবতা সবসময় নতুন কিছু সৃষ্টির জন্য চেষ্টা করে এসেছে এবং এই প্রচেষ্টা আমাদের ইতিহাসের একটি গুরুত্বপূর্ণ অংশ। এই ব্লগ পোস্টের মাধ্যমে আমরা বিশ্বের সপ্তাশ্চর্যগুলোর ইতিহাস, ঐতিহ্য, গুরুত্ব ও সাংস্কৃতিক প্রভাব সম্পর্কে জানলাম। আশা করি, এই তথ্যগুলো আপনাদের জন্য উপকারী হবে এবং আপনাদের জ্ঞানের ভাণ্ডারকে সমৃদ্ধ করবে।</p>

          ]]></content:encoded>
          <media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://rsinfo.vercel.app/images/posts/2024-12-25-the-seven-wonders-of-the-world/cover.avif"/>
          <media:content xmlns:media="http://search.yahoo.com/mrss/" medium="image" url="https://rsinfo.vercel.app/images/posts/2024-12-25-the-seven-wonders-of-the-world/cover.avif"/>          
        </item>
      
        <item>
          <guid>https://rsinfo.vercel.app/what-is-phishing-attack</guid>
          <title>ফিশিং অ্যাটাক কী? এটি কিভাবে হয়? এর থেকে বাঁচার উপায়</title>
          <description>ফিশিং একটি ইংরেজি শব্দ। এর মানে হলো প্রতারণা বা ধোকা দেওয়ার মাধ্যমে কারো নিকট থেকে তার ব্যক্তিগত বা ব্যাংক লেনদেন গত কোন তথ্য হাতিয়ে নেওয়া। </description>
          <link>https://rsinfo.vercel.app/what-is-phishing-attack</link>
          <pubDate>Fri, 31 May 2024 04:49:14 +0000</pubDate>
          
          <content:encoded><![CDATA[
            <div style="margin: 50px 0; font-style: italic;">
              If anything looks wrong, 
              <strong>
                <a href="https://rsinfo.vercel.app/what-is-phishing-attack">
                  read on the site!
                </a>
              </strong>
            </div>

            <p>হ্যালো টেকপ্রেমী বন্ধুরা, আশা করি সবাই ভালো আছেন। আজকে আমি শেয়ার করতে যাচ্ছি অনলাইনের একটি গুরুত্বপূর্ণ বিষয় নিয়ে। আশা করি পোস্টটি আপনাদের উপকারে আসবে। তাই সম্পূর্ণ পোস্টটি পড়তে ভুলবেন না।</p>
<p>বর্তমান যুগ ইন্টারনেটের যুগ। স্মার্টফোন ও অনলাইন ব্যতীত আমরা একটা দিনও কল্পনা করতে পারি না। আমাদের দৈনন্দিন জীবনকে সহজ ও স্মার্ট করার উদ্দেশ্যে অনলাইনে যোগাযোগ স্থাপন ও আর্থিক লেনদেন করে থাকি। এটা যেমন দৈনন্দিন জীবনব্যবস্থাকে সহজ করেছে, একইভাবে ব্যক্তিগত ও আর্থিক লেনদেন তথ্যের নিরাপত্তা ঝুঁকি তৈরি করেছে। নিরাপত্তা ঝুঁকি তৈরি করার ক্ষেত্রে প্রতারকদের নিকট সবথেকে জনপ্রিয় মাধ্যম হচ্ছে ফিশিং বা ফিশিং অ্যাটাক।তাই আজকে আমি ফিশিং অ্যাটাক সম্পর্কে আপনাদেরকে বিস্তারিত তথ্য জানাবো। পোস্টটি সম্পূর্ণ পড়ে দেখুন আপনার সাথে এরকম কোন ঘটনা ঘটেছে কিনা। আর ঘটে না থাকলে জেনে নিন ভবিষ্যতে ফিশিং থেকে বাঁচার উপায়।</p>
<h2 id="ফিশিং-অ্যাটাক-কী">ফিশিং অ্যাটাক কী?</h2>
<p>ফিশিং একটি ইংরেজি শব্দ। এর মানে হলো প্রতারণা বা ধোকা দেওয়ার মাধ্যমে কারো নিকট থেকে তার ব্যক্তিগত বা ব্যাংক লেনদেন গত কোন তথ্য হাতিয়ে নেওয়া। এটি এক ধরনের সাইবার অপরাধ, যেখানে অপরাধীরা কোন বিশ্বস্ত ব্যক্তি বা প্রতিষ্ঠানের বেশ ধারণ করে টার্গেট করা ব্যক্তিকে প্রতারণার ফাঁদে ফেলে বা যেকোন উপায়ে বোকা বানিয়ে তার সংবেদনশীল তথ্য, ব্যক্তিগত ও আর্থিক লেনদেন গত তথ্য যেমন ব্যাংকিং ইনফর্মেশন, ক্রেডিট কার্ডের বিবরণ, পাসওয়ার্ড, পিন কোড ইত্যাদি হাতিয়ে নেয়। এক্ষেত্রে তারা বিভিন্ন ধরনের প্রলোভন ব্যবহার করে থাকে। যাতে করে টার্গেটেড ব্যক্তি সহজেই প্রতারণার ফাঁদে পা দেয় এবং তার সংবেদনশীল তথ্য গুলো প্রতারকের হাতে তুলে দেয়। অনেক সময় ব্যক্তি বুঝতেও পারে না সেই ইতোমধ্যেই প্রতারিত হয়ে গেছে।প্রতারিত করে নেয়া এই তথ্য গুলোর মাধ্যমে ব্যাংক থেকে অর্থ চুরি সহ প্রতারিত ব্যক্তির গোপনীয় ও সংবেদনশীল তথ্যের এক্সেস গ্রহণ করে ব্ল্যাকমেইল করা হয়। অনেক সময় এই তথ্যগুলো ব্যবহার করে অনেক বড় বড় অপরাধ সংঘটিত হয় যার দায় গিয়ে পড়ে প্রতারিত ব্যক্তির উপর। এতে করে প্রতারিত ব্যক্তির জীবন অনেক সময় দুর্বিষহ হয়ে পড়ে। অনলাইন বা সাইবার জগতে ব্যক্তিগত তথ্যের নিরাপত্তা বিধান করার ক্ষেত্রে ফিশিং একটি বড় ধরনের হুমকি। ফিশিং থেকে বেঁচে থাকার কৌশল না জানলে যে কোনো সময় ব্যক্তিগত তথ্য নিরাপত্তা হুমকিতে পড়তে পারে।</p>
<h2 id="ফিশিং-এর-কিছু-সাধারণ-বৈশিষ্ট্য">ফিশিং এর কিছু সাধারণ বৈশিষ্ট্য</h2>
<ul>
<li>চটকদার বিজ্ঞাপন - অত্যন্ত আকর্ষণীয় ও চটকদার বিজ্ঞাপন যা সহজেই মানুষকে আকৃষ্ট করে। যেমন, অনেক সময় অনেক ওয়েবসাইটে প্রবেশ করলে দেখানো হয় যে আপনি একটি আইফোন জিতেছেন কিংবা একটি বড় অ্যামাউন্ট এর লটারি জিতেছেন। বা হতে পারে আপনি কোন বড় উপহার পেয়েছেন এই ধরনের লেখা সম্বলিত কোন তথ্য। মনে রাখবেন এটি যতই ভালো লাগুক এবং আকর্ষণীয় হোক না কেন এটি মিথ্যা প্রলোভন ব্যতীত আর কিছু নয়।</li>
<li></li>
<li>জরুরী অবস্থা - ফিশিং করার ক্ষেত্রে সাইবার অপরাধীরা আরেকটি সহজ কৌশল ব্যবহার করে থাকে, সেটি হচ্ছে মানুষকে বিভ্রান্ত করা। এরকম ক্ষেত্রে আপনাকে দেখানো হয় যে আপনার ফোনে কোন ভাইরাস কিংবা ম্যালওয়্যার আছে। এটি থেকে আপনার ডিভাইসকে নিরাপদ করতে হলে তারা তাদের থেকে অ্যাপস ডাউনলোড করতে বলে। অনেক সময় আপনাকে এটাও দেখানো হয় যে অনলাইনে আপনার গুরুত্বপূর্ণ কোন অ্যাকাউন্ট শীঘ্রই ডিএক্টিভেট কিংবা বন্ধ করে দেয়া হবে যার থেকে বাঁচার জন্য তারা আপনার নিকট সেই অ্যাকাউন্ট সম্পর্কিত তথ্যগুলো চেয়ে থাকে। এই অবস্থায় মানুষজন কিংকর্তব্যবিমূঢ় হয়ে তাদের তথ্যগুলো অনলাইন প্রতারকদের প্রদান করে থাকে। যার মাধ্যমে তারা ফিশিং অ্যাটাক এর শিকার হয়।</li>
<li></li>
<li>ইমেইলের মাধ্যমে - উপরোক্ত বিষয়গুলো শুধুমাত্র ওয়েবসাইটে না দেখিয়ে অনেক সময় ইমেইলমআকারে প্রেরণ করে থাকে। এক্ষেত্রে তারা তাদের ইমেইল কে কোন বিশ্বস্ত বা বড় প্রতিষ্ঠানের ইমেইল ও নামের সাথে মিল রাখার চেষ্টা করে। যাতে করে টার্গেটের ব্যক্তি সেই ই-মেইল কে বিশ্বস্ত বা বড় প্রতিষ্ঠানের ইমেইল ভেবে ভুল করে থাকে। আর এভাবেই তারা প্রতারণার ফাঁদে পা দিয়ে থাকে।
এছাড়াও মাঝে মাঝে অনেক অপরিচিত ব্যক্তির নিকট থেকে দাতব্য সংস্থার নাম করে আপনাকে অর্থ প্রেরণের কথা বলা হয়ে থাকে। এক্ষেত্রে তারা আপনার ব্যক্তিগত ব্যাংকের তথ্য চেয়ে থাকে যাতে তারা আপনাকে অর্থ প্রেরণ করতে পারে। তাদের এসব ফল উপন্যাস প্রস্তাব সহজে আমরা বুঝতে পারি না। উপরন্ত এগুলোর মোহ আমাদেরকে আকৃষ্ট করে। ফলে আমরা তাদেরকে বিশ্বাস করি ব্যক্তিগত তথ্য প্রদান করি এবং প্রতারণার শিকার হই।</li>
<li></li>
<li>হাইপারলিংক - অনেক সময় আপনাকে একটি প্রলোভন মূলক লিংক প্রেরণ করা হয়। আপাত দৃষ্টিতে সেই লিংকটিকে কোন অসাধু চক্র সাধনের উপায় মনে নাও হতে পারে। বাইরে থেকে দেখতে তা গ্রহণযোগ্য লিংক মনে হলেও এর ভেতরে ফিশিং লিংক মাস্কিং করে দেয়া থাকতে পারে। সে ক্ষেত্রে লিংকে ক্লিক করার পূর্বে লিংক প্রেরণকারী ব্যক্তির বিশ্বস্ততা এবং নিরাপত্তা ঝুঁকির কথা বিবেচনায় রাখা উচিত।</li>
<li></li>
<li>নামের বিভ্রাট - অনেক সময় আপনাকে যে নাম বা লিংক থেকে মেসেজ বা ইমেইল প্রেরণ করা হয় তা কোন প্রতিষ্ঠিত ও বিশ্বস্ত ব্যক্তি বা প্রতিষ্ঠানের নামের বা লিংকের বানানের সাথে প্রায় সাদৃশ্যপূর্ণ বানান হয়ে থাকে। সামান্য কিছু পরিবর্তন যা সাধারণত চোখে পড়ার মত নয় এমন ধরনের হয়ে থাকে। যা দ্বারা আমরা সহজেই প্রতারণার শিকার। এ ধরনের কোনো লিংক আমাদের নিকট আসলে অবশ্যই ভালোভাবে তা পর্যবেক্ষণ করার পরই তাতে ক্লিক করা উচিত।</li>
</ul>
<h2 id="ফিশিং-এর-প্রকারভেদ">ফিশিং এর প্রকারভেদ</h2>
<p>অপরাধীরা ফিশিং করার ক্ষেত্রে যেভাবে ও যে মাধ্যমগুলো ব্যবহার করে তা সম্পর্কে নিম্নে আলোচনা করা হলোঃ</p>
<ul>
<li>ইমেইল ফিশিং - এই পদ্ধতিতে প্রতারকেরা ব্যবহারকারীর নিকট বিভিন্ন সু-প্রতিষ্ঠিত বা সুপরিচিত ব্যাংক, কুরিয়ার সার্ভিস, অনলাইন শপিং ওয়েবসাইট, অনলাইন ক্যাসিনো কিংবা দাতব্য সংস্থার মতো দেখতে প্রায় একই নামে বা লিংকে ইমেইল প্রেরণ করে থাকে। ইমেইলে তারা ব্যবহারকারীকে তার একাউন্টে কোন সমস্যা আছে বা সে কোন লোভনীয় পুরস্কার জিতেছে এই বিষয়ে বলা হয়ে থাকে। তারপর তারা ব্যবহারকারীকে একটি লিংকে ক্লিক করে সেই সমস্যার সমাধান কিংবা পুরস্কারটি গ্রহণ করতে বলে সেখানে ক্লিক করলে ব্যবহারকারীকে এমন একটি ওয়েবসাইটে নিয়ে যাওয়া হয় যেখানে ব্যবহারকারীকে তার ব্যক্তিগত একাউন্টের তথ্য ব্যবহার করে লগইন করতে বলা হয় যা প্রতারকেরা সংগ্রহ করে নেয়।</li>
<li></li>
<li>ওয়েবসাইট ফিশিং - এই পদ্ধতিতে প্রতারকেরা কোন জনপ্রিয় কিংবা বিশ্বস্ত ওয়েবসাইটের নকল করে একই রকম দেখতে আর একটি ভুয়া ওয়েবসাইট তৈরি করে। সাধারণত যেটি দেখতে অনেকটা আসল ওয়েবসাইটের মতোই মনে হয়। তারপর তারা বিভিন্ন প্রন্থা ব্যবহার করে ব্যবহারকারীদেরকে সেই ভুয়া ওয়েবসাইটে যেতে বলব দেখায়। এক্ষেত্রে তারা সার্চ ইঞ্জিন অপটিমাইজেশন, সামাজিক যোগাযোগ মাধ্যমে লিংক শেয়ার কিংবা ব্যানার বা পপ আপ বিজ্ঞাপনের মাধ্যমে প্রলোভন দেখানো ইত্যাদি। ব্যবহারকারীরা সেই ফিশিং সাইটে প্রবেশ করার পর সেখানে তাদেরকে লগইন কিংবা রেজিস্ট্রেশন করতে বাধ্য করা হয়। এভাবে তথ্যগুলো প্রতারকরা হাতিয়ে নেয়।</li>
<li></li>
<li>ভার্চুয়াল ফিশিং - এই পদ্ধতিতে প্রতারকরা কোন জনপ্রিয় কিংবা প্রতিষ্ঠিত ওয়েবসাইটের নকল তৈরি করে। আসল সাইট মনে করে ভুলবশত এসব সাইটে প্রবেশ করলে প্রতারকরা ভার্চুয়াল মেশিন চালিয়ে ব্যবহারকারীর তথ্য হাতিয়ে নেয়। ব্যবহারকারীর কুকি, ব্রাউজার হিস্ট্রি, ক্যাশ সার্ভার, ফর্ম ডাটা ইত্যাদি চুরি করে নেয়। যা থেকে তারা ব্যবহারকারীর গোপন তথ্য গুলোর একসেস নেয়।</li>
<li></li>
<li>উপরোক্ত ফিশিং পদ্ধতিগুলো ছাড়াও প্রতারকরা আরো বিভিন্ন ধরনের ফিশিং পদ্ধতি ব্যবহার করে থাকে। তাদের মধ্যে প্রচলিত কিছু যেমন ভিশিং (Vishing), স্মিশিং (Smishing), স্পিয়ার ফিশিং (Spear phising), ওয়ালিং (Whaling), ক্লোন ফিশিং (Clone Phishing), স্নো শোভিং (Snowshoeing) ইত্যাদি ফিশিং পদ্ধতির ব্যবহার করে থাকে।</li>
</ul>
<h2 id="ফিশিং-থেকে-বাচার-উপায়">ফিশিং থেকে বাচার উপায়</h2>
<p>ফিশিং থেকে নিরাপদ থাকার শ্রেষ্ঠ উপায় হচ্ছে সতর্কতা অবলম্বন করা। সন্দেহজনক কোনো বিজ্ঞাপন, ওয়েবসাইট, ইমেইল কিংবা লিংকে প্রবেশ করার পূর্বে সতর্কতা অবলম্বন করা। নিম্নে আরো কিছু টিপস প্রদান করা হলোঃ</p>
<ul>
<li>যেকোনো লিংকে ক্লিক করার পূর্বে লিংকের ঠিকানা ও এটি বিশ্বাসযোগ্য সোর্স থেকে এসেছে কিনা তা সম্পর্কে নিশ্চিত হওয়া।</li>
<li></li>
<li>ইমেইলের সাথে আসা অ্যাটাচমেন্ট ডাউনলোড করার পূর্বে প্রেরক ইমেইলের ঠিকানা ও সাথে থাকা ফাইলগুলো সম্পর্কে পূর্বেই ধারণা লাভ করা।</li>
<li></li>
<li>যেকোনো ওয়েবসাইটে প্রবেশের পর আপনার সামনে উপস্থাপিত এলাও (Allow) বাটন এড়িয়ে চলুন।</li>
<li></li>
<li>যেকোনো অ্যাপস বা সফটওয়্যার ইন্সটল এর পূর্বে অ্যাপস বা সফটওয়্যারটি কি কি অনুমতি চাচ্ছে সেটি ভালো করে পড়ে নিন। যদি এটি আপনার ব্যক্তিগত তথ্য কিংবা ডিভাইস কন্ট্রোলের অনুমতি চায় তাহলে এটিকে সন্দেহের তালিকায় রাখুন। এই অ্যাপস বা সফটওয়্যার সম্পর্কে ভালোভাবে জেনে তারপর ইন্সটল করুন। অন্যথায় এটি ইন্সটল পরিহার করুন।</li>
<li></li>
<li>আপনি যে ওয়েবসাইটটিতে প্রবেশ করতে যাচ্ছেন সেটিতে নিরাপত্তা সার্টিফিকেট (ব্রাউজারের এড্রেসবারের বামপাশে সবুজ রঙের তালা চিহ্ন) আছে কিনা সেটি ভালো করে লক্ষ্য করুন।</li>
<li></li>
<li>যেকোনো ওয়েবসাইটে আপনার ব্যক্তিগত তথ্য বা পাসওয়ার্ড প্রবেশের পূর্বে ভালোভাবে লক্ষ্য করে নিন সাইটের ঠিকানায় সবুজ রঙের লক আইকন এবং https (শুধুমাত্র http যুক্ত ওয়েবসাইট এড়িয়ে চলুন) আছে কিনা। এটি আপনার তথ্যের এনক্রিপশন নিশ্চিত করার মাধ্যমে নিরাপত্তা প্রদান করে।</li>
<li></li>
<li>বিভিন্ন ওয়েবসাইটে বিদ্যমান থাকা আপনার একাউন্ট গুলোতে ভিন্ন ভিন্ন পাসওয়ার্ড ব্যবহার করুন। এবং একটি নির্দিষ্ট সময় পরপর পাসওয়ার্ড পরিবর্তন করুন। সর্বদা সংখ্যার সাথে বিভিন্ন বিভিন্ন অক্ষর ও স্পেশাল ক্যারেক্টার সম্বলিত পাসওয়ার্ড ব্যবহার করুন। পাসওয়ার্ড এর দৈর্ঘ্য অবশ্যই 8 থেকে 16 ক্যারেক্টার এর ভিতরে রাখুন।</li>
<li></li>
<li>বিভিন্ন অনলাইন একাউন্টিং নিরাপত্তায় টু ফ্যাক্টর অথেন্টিকেশন (Two Factor Authentication) ব্যবহার করুন। এটি আপনার একাউন্টের নিরাপত্তা বৃদ্ধিতে সহায়তা করবে।</li>
</ul>
<h2 id="শেষ-কথা">শেষ কথা</h2>
<p>ইন্টারনেটের ব্যবহার আমাদের জীবনকে সহজ ও আরামদায়ক করেছে। দিন দিন ইন্টারনেটের ব্যবহার বাড়বে। অনলাইন ঝুঁকিও বাড়বে। যেহেতু আমরা ইন্টারনেট ব্যবহার বন্ধ করতে পারবো না। সেহেতু আমাদেরকে অনলাইনে থাকা ব্যক্তিগত তথ্যের নিরাপত্তা নিশ্চিত করতে হবে। অন্যথায় আমরাই এটার ভোগান্তির শিকার হবো। একটু সচেতনতা আর সজাগ দৃষ্টিই পারে অনলাইন প্রতারণার হাত থেকে আমাদের তথ্যের নিরাপত্তা নিশ্চিত করতে। দিন দিন ইন্টারনেট ব্যবহারের পদ্ধতি যেমন পরিবর্তন হচ্ছে, তেমনিভাবে প্রতারকরাও নিত্য নতুন ভিন্ন ভিন্ন পন্থায় প্রতারণার ফাঁদ তৈরি করছে। তাই আমাদেরকে ফিশিং এবং স্পামিং থেকে সতর্ক থাকতে হবে।আজকে এ পর্যন্তই। সবার ইন্টারনেট ব্যবহার নিরাপদ হোক। সবাই ভালো থাকবেন।</p>

          ]]></content:encoded>
          <media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://rsinfo.vercel.app/images/opengraph-domain-icon.svg"/>
          <media:content xmlns:media="http://search.yahoo.com/mrss/" medium="image" url="https://rsinfo.vercel.app/images/opengraph-domain-icon.svg"/>          
        </item>
      
        <item>
          <guid>https://rsinfo.vercel.app/automating-social-media-preview-images-satori</guid>
          <title>Automating Social Media Preview Images</title>
          <description>Social media preview images are very useful if you want to attract people to your website. They're sometimes a pain to create, though. Let's automate it!</description>
          <link>https://rsinfo.vercel.app/automating-social-media-preview-images-satori</link>
          <pubDate>Sun, 05 May 2024 22:15:42 +0000</pubDate>
          
          <content:encoded><![CDATA[
            <div style="margin: 50px 0; font-style: italic;">
              If anything looks wrong, 
              <strong>
                <a href="https://rsinfo.vercel.app/automating-social-media-preview-images-satori">
                  read on the site!
                </a>
              </strong>
            </div>

            <p><img src="https://fantinel.dev/opengraph?text=This%20image%20was%20generated%20automatically!" alt="Image with my website&#39;s visual identity and the title of this blog post written on it"></p>
<p>Social media preview images (or open graph images, or og images) are very useful if you want to attract people to your website. Displaying that neat blog post featured image on the link preview might be the difference between someone scrolling past your link or clicking on it. Plus, it looks neat.</p>
<p>Problem is, not all blog posts have an image. Maybe it&#39;s just a quick thought, or something so abstract you just can&#39;t figure out a good image to put in there. Your blog layout is fine if you don&#39;t add an image, but what happens when that link is shared? Maybe nothing will show up and people will miss it? Or maybe the more generic fall-back image of your website will show up in there. And how will people mindlessly scrolling on social media know what your link is about?</p>
<p>Luckily for us lazy people, there&#39;s a way of automating them!</p>
<h2 id="generating-images-from-html-using-satori">Generating images from HTML using Satori</h2>
<p>This is kind of an old problem that has had a few solutions in the past, but none of them were really great. Depending on how long you&#39;ve been coding, you might have used packages like <code>html2png</code> or something similar, and if you did, you probably remember it never really worked well and had plenty of limitations.</p>
<p>Enter <a href="https://github.com/vercel/satori">Satori</a>. It&#39;s a library developed by Vercel that actually converts HTML and CSS to SVG. SVGs are way easier to convert to images than HTML, so that&#39;s why they decided to go down this route. They then provide their own solution for converting to a PNG, but honestly, that&#39;s not a big deal and you can roll your own quite easily (I did!).</p>
<h2 id="why-not-just-screenshot-a-page-some-sites-do-that">Why not just screenshot a page? Some sites do that!</h2>
<p>If you&#39;re searching for this topic, you&#39;ve probably found <a href="https://www.zachleat.com/web/automatic-opengraph/">some articles</a> talking about a method of generating these images by creating a page on your website that looks the way you want, and then using a serverless function to spin up an instance of Chromium, load your site, and take a screenshot of it.</p>
<p>That approach makes a lot of sense - I even used it briefly! - but it has three main problems:</p>
<ol>
<li>It&#39;s <strong>slow!</strong> Spinning up Chromium on a server, waiting for the page to load, taking the screenshot and downloading it are a lot of considerably large steps. </li>
<li>It&#39;s <strong>inefficient!</strong> Spinning up an entire browser just to grab a screenshot sounds really wasteful. If you&#39;re in a paid plan, it&#39;s expensive too.</li>
<li>It <strong>probably won&#39;t  work.</strong> Which might actually be the #1 reason not to use it. <span>Most of those articles were written years ago</span>, when the headless version of Chromium that&#39;s used on those serverless functions was smaller. Nowadays, <span>it takes up more than 50MB</span>, which is the maximum limit of serverless functions! There are technically still <a href="https://www.stefanjudis.com/blog/how-to-use-headless-chrome-in-serverless-functions/">some ways of working around that limit</a>, but those break often and are not guaranteed to work in the long run. Chromium is likely to keep growing.</li>
</ol>
<p>So, with that out of the way, we can now talk about how Satori works.</p>
<h2 id="the-more-efficient-albeit-slightly-limited-way">The more efficient, albeit slightly limited way</h2>
<p><a href="https://vercel.com/blog/introducing-vercel-og-image-generation-fast-dynamic-social-card-images">In their announcement blog post</a>, Vercel explains that they built Satori to counter the problems of the previous approach. In order to avoid running into the same speed and inefficiency problems, they wanted to avoid using any browser engine. So, they use the same layout engine as React Native, which, while not a complete CSS implementation, still has good parity in results for most cases.</p>
<p>The nice thing about that is that it&#39;s lightweight and reliable. The bad things is that it has some caveats:</p>
<ul>
<li>It only supports a subset of CSS. So, no Grid support, for example. But considering you&#39;re using this for generating preview images and not really something complex, it&#39;s a fair tradeoff. <a href="https://github.com/vercel/satori?tab=readme-ov-file#css">Their GitHub page</a> details what it does and does not support;</li>
<li>It expects JSX syntax for elements. If you&#39;re working on a project that doesn&#39;t use it, that&#39;d require another dependency and a build step. Additionally, you can also pass JS objects that have <code>type</code>, <code>props.children</code> and <code>props.style</code>. It&#39;s good for not needing another dependency, but it&#39;s <em>really</em> hard to read. Or you can use <a href="https://github.com/natemoo-re/satori-html">satori-html</a>, a package that translates HTML and CSS into JSX so you can just write good ol&#39; web code.</li>
</ul>
<h2 id="where-to-run-it">Where to run it</h2>
<p>In case it&#39;s not yet clear, you need to have some sort of backend in order to run this. That way, you can make your backend return an image file instead of a page or something else.</p>
<p>Luckily, a bunch of frameworks include that nowadays. SvelteKit, Next JS, Astro, and others, all allow you to create some endpoints inside your web app. And, if you host things on platforms like Vercel or Netlify, you can probably have all that working for free (or included in the plan you already have).</p>
<p>On SvelteKit, you can just create a route with a server file (<code>+server.js</code>). On Next JS, you can add a new route to the <code>/api</code> folder. Other frameworks may vary, but it shouldn&#39;t be that hard!</p>
<p>If you have a static site or something else and can&#39;t run it, I haven&#39;t really done much research into how it can be done. But I believe you can still use the free tier of <a href="https://vercel.com/docs/functions/quickstart">Vercel Functions</a>, for example, to get that working.</p>
<h2 id="my-implementation">My implementation</h2>
<blockquote>
<p>[!info] 
In order to set it up on my site, I followed <a href="https://geoffrich.net/posts/svelte-social-image/">this post from Geoff Rich</a> that goes deep into how things work and how to build things. I&#39;m not gonna try to rewrite his post because there&#39;s really no need - his is already amazing, so if you&#39;re looking into a tutorial, definitely follow his instead of mine.</p>
</blockquote>
<p>Since I use SvelteKit, I created a new <code>/opengraph</code> route with a <code>+server.js</code> file that does the magic. It receives some params via query string (like the text of the image) and then returns back the generated image.</p>
<p>Since I don&#39;t use JSX and didn&#39;t wanna add that to my project, I used <a href="https://github.com/natemoo-re/satori-html">satori-html</a> to convert HTML and CSS to it. Additionally, I used <a href="https://github.com/yisibl/resvg-js">resvg-js</a> to convert the SVG that Satori generates into a PNG. </p>
<p>To make things even nicer, I moved the HTML and CSS code into a Svelte component, added the <code>text</code> variable, and then imported that on the server file. In the end, the code goes through this entire flow: Svelte -&gt; HTML -&gt; SVG -&gt; PNG! It looks roughly like this:</p>
<pre><code class="language-javascript">~filename +server.js

const componentResult = component.render();  
const htmlString = satoriHtml(componentResult.html);  
const svg = await satori(htmlString, satoriConfig);  
const image = new Resvg(svg, resvgConfig).render();  
return new Response(image.asPng(), {  
    headers: {  
        &#39;content-type&#39;: &#39;image/png&#39;  
    }  
};
</code></pre>
<p>After that, I can just make my <code>og:image</code> meta tag point to that endpoint:</p>
<pre><code class="language-svelte">&lt;meta property=&quot;og:image&quot; content={`https://fantinel.dev/opengraph?text={encodeURIComponent(post.title)}`} /&gt;
</code></pre>
<p>And... that&#39;s it! All my posts that don&#39;t have an explicitly set cover image will now have at least a good looking related image that shows up on social media.</p>

          ]]></content:encoded>
          
                    
        </item>
      
        <item>
          <guid>https://rsinfo.vercel.app/thinking-of-a-redesign</guid>
          <title>Thinking of a redesign</title>
          <description>I want my personal website to reflect a bit of who I am. Am I the same person I was 3-4 years ago?</description>
          <link>https://rsinfo.vercel.app/thinking-of-a-redesign</link>
          <pubDate>Fri, 29 Mar 2024 04:02:11 +0000</pubDate>
          
          <content:encoded><![CDATA[
            <div style="margin: 50px 0; font-style: italic;">
              If anything looks wrong, 
              <strong>
                <a href="https://rsinfo.vercel.app/thinking-of-a-redesign">
                  read on the site!
                </a>
              </strong>
            </div>

            <p>I recently wrote about <a href="https://rsinfo.vercel.app/5-year-blog-anniversary">my website’s 5th anniversary</a>, and made a little retrospective of its past layouts. Which made me realize it has looked pretty much the same for the last 3 or 4 years.</p>
<p>Which is… really not that long? In the grand scheme of things it’s still quite recent. You can also argue that this consistency is good for my “personal brand”. You see green waves, you’re on my website (or in <a href="https://github.com/matfantinel/fantinel.dev/forks">some of the many forks</a> around the web). And people seem to like it. A lot of people forked, copied, or rebuilt something similar for their websites. I even got hired to branch it out into <a href="https://github.com/matfantinel/sveltekit-static-blog-template">a separate template</a>. That makes me really happy, not only because it shows that people like what I built, but because my work is helping them like many other people’s work helped me (and still do).</p>
<p>On the other hand, I’m a person, not a brand. I want my personal website to reflect a bit of who I am. Am I the same person I was 3-4 years ago? Yes, but not really. I changed a lot, hopefully for the better, and maybe it’s time for my website to do the same.</p>
<p>There’s this fear of ending up with something I don’t like as much as I like the current one. Fear that I’ll waste time or that I’ll regret the changes a year from now.</p>
<p>But I think that if it does actually end up objectively worse, it just means I haven’t changed enough to express myself differently, which I guess will make me happier with what it is right now. Plus, I’ll have the experience of knowing I tried. Worst case scenario, it’ll end up exactly like it is now, but with me a little wiser.</p>
<p>Best case scenario, the 10-years retrospective will be more interesting ;)</p>

          ]]></content:encoded>
          
                    
        </item>
      
        <item>
          <guid>https://rsinfo.vercel.app/5-year-blog-anniversary</guid>
          <title>5 Years of Fantinel.dev!</title>
          <description>My website has existed for half of my professional life now. In this post I look back at some snapshots of its history and talk about what's next.</description>
          <link>https://rsinfo.vercel.app/5-year-blog-anniversary</link>
          <pubDate>Fri, 08 Mar 2024 12:05:36 +0000</pubDate>
          
          <content:encoded><![CDATA[
            <div style="margin: 50px 0; font-style: italic;">
              If anything looks wrong, 
              <strong>
                <a href="https://rsinfo.vercel.app/5-year-blog-anniversary">
                  read on the site!
                </a>
              </strong>
            </div>

            <p>On this day, 5 years ago, I launched my blog alongside <a href="https://rsinfo.vercel.app/purpose-of-this-blog">its first post</a>! Back then, I had little idea if I was gonna keep writing or maintaining it. Well... turns out I did!</p>
<h2 id="the-first-days">The First Days</h2>
<p>This blog actually began as a <a href="https://ghost.org">Ghost</a> blog, using its default theme. Ghost was great as a starting point as it provided a quick way to get up and running, and most importantly, a quick way to start <em>writing</em>. Back then I had a couple ideas for blog posts related to stuff I was doing at work - I believe they were the two posts about PWAs (<a href="https://rsinfo.vercel.app/angular-pwa-how-to">How to transform your Angular app into a PWA</a> and <a href="https://rsinfo.vercel.app/what-are-pwas-and-why-should-i-care-about-them">What are PWAs</a>). So, back then, to me, it was more important to get started with writing than to have the perfect blog setup.</p>
<p>Unfortunately, I don&#39;t have a screenshot of what it looked like back then, but since it used the default Ghost theme (Casper), I guess it doesn&#39;t matter much.</p>
<p>Five months later (October, 2019), I released the first version of this blog built by my own hands. It was built with <a href="https://jekyllrb.com/">Jekyll</a>, a Ruby-based static site generator that I chose because it was fully supported by GitHub Pages (GitHub&#39;s own static website hosting service - it&#39;s free!). All posts were stored in Markdown files (that&#39;s still true to this day!), and building it was quite fun!</p>
<p>I didn&#39;t have the skills or courage to design something from scratch yet, so I opted to almost completely clone Ghost&#39;s default theme. Here&#39;s what it looked like:</p>
<p><img src="https://rsinfo.vercel.app/images/posts/5-year-blog-anniversary/v1.png" alt="Screenshot of the first version of my website, in light and dark themes. It contains a big section saying &quot;Hey, Matheus Fantinel here.&quot;. Below, a card with a picture of me and some text that&#39;s too small to read describing myself." title="Fantinel.dev v1, October 2019"></p>
<p>Although I think it&#39;s definitely evolved since then, it still has its charm. The big hero with my name had a typing effect that thankfully <a href="https://web.archive.org/web/20200105151225/http://fantinel.dev/">you can still check out thanks to the Wayback Machine</a>.</p>
<p>Even back then, I had some main goals for the website, that I had written on the project&#39;s README:</p>
<blockquote>
<p>It was built with a few goals in mind:<br><br>• Responsive design: the website looks and behaves well on screens of all sizes;
• Fast: it only loads what&#39;s needed for it to work. No external JS or CSS libraries:
• Adaptive: it supports dark mode from most operating systems by default (desktop and mobile);
• Pretty: use a simple and organized layout with simple animations to provide a pleasant experience to all visitors.</p>
</blockquote>
<p>That&#39;s still what I strive for nowadays with the website, so I&#39;m glad 2019 me set the path to where it is right now 😊.</p>
<h2 id="version-20">Version 2.0</h2>
<p>For Version 2.0, I decided to do a big redesign of the website, and add a bit more of <em>me</em> into it, instead of it being a carbon copy of a theme. It&#39;s the first time I added the &quot;waves&quot; effect on the homepage, and since I wanted to design everything myself BUT don&#39;t have much design skills, I relied heavily on cards to organize content (I still rely on cards often). Unfortunately, there&#39;s no (working) snapshot of this version of the website on the Wayback Machine, so unless I run it locally (I&#39;m too lazy to do it), all we have is this screenshot:</p>
<p><img src="https://rsinfo.vercel.app/images/posts/5-year-blog-anniversary/v2.png" alt="Screenshot of the second version of my website, in light and dark themes. There is a green background with a &quot;wavy&quot; effect behind a big card with my picture and information about me. || no-shadow" title="Fantinel.dev v2, November 2020"></p>
<p>Overall, I think this is my least favorite version of it. I really like the waves effect (I still have it today), but I feel like the content didn&#39;t have enough weight. Still, it set the precedent for what the website would look like today, with the colors and overall layout.</p>
<h2 id="version-30">Version 3.0</h2>
<p>This was a big rewrite, and brought it really close to what it&#39;s like today. It was a complete rebuild from the ground up, now using Svelte and SvelteKit, replacing Jekyll. <a href="https://rsinfo.vercel.app/blog-development-sveltekit">I wrote about how I built it</a>, and it became my most read post of all time!</p>
<p>If you open it <a href="https://web.archive.org/web/20211006092452/https://fantinel.dev/">on the Wayback Machine</a> and compare to the current site, it mostly looks the same. I still think the layout is not perfect, but I haven&#39;t found a better way of displaying information about me yet.</p>
<p><img src="https://rsinfo.vercel.app/images/posts/5-year-blog-anniversary/v3.png" alt="Screenshot of the third version of my website. It has a background that resembles waves, and a greeting &quot;Hello, I&#39;m Matt!&quot; front and center. There&#39;s an illustrated version of me wearing glasses. || no-shadow" title="Fantinel.dev v3, September 2021"></p>
<p>I guess the main difference is that I lost the glasses.</p>
<h2 id="version-40-current">Version 4.0 (current)</h2>
<p>On February, 2023, I released the current version of the website, aptly named v4. Visually, it really wasn&#39;t much of a change, but it included big changes under the hood, with me adopting atomic design for components, TypeScript, and some interactive stuff like the theme toggle. There were still some visual tweaks, like better positioning of some elements in the home page, but nothing major.</p>
<p><img src="https://rsinfo.vercel.app/images/posts/5-year-blog-anniversary/v4.png" alt="Screenshot of the fourth version of my website. It still has a wavy background, but the content is positioned in more readable ways. || no-shadow" title="Fantinel.dev v4, February 2023"></p>
<h2 id="looking-back-at-it-all">Looking back at it all</h2>
<p>On my first ever post, I wrote that the purpose of this blog was to help myself learn about the topics I write here. And it certainly helped with that. A lot of posts here feel like guides because they are - initially a guide to myself that I decided to publish for everyone. And I&#39;m glad I did! I don&#39;t have the numbers since the beginning, but at least since January 2021, <span>this site was visited by 43.4k people</span>! 🤯 That&#39;s a lot. I never expected so many people to drop in and read something I wrote. And considering most of the visitors got here from Google and into one of the guide/help articles, I hope I helped them somehow. Blog posts have been a huge source of help to me over the past years, and I&#39;m happy to be giving back to the dev community.</p>
<p>(by the way, all my blog&#39;s analytics data is fully anonymized and public. <a href="https://plausible.io/fantinel.dev?period=all">You can check it out on Plausible</a>)</p>
<p>But most of all, this website has been by itself a source of learning for me. More than writing, I think I learned more from building and experimenting on it, and I really don&#39;t plan on stopping. It&#39;s my testing grounds, a way to reflect a bit of who I am, and most of all, have fun.</p>
<h2 id="next-steps">Next steps</h2>
<p>On the dev side, I want to keep experimenting. I have some small redesigns planned that I just need time to work on. More importantly, I&#39;m trying really hard to simplify the writing process so I can write more, and more often, from anywhere.</p>
<p>And on the writing side, I really wanna expand the topics I write about. The “blogging renaissance” that&#39;s been going on lately has really inspired me to have this blog be less of a content repository and more of... Matt&#39;s blog. Last year I already started with some purely personal posts and I&#39;m thinking of doubling down on that. But, that&#39;s only good if it comes naturally, I won&#39;t force myself to write stuff I don&#39;t want to. We&#39;ll see.</p>
<p>The only thing I&#39;m certain of is that I want to keep it going.</p>

          ]]></content:encoded>
          <media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://rsinfo.vercel.app/images/posts/5-year-blog-anniversary/cover.jpg"/>
          <media:content xmlns:media="http://search.yahoo.com/mrss/" medium="image" url="https://rsinfo.vercel.app/images/posts/5-year-blog-anniversary/cover.jpg"/>          
        </item>
      
        <item>
          <guid>https://rsinfo.vercel.app/owning-your-stuff</guid>
          <title>Owning your stuff is pretty cool, actually</title>
          <description>Let's talk a bit about Obsidian, VC-funded apps, the appocalypse and how awesome Markdown life can be.</description>
          <link>https://rsinfo.vercel.app/owning-your-stuff</link>
          <pubDate>Thu, 29 Feb 2024 00:00:00 +0000</pubDate>
          
          <content:encoded><![CDATA[
            <div style="margin: 50px 0; font-style: italic;">
              If anything looks wrong, 
              <strong>
                <a href="https://rsinfo.vercel.app/owning-your-stuff">
                  read on the site!
                </a>
              </strong>
            </div>

            <blockquote>
<p>If you want to create digital artifacts that last, they must be files you can control, in formats that are easy to retrieve and read. Use tools that give you this freedom.
 
– Steph Ango, in <a href="https://stephango.com/file-over-app">Files over apps</a></p>
</blockquote>
<p>This week I re-read Steph Ango’s post about why we should prefer files over apps. The context over which it was reposted was because Notion bought Skiff, an email client, which was quickly followed by an announcement that the service is being sunset in 6 months (and its source code got moved to another repo with no warning; which made many people think it got pulled completely).</p>
<p>There’s a ton of things to like about this idea of using open format files for everything. It’s pretty much the most guaranteed way to make sure your data belongs to you, because it’s as close as you can get to physically owning something digital.</p>
<p>Nowadays, most of what we use has databases hosted somewhere we don’t own, and that data can only be read by that service. Some integrate with others, some allow you to export your data to other services (or even to files), but the truth is that you don’t have the same level of control. If that service runs out of money and goes down suddenly, or some stakeholder decides letting people export their data is bad for business, you’re at their mercy. Especially if it’s a VC-funded company, which are encouraged to either go big or go broke.</p>
<p>Sure, there’s a reason those apps exist and we use them: dealing with files can be hard. It becomes our responsibility to manage them, keep them safe, and if you want to access them on multiple devices (your laptop and your phone, for example), then it gets a lot more complicated. So, is there a happy medium somewhere? I think so.</p>
<h2 id="file-based-apps">File-based apps</h2>
<p>Steph Ango is one of the people behind <a href="https://obsidian.md/">Obsidian</a>, a note-taking app that writes everything into Markdown (.md) files. It is a pretty powerful app, capable of linking and organizing notes in pretty complex ways. But still, all the data in there is stored in files that can be read by any program in any system. Even though Obsidian has come unique features (and even plugins that add even more features), you can use it with the peace of mind that, if anything ever happens to Obsidian, you’ll still have 100% of your data with you.</p>
<p>Obsidian is far from the only app that works like this, which is great. It means that if you find another app that better suits your needs, you can easily take your data in there too. Off the top of my head, you could easily migrate to Logseq, Notable, or even VS Code without having to do anything.</p>
<p>And what conveniences do you lose with this kind of approach?</p>
<p>Well, syncing files between devices is not as straightforward (or at least not free). In Obsidian’s case, you can pay for Obsidian Sync, which is actually what funds development. If you don’t want to pay, it can still be done in a lot of ways. Some people use iCloud or Dropbox folders, others use Git, or other solutions. But yeah, definitely not as easy, especially nowadays where we expect these things to be free. Which leads us to another topic…</p>
<h2 id="sustainable-apps">Sustainable apps</h2>
<p>Software costs money to build. A lot. Even if it doesn’t cost money to keep it up (i.e. there are no servers or support), there’s still all of the dev work that went into it.</p>
<p>What we’ve been seeing happen a lot in the past decade (or even further back) is that startups receive huge investments, with the goal of growing as much as possible, as quickly as possible, to grab a good market share. So these startups operate at huge losses in order to gather a large user base. Then, eventually, the investors want their money back, and now startups need to figure out ways of generating revenue from all these users.</p>
<p>What happens then is… a lot of the things that brought users into those apps start being taken away. The things that caused financial losses to the startup aren’t really feasible anymore, and they need to either start charging for stuff that was free or hike up prices that were low. Or even worse, start making money off user data. The term “<a href="https://en.wikipedia.org/wiki/Enshittification">enshittification</a>” was coined the word of the year in 2023 for a reason.</p>
<p>This is because, as I’ve written before, VC-funded companies are encouraged to either go big or go broke. There’s no middle ground. They can’t grow steadily at a sustainable rate because they got a big chunk of money that they’ve gotta pay back in a few years, and they gotta hurry. So, there’s even more reason to <strong>really</strong> consider not having all your important data on a server they own, with no easy way of backing it up somewhere else.</p>
<p>Which is why I have a big appreciation for companies that aim to build software (or anything, really) in a sustainable way. They start with products that are good and appealing, yes, but also with well defined monetization strategies. Companies like <a href="https://plausible.io/blog/open-source-saas">Plausible</a>, the brazilian news blog <a href="https://manualdousuario.net/">Manual do Usuário</a> and the previously mentioned Obsidian come to mind. I’m sure there are more.</p>
<h2 id="my-next-steps">My next steps</h2>
<p>I have a confession to make: I talked a lot about Obsidian here, but I don’t actually use it. I use Notion, a VC-funded note taking app that keeps all my notes on a database on their server somewhere. I also use some other VC-funded apps. So this post was written for myself, too. Often as I read some tech news I get a bit worried that I might lose some things. Eventually something will happen with Notion that will force me to change my workflow or make me migrate somewhere else (this migration, again, isn’t easy, because my notes are not just files).</p>
<p>So, I’m planning on changing some things. All my blog posts here are already just Markdown files, and I’m testing editing them in Obsidian for kicks (and maybe to eventually be able to post from a phone or tablet). This will be my first step into getting used to it and bringing over my important personal notes to Markdown files too.</p>
<p>Beyond the peace of mind of actually owning my stuff, it’ll be nice to be able to admire everyone who builds the software I use, instead of being slightly concerned that they’ll turn on me someday.</p>

          ]]></content:encoded>
          
                    
        </item>
      
        <item>
          <guid>https://rsinfo.vercel.app/stripping-web-humanity</guid>
          <title>Stripping the web of its humanity</title>
          <description>A less human web is no good for anyone.</description>
          <link>https://rsinfo.vercel.app/stripping-web-humanity</link>
          <pubDate>Tue, 30 Jan 2024 23:43:46 +0000</pubDate>
          
          <content:encoded><![CDATA[
            <div style="margin: 50px 0; font-style: italic;">
              If anything looks wrong, 
              <strong>
                <a href="https://rsinfo.vercel.app/stripping-web-humanity">
                  read on the site!
                </a>
              </strong>
            </div>

            <p>Talking about the newly released <a href="https://apps.apple.com/us/app/arc-search/id6472513080?pt=120729021&ct=arcnet-homepage">Arc Search</a>, Ben Werdmuller says:</p>
<blockquote>
<p>A world where everyone uses an app like this is a death spiral to an information desert.<br><br>We built the world’s most incredible communication and knowledge-sharing medium, rich with diverse perspectives and alternative ideas; let’s not sanitize it through a banal filter that is designed to strip it of its humanity.<br><br>– Ben Werdmuller, in <a href="https://werd.io/2024/stripping-the-web-of-its-humanity">Stripping the web of its humanity</a></p>
</blockquote>
<p>I agree with Ben&#39;s sentiment here. As flashy and interesting on surface as these AI tools are, they usually bring their own bunch of problems. And they&#39;re also symptoms of even bigger problems: the apparent need to summarize web content is a result of how much filler content there is, usually just as a manner of improving SEO and being able to show more ads to more people. It&#39;s content written by robots for robots (search engine bots), now being read by robots and summarized in a few bullet points. Where&#39;s the <em>human</em> in that?</p>
<p>I am a user of GitHub Copilot and love the tool, so I&#39;m not totally against this latest wave of AI tools. But as of now, there are only a few use cases where I see a net positive for us in the end.</p>
<p>Today, I limited a bunch of AI bots&#39; access to my website&#39;s content. Probably won&#39;t do any difference, as there&#39;s a lot of similar content to scrap out there. And the thing that makes my content <em>mine</em>, the human part of this, wasn&#39;t going to be used by them anyway. I guess it&#39;s just a way of me yelling at the clouds that the internet I want to see is not the one they&#39;re trying to build.</p>

          ]]></content:encoded>
          
                    
        </item>
      
        <item>
          <guid>https://rsinfo.vercel.app/progressive-enhancement</guid>
          <title>Progressive Enhancement (and why it matters)</title>
          <description>Progressive Enhancement isn't just another web jargon; it's a guiding principle shaping modern web development.</description>
          <link>https://rsinfo.vercel.app/progressive-enhancement</link>
          <pubDate>Tue, 23 Jan 2024 01:50:25 +0000</pubDate>
          
          <content:encoded><![CDATA[
            <div style="margin: 50px 0; font-style: italic;">
              If anything looks wrong, 
              <strong>
                <a href="https://rsinfo.vercel.app/progressive-enhancement">
                  read on the site!
                </a>
              </strong>
            </div>

            <p>I’ve mentioned Progressive Enhancement on this blog <a href="https://rsinfo.vercel.app/blog-development-sveltekit">once before</a>, when explaining how my blog was built and how Svelte has that concept as one of its main appeals. Since then, it’s something that has stuck with me on everything I’ve built, and as such has shaped the way I work both on personal projects and professionally as well.</p>
<p>This article talks about Progressive Enhancement focusing mainly on websites and web apps, but it’s a concept that may carry over to other areas of development (client-side, at least), though the specifics might differ.</p>
<h2 id="what-is-progressive-enhancement">What is Progressive Enhancement?</h2>
<p>If you really think about it, Progressive Enhancement is all about accessibility. It’s about making sure people of all kinds and with all kinds of devices and connections are able to access your software in at least some capacity.</p>
<p>Just like you can’t expect all users to have perfect eyesight and motor skills, you can’t expect them to have the latest hardware and software, or to have perfect network connections to load everything as intended. Of course that the experience of someone whose spotty 3G connection wasn’t able to load your JS files to be as good as someone in a fast stable Wi-Fi, but what if both could use your website/app either way?</p>
<p>Sounds hard, right? But it really isn’t.</p>
<h2 id="why-and-when-it-matters">Why and when it matters</h2>
<p>When talking about Progressive Enhancement, there’s three main reasons a user may be facing a non-ideal version of your website:</p>
<ol>
<li>The JavaScript files couldn’t be downloaded;</li>
<li>The CSS couldn’t be downloaded;</li>
<li>The user’s browser/device doesn’t support a feature your code uses;</li>
</ol>
<p>For number 3, this can be dealt with with some clever feature-checking (more on this below) and using websites like [<a href="http://caniuse.com">caniuse.com</a>](<a href="https://caniuse.com">https://caniuse.com</a>) before using newer features.</p>
<p>As for 1 and 2, there are numerous reasons it can happen. I like to refer to <a href="https://www.kryogenix.org/code/browser/everyonehasjs.html">this website</a> whenever I want to reference why someone might not have JavaScript loaded (and the same reasons apply for CSS), but to summarize:</p>
<ul>
<li>A faulty connection may make the JS/CSS file requests fail, even though the page itself loaded;</li>
<li>A lot of corporate firewalls and ISPs block domains, which might affect requests, especially 3rd-party files your code might depend on;</li>
<li>The user might have disabled JavaScript (a lot of people do);</li>
<li>Browser extensions (especially adblockers) might block your scripts from running;</li>
</ul>
<p>It’s hard to know exactly how many people this affects, and the number will greatly vary depending on who your audience is. <a href="https://gds.blog.gov.uk/2013/10/21/how-many-people-are-missing-out-on-javascript-enhancement/">A 2013 study by the UK Government</a> showed that 1 in 93 people won’t get your JavaScript code running correctly. 11 years later, while in general connections have gotten faster and more stable, users have also become more likely to use ad-blockers or similar tools. So I’d wager the rate hasn’t changed much.</p>
<h2 id="how-to-progressively-enhance-your-website">How to Progressively Enhance Your Website</h2>
<p>I’m gonna be honest: Progressive Enhancement is easy, as long as you’re building something new. There’s no quick way of going back to old JS-dependent features and make them work without it, as it will require a refactor. Beyond that, while Progressive Enhancement is a always good thing to keep in mind when developing, a fully working website with JS disabled might not be achievable if you have an app that uses JS to build its entire UI - a SPA (Single Page Application).</p>
<p>With that out of the way, these are my main tips for building websites that get progressively better the more resources the user has:</p>
<h3 id="start-with-the-basics">Start with the basics</h3>
<p>Instead of building a fully-featured UI and then stripping it down, we&#39;re doing the opposite: start with the bare minimum. It helps to disable JS for your website (can be done in the browser’s DevTools), so you’re 100% sure everything will work without it. It doesn’t need to be pretty or smooth, it just needs to function. Once that’s done, you can re-enable JavaScript and start adding the charming bits.</p>
<p>There’s not much you can do to prepare for a case where your CSS didn’t load, but you can mitigate one of the main issues when that happens: <strong>add height/width to your images and SVGs.</strong> That way, they won’t be absurdly big and won’t break the layout as much. And, if you want to style your images with more complex rules, you can add the styles in CSS and they&#39;ll overwrite the height/width attributes. For example:</p>
<pre><code class="language-html">&lt;img src=&quot;example.jpg&quot; width=&quot;500&quot; height=&quot;500&quot; /&gt;
</code></pre>
<pre><code class="language-css">~filename styles.css
/* These will only be applied if 
the CSS file loads successfully */
img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}
</code></pre>
<p>And, if you want your images to be scale responsively when your CSS actually loads, just overwrite the height/width there! Fun fact: adding height/width properties to the <code>img</code> element also helps many frameworks load correctly-sized images to make them more lightweight.</p>
<h3 id="think-inside-the-box-📦">Think <em>inside</em> the box 📦</h3>
<p>There’s a lot of talk about thinking outside the box when developing - and indeed it’s one of the best skills a developer can have! But often the inside of the box is really useful too. Whatever you&#39;re thinking of building, there’s probably an HTML element that behaves similarly. Why not expand on that instead of just adding more events to a div?</p>
<ul>
<li>For hyperlinks, use <code>&lt;a&gt;</code> (please);</li>
<li>For accordions, use <a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/details">the <details> element</a>;</li>
<li>Need to send data to a server? Just use a <code>&lt;form&gt;</code>! No need for onClicks or onSubmits;</li>
<li>Any element that has a toggleable state - for example, a hamburger menu or even a modal dialog - can be controlled by a checkbox instead. Yes, really! Check out the mobile hamburger menu of this website;</li>
<li>In fact, add <a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element">MDN’s list of HTML elements</a> to your bookmarks. Use divs only as a last resort. Chances are, using a proper HTML element is going to make your code simpler, more readable and more accessible.</li>
</ul>
<h3 id="use-feature-queries">Use feature queries</h3>
<p>In the past few years, CSS has been getting a ton of new features, making web development easier in general. Things like <a href="https://rsinfo.vercel.app/container-queries">container queries</a>, <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/:has">parent selectors</a> (:has), and many more.</p>
<p>However, even when all browsers adopt the new features quickly, users still might keep using older versions of a browser for a while. But it the feature you want to use has been available for a bit, you can use feature queries to check if a feature is available or not. I’ve briefly mentioned this in my <a href="https://rsinfo.vercel.app/css-hover-media-query">conditional hover styles post</a>, but to sum it up, you can use the <code>@supports</code> keyword to check if a property is available or not. Take this example of a feature check for container queries:</p>
<pre><code class="language-css">@supports (container-type: inline-size) {
    /* container queries styles */
}

@supports not (container-type: inline-size) {
    /* fallback styles */
}
</code></pre>
<p>And what if the feature isn’t supported, do I need to write my CSS rules twice? No, not really. I mean, it’s your choice how much effort you want to have in supporting the older browsers in this case, but I’d recommend you to at least do something that’s good enough. In the example above (common for creating responsive elements), the older browser could be served some media queries that might not be as pixel-perfect or smooth, but still good enough to not serve a broken experience.</p>
<h2 id="wrapping-up">Wrapping Up</h2>
<p>I hope this article has been at least a bit enlightening as to how important and easy it can be to start adopting Progressive Enhancement. I feel like as web frameworks got more advanced and decoupled from the basic web development experience, we also started to forget using what the platform gives us, and began reinventing wheels, often in less accessible and less performant ways.</p>
<p>That was a response to a stagnant web platform, more than a decade ago. But that time is past, and the web platform has been progressing greatly in the past few years. By consequence, there has been a change in web frameworks that seem to be adopting more of the native web and depending less on client-side JavaScript. That can be seen in newer frameworks like Svelte and Solid when compared to older ones like React and Angular. But most of all it can be seen in meta-frameworks like Astro or NextJS, that are trying to make the JS-dependent frameworks all produce markup in the server and serving the user a complete page even with JavaScript disabled.</p>
<p>Web development is changing again (has it ever stopped?), and this time it’s hard to see a downside.</p>

          ]]></content:encoded>
          
                    
        </item>
      
        <item>
          <guid>https://rsinfo.vercel.app/2023-year-in-review</guid>
          <title>2023 In Retrospective</title>
          <description>A quiet year, but still with lots to talk about.</description>
          <link>https://rsinfo.vercel.app/2023-year-in-review</link>
          <pubDate>Thu, 21 Dec 2023 16:09:02 +0000</pubDate>
          
          <content:encoded><![CDATA[
            <div style="margin: 50px 0; font-style: italic;">
              If anything looks wrong, 
              <strong>
                <a href="https://rsinfo.vercel.app/2023-year-in-review">
                  read on the site!
                </a>
              </strong>
            </div>

            <h2 id="last-years-predictions">Last Year’s Predictions</h2>
<p><a href="https://rsinfo.vercel.app/2022-year-in-review">Last year</a>, I hoped 2023 would be a <em>less exciting</em> year, compared to how 2022 was. And I got that right. Nothing major happened to me in 2023 and I feel like I needed that. It was a year to put my head in its right place and prepare for the next couple of years.</p>
<p>I also mentioned I was planning on refactoring my website, and releasing at least one of the side projects I had planned. I did refactor a huge chunk of my website, but… at this point, I don’t even remember what side project I had in mind when I said that 😅.</p>
<p>I also said I wanted 2023 to be <em>cozy</em>. Eeeh… kinda?</p>
<h2 id="personal-life">Personal Life</h2>
<p>As for my personal life, nothing really big happened this year. Last year I got married and lived in Italy for 3 months, but this year I just moved from one apartment to another in the same city and that’s it. There were a bunch of smaller, but still amazing moments, though!</p>
<h3 id="travel">Travel</h3>
<p>My wife and I took some time to discover more of the region we live in (Serra Gaúcha - Brazil). We found out a cool buddhist temple, a random place on a country road filled with mannequins of horror movie characters (!), some really nice parks and places to eat at nearby cities, and, for our 1-year anniversary, we went to a nice retreat in the mountains, and even watched the sunrise atop a hot air balloon!</p>
<p><img src="https://rsinfo.vercel.app/images/posts/2023-year-in-review/serra.jpeg" alt="Picture of a mountain range. The mountains are covered with trees, the sky is cloudy but with enough gaps for the sun to come through. In the foreground, a pool and two chairs overlook the cliffs." title="This mountain range is in the divide between the states of Rio Grande do Sul and Santa Catarina, in the south of Brazil. Photo by me."></p>
<p>We also took a trip to São Paulo in August. São Paulo is the biggest city in Brazil (and the biggest in the American continent), and I’d never been anywhere even comparably as big. I consider the city I live in big (with 500k people), but São Paulo’s 22 million people is just something else.</p>
<p>Being such a big city, it’s also a boiling pot of different cultures from all around the country (and neighboring countries as well). Which makes it really fun! We spent a few days there and came across so many different cultures, often on the same street, side by side, resulting in a sight you can’t really see anywhere else.</p>
<p>On Sundays, one of the city’s main avenues (Avenida Paulista) is closed for cars, which turns it into a public space where everything happens, all at once. Just as we got there, we saw a zumba class happening, while a guy dressed up as Batman was singing karaoke in the middle of the street. Wolverine was calmly watching that happen, while African-based religious groups were grouping up across the street to sing and praise their deities. Walking up the street for a couple minutes, you’d find a samba school rehearsing for the carnival and a bit further a DJ in their booth playing some hardcore dubstep. Everything everywhere all at once. It was great.</p>
<p>São Paulo also has an immense amount of museums, including modern art, african art, a museum of Japanese Immigration, and even one of the story of football (soccer) in Brazil. There’s no shortage of culture to be absorbed there, and most of it was either free or really cheap.</p>
<p><img src="https://rsinfo.vercel.app/images/posts/2023-year-in-review/masp.jpeg" alt="Picture taken from below the MASP museum, in São Paulo. The sidewalk and the street are filled with all kinds of people, and on the other side of the street, there are street food stands and a park." title="Photo taken below the MASP, in São Paulo."></p>
<h2 id="blog">Blog</h2>
<p>I’m pretty sure this was the best year for the blog, at least considering the amount of posts published. Not counting this one, I’ve published <strong>12</strong> posts, up from the 3 from last year.</p>
<p>I feel like what made me motivated to post more is the fact that I’m now following personal blogs much more than I was in the past - with the death of Twitter, I’ve <a href="https://rsinfo.vercel.app/from-twitter-to-mastodon">moved to Mastodon</a> and this pivot towards <a href="https://rsinfo.vercel.app/open-web-and-the-masses">a more open web</a> has made me start using RSS seriously. Seeing so many people write on their own blogs and experiment with their own websites made me want to work on mine more. It’s a win-win!</p>
<p>I think my favorite post was “<a href="https://rsinfo.vercel.app/belonging-somewhere">Belonging Somewhere</a>”, which was the first post that’s purely personal, no tech involved. My other highlights were the <a href="https://rsinfo.vercel.app/review-zelda-tears-of-the-kingdom">new Zelda game review</a> and <a href="https://rsinfo.vercel.app/iron-maiden-killers-concept-album">me trying to explain why I think “Killers” by Iron Maiden is a concept album</a>. I enjoyed diversifying the subjects I post about, even if those posts don’t do big numbers (which is honestly fine, that’s not why I write).</p>
<p>Speaking of numbers, I joined the blogging trend of <a href="https://rsinfo.vercel.app/default-apps-2023">posting about my default apps</a>, and after Matt Birchler reposted it on his Mastodon account, I got a huge traffic spike (compared to the regular traffic I get), from 35-50 to 270 visitors on a single day!</p>
<p><img src="https://rsinfo.vercel.app/images/posts/2023-year-in-review/traffic-spike.png" alt="Screenshot of a line graph showing a huge spike in traffic on a specific day on my website, going from between 35 and 50 visitors to 275."></p>
<p><em>As a reminder, all my website’s analytics are privacy-respecting and public, <a href="https://plausible.io/fantinel.dev">you can see them here</a>.</em></p>
<p>Something else I’ve tried is shorter articles that are usually reading recommendations of other great articles I’ve read. I’m grouping them under the “Reading Recs” tag and plan to add some filtering in the future.</p>
<hr>
<p>On the development side, I’ve done a bunch of changes to the website, though none are too visually impactful:</p>
<ul>
<li>Added a new Table of Contents component to the longer articles I have. It is auto-generated, responsive, and I think it’s working great! There’s one right here on this post 😁.</li>
<li>Significantly refactored how blog posts are stored and loaded. I went full steam on Markdown, with all blog posts having their content and metadata stored in Markdown files, and managed inside VS Code with <a href="https://frontmatter.codes/">FrontMatter</a>;<ul>
<li>This included extending Markdown to be able to use some custom elements inside it! Which means that even if I choose to manage posts differently in the future (like using a CMS), I won’t need to change anything in the posts themselves;</li>
</ul>
</li>
<li>I started using my own <a href="https://www.npmjs.com/package/image-transmutation">image-transmutation</a> package to optimize the images of the website, making sure their quality is good and their size is the smallest possible;</li>
<li>Swapped the font I use to <a href="https://fixel.macpaw.com/">MacPaw’s Fixel font</a>, a delightful variable font that’s as easy to use as it is to read;</li>
<li>Added view transitions so that navigating between pages now animates smoothly (Chromium-only, for now);</li>
<li>Added pagination to posts and a hamburger menu for mobile;</li>
</ul>
<h2 id="work-life">Work Life</h2>
<p>This year, I’ve started working full-time for <a href="https://www.usefulgroup.com/">Useful Group</a>, a lovely agency from Illinois, USA, as a web developer building mainly WordPress websites. This was a very interesting development, as previously I was mainly a “web app guy” instead of working on websites, and me having zero experience handling WordPress or PHP. It still felt as a natural step, as I had started to focus more on “<a href="https://css-tricks.com/the-great-divide/">the front of the frontend</a>” in recent years, and working with websites allows me to focus on that.</p>
<p>I learned quickly though, and really enjoy the way they work there, and was able to fit in nicely. I particularly enjoyed seeing how you can adapt older, battle-hardened technologies to newer, more modern concepts (like atomic design), and how well everything fits in. It also made me realize how much of what’s “new” in web frameworks nowadays is mainly us going back from SPAs to older concepts.</p>
<p>That might sound bad, but I think it’s actually good when tech comes full circle and goes back to concepts that have worked well in the past, because it means that it has matured. Static/multi-page websites had their issues years ago, which is why SPAs became a popular thing. Of course, SPAs brought their own set of issues and now we’re transitioning back to multi-page websites, but with more mature tooling and with a lot of the original issues solved.</p>
<p>Speaking of static websites, I was contacted by a company that was interested in using my personal website as a template for their own. My website is open source and can be modified by anyone, but they would like me to do the needed modifications, since I was already used to the codebase.</p>
<p>I ended up making <a href="https://sveltekit-static-blog-template.vercel.app/">a generic blog template</a> instead, based on what my website looked like in that specific point in time. I strongly recommend using that code instead of this in case you’re interested in forking it!</p>
<p>I internally debated for a while if I wanted to keep my website as a fork of that template, or keep them separate. I opted for the latter after realizing that I didn&#39;t want my personal website to be tied up to a template meant to help others. I like being able to experiment here, and didn’t want the onus of having to maintain compatibility and/or having to backport anything there.</p>
<h2 id="fun">Fun</h2>
<p>Now the best part: the things I enjoyed watching, playing or listening the most in 2023!</p>
<h3 id="tv-and-movies">TV and Movies</h3>
<ul>
<li><strong>Succession</strong> is a show that I’ve been recommended for a while, but its synopsis had never struck a chord with me. However, I was bored one day and decided to start watching it. And it’s <em>amazing</em>! The show doesn’t take itself seriously, so it’s as much of a comedy as it is a family drama. It follows the lives of a wealthy family that owns a big media conglomerate, and the patriarch’s health is deteriorating and his children start fighting to be his successors. They’re so out of touch with reality, though, that even mundane situations reach absurd conclusions. <em>Available on HBO/Max</em>.</li>
<li><strong>Bojack Horseman</strong> speaks to me on a really deep level, even more on my 2nd rewatch of the show. It starts deceptively simple, and you think it’s going to be a really funny, albeit kinda generic cartoon. And then it hits you. And hits again. It’s an incredibly emotional show that gives you tears of joy and sadness in equal amounts. It’s a must-watch for anyone that has ever gone through any mental health issues and/or would like to understand them better. Plus, it has one of the best autistic representations on TV! <em>Available on Netflix</em>.</li>
<li><strong>Severance</strong> was a surprise hit for me. It’s a show about a company where its employees have their mind <em><strong>severed</strong></em> in half, with one “personality” that only exists in the workplace, while the regular personality doesn’t remember anything from work and only ever experiences the “good parts” of life. As you can imagine, it goes really wrong really fast. It masterfully keeps you hooked with an ever-increasing amount of mystery, but then the bad part comes: season 1 ends in a cliffhanger, and there’s still no word on when season 2 is coming. So I recommend waiting a bit before watching it. <em>Available on Apple TV+.</em></li>
<li><strong>Ted Lasso</strong> was one of my favorite shows when I watched seasons 1 and 2 last year, and this year I rewatched it all in preparation for the final season 3. It is the most heartwarming show I’ve ever seen, and even the sadder parts hit you just hard enough to make the heartwarming moments even better. Season 3 was not as high quality as the first two, but it still provided me a lot of joy and the ending was really satisfying. <em>Available on Apple TV+.</em></li>
<li><strong>The Last of Us</strong> was an absolutely incredible experience - a gut punch every episode, but in a good way. I had played the game before, and while I knew the major plot points before they happened, I was absolutely floored when they happened on the show. Incredible writing, acting, and with just enough tweaks to make it feel like a real TV show and not just a game adaptation. The game&#39;s story was already really good, and I feel like it was greatly improved for TV. Doesn&#39;t mean the show&#39;s story is better than the game&#39;s, but it definitely is <em>better for TV</em>.</li>
</ul>
<h3 id="games">Games</h3>
<ul>
<li><strong>Disco Elysium</strong> is one of the most unique games I&#39;ve ever played. It has by far the best dialogue of any game I know, and there are so many branching paths that I think it can be replayed multiple times and still provide an unique experience each time. It is basically an investigation RPG, where you play as a cop with an alcohol-induced amnesia, trying to figure out who you are and who’s responsible for a murder. There’s a lot of dialogue and the majority of it is with other voices in your head (fragments of your psyche). It’s nuts. It takes place in a unique world with a ton of lore, it’s incredibly political and it hits really heavy at some points.</li>
</ul>
<p><img src="https://rsinfo.vercel.app/images/posts/2023-year-in-review/disco-elysium.jpg" alt="Official artwork for Disco Elysium. A heavily stylized drawing of two men, one of them wearing glasses and a puffy jacket, holding a gun and a flashlight. The other has mutton chops and long hair and is wearing a formal shirt with a tie and holding a green jacket in one hand and a gun in the other. In the background, a very dense city and the twilight sky."></p>
<ul>
<li><strong>The Legend of Zelda: Tears of the Kingdom</strong> is my game of the year - an incredible step up from what was already one of my favorite games of all time. I wrote <a href="https://rsinfo.vercel.app/review-zelda-tears-of-the-kingdom">an in-depth review of it here</a>!</li>
<li><strong>Hogwarts Legacy</strong> was a pretty good game that unfortunately didn&#39;t seem to understand its own appeal. It does an incredible job of bringing Hogwarts to life, making the entire castle explorable and full of secrets. Every part of it carefully designed and decorated, with so much attention to detail to praise even the most hardcore book fans. And then… it keeps sending you outside the castle to do generic action adventure game things. And compared to all the other games that do that, it’s just okay.</li>
<li><strong>Bloodborne</strong> again. I’ve written about it last year, and I’ve played it again (twice!) this year, to get the Platinum trophy and… I just love this game so much. It’s become my favorite game of all time and just writing this I feel like playing it again. Masterpiece.</li>
</ul>
<h3 id="music">Music</h3>
<ul>
<li>Last year I discovered the album Infinite Granite by <strong>Deafheaven</strong>, and it&#39;s also been my most listened to album (by far) in 2023. However, I also started listening to other albums by the band and I love them so much. <strong>Sunbather</strong> and <strong>Ordinary Corrupt Human Love</strong> especially are gems.</li>
<li><strong>Shoegazing</strong> has become my favorite genre. Wanting to listen to more stuff that sounded like Infinite Granite, I found out about this genre and started building up a playlist on Apple Music, and it’s become my go-to whenever I need to relax, focus or simply listen to great music. If you have Apple Music, you can listen to it too:</li>
</ul>
<iframe allow="autoplay *; encrypted-media *; fullscreen *; clipboard-write" frameborder="0" height="450" style="width:100%;max-width:100%;overflow:hidden;border-radius:10px;" sandbox="allow-forms allow-popups allow-same-origin allow-scripts allow-storage-access-by-user-activation allow-top-navigation-by-user-activation" src="https://embed.music.apple.com/br/playlist/shoegazing/pl.u-V9D7mqacBrRjxkR"></iframe>

<h3 id="concerts">Concerts</h3>
<p>This year, my wife and I went to 3 amazing concerts! They were all in Porto Alegre, the capital of our state, which is a 2-hour drive from here. They were:</p>
<ul>
<li><a href="https://www.youtube.com/watch?v=Ag-WBs8kVWc">Bruce Dickinson + Band + Orchestra</a> playing a concert piece composed by Jon Lord from Deep Purple, back in April. They also played some Deep Purple classics and a couple of Bruce Dickinson’s solo songs. Admittedly, I didn’t know the concert piece nor some of the Deep Purple songs, so I went mostly to see Bruce, my favorite singer. It was in a smaller theatre and it was a fantastic experience. I’ll see him again next year, this time on a full solo concert!</li>
<li><a href="https://www.youtube.com/watch?v=dsa9ZnD2tWM">Roger Water’s “This Is Not A Drill” tour</a>, back in November. Absolutely incredible show, a mix of Pink Floyd classics and his own solo work (which I like), and most of all a very clear political statement. I also saw him back in 2018, which was also incredible, and I have no idea which one I’ve liked best. The production value of his shows are simply unmatched and I cried like a baby multiple times.</li>
<li><a href="https://www.youtube.com/watch?v=KWWkppRb7yU">Blind Guardian’s “The God Machine” tour</a>, also in November. A smaller venue, but the audience in Blind Guardian’s concerts makes you feel like there are thousands of people with you there. The band is just fantastic and I felt they played extra hard to match the energy of the audience!</li>
</ul>
<h2 id="2024-expectations">2024 Expectations</h2>
<p>Time for the predictions - hopefully I’ll get more right this time!</p>
<p>I expect to take big steps towards owning my own house. I really want to stop paying rent and hopefully get a house instead of an apartment. It’s more work, but it’s more fulfilling and freeing.</p>
<p>I expect to write even more on this blog, and continue to expand on the topics I post about. Dev articles aren’t going anywhere, but I don’t always have something to post about in that regard.</p>
<p>Also, I want to add proper support for categories and filtering, as well as search. As I post more, even I am starting to struggle finding something I wrote in the past to reference. Additionally, some code refactoring is always welcome.</p>
<p>I also want to travel a bit next year too - either to the US to meet my work colleagues or to Italy to see my brother. And of course, do some sightseeing!</p>
<h2 id="wrapping-up">Wrapping Up</h2>
<p>Starting this post, I didn’t think there was much to write about 2023, but I ended up talking about it quite a bit. That’s great! I guess it’s the main point of these kinds of retrospectives - remembering what was noteworthy about the year and reflecting on it. I hope you enjoyed the read and see you next year!</p>

          ]]></content:encoded>
          <media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://rsinfo.vercel.app/images/posts/2023-year-in-review/cover.png"/>
          <media:content xmlns:media="http://search.yahoo.com/mrss/" medium="image" url="https://rsinfo.vercel.app/images/posts/2023-year-in-review/cover.png"/>          
        </item>
      
        <item>
          <guid>https://rsinfo.vercel.app/css-isolation-property</guid>
          <title>CSS's "isolation" property is pretty cool</title>
          <description>I had never heard about it before, but it's a pretty clean way of solving z-index related issues.</description>
          <link>https://rsinfo.vercel.app/css-isolation-property</link>
          <pubDate>Fri, 24 Nov 2023 13:15:59 +0000</pubDate>
          
          <content:encoded><![CDATA[
            <div style="margin: 50px 0; font-style: italic;">
              If anything looks wrong, 
              <strong>
                <a href="https://rsinfo.vercel.app/css-isolation-property">
                  read on the site!
                </a>
              </strong>
            </div>

            <blockquote>
<p><code>isolation</code> is a special property whose sole and unique purpose is to create a new stacking context on the element it is applied to, with no other side-effects. 😄<br><br>– Francesco Vetere, in <a href="https://dev.to/francescovetere/the-css-property-you-didnt-know-you-needed-3fk0">The CSS property you didn&#39;t know you needed</a></p>
</blockquote>
<p>You learn something new everyday! Today, I learned about CSS&#39;s <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/isolation">isolation</a> property. I learned it through <a href="https://dev.to/francescovetere/the-css-property-you-didnt-know-you-needed-3fk0">this Francesco Vetere post</a>, which I highly recommend you to read, as he explains it way better than I do.</p>
<p>Basically, <code>isolation: isolate</code> is a very simple way of creating a stacking context in CSS. Stacking context is basically a &quot;reset&quot; of how <code>z-index</code> works, so you can manage indexes in a smaller scope.</p>
<p>Francesco gives a perfect example of a card element with a decorative element in its background. To make that element appear below the text, you&#39;d naturally add <code>z-index: -1;</code>, but that means the element would show below the card as well! By creating a new stacking context on the card, you can safely manage <code>z-index</code> without worrying about any child element appearing below/outside its parent.</p>

          ]]></content:encoded>
          
                    
        </item>
      
        <item>
          <guid>https://rsinfo.vercel.app/default-apps-2023</guid>
          <title>My Default Apps: 2023</title>
          <description>I'm jumping on the trend of posting my default apps!</description>
          <link>https://rsinfo.vercel.app/default-apps-2023</link>
          <pubDate>Tue, 07 Nov 2023 12:11:50 +0000</pubDate>
          
          <content:encoded><![CDATA[
            <div style="margin: 50px 0; font-style: italic;">
              If anything looks wrong, 
              <strong>
                <a href="https://rsinfo.vercel.app/default-apps-2023">
                  read on the site!
                </a>
              </strong>
            </div>

            <p>I saw this on <a href="https://birchtree.me/blog/my-default-apps-at-the-end-of-2023/">Matt Birchler&#39;s blog</a>, and then saw the multitude of people posting about their default apps in their own blogs. I&#39;ve never jumped on a trend like this before, so I figured this would be a fun first one to do 😅.</p>
<p>I guess you can say my choices are pretty vanilla; I&#39;ve been through my phase of trying a specific app for everything, but nowadays I&#39;m settling down on things that actually work.</p>
<ul>
<li>📧 Mail service: <a href="https://fastmail.com">Fastmail</a></li>
<li>📬 Mail client: Apple Mail (Mac and iPhone)</li>
<li>✅ Tasks: <a href="https://notion.so">Notion</a>/<a href="https://ticktick.com/">TickTick</a></li>
<li>📰 RSS service: <a href="https://readwise.io/read">Readwise Reader</a></li>
<li>⌨️ Launcher: <a href="https://www.raycast.com/">Raycast</a></li>
<li>☁️ Cloud storage: iCloud</li>
<li>🌅 Photo library: iCloud</li>
<li>🌐 Web browser: <a href="https://arc.net/">Arc</a> on Mac, Safari on iPhone</li>
<li>📆 Calendar: Apple Calendar</li>
<li>📖 Reading: <a href="https://readwise.io/read">Readwise Reader</a></li>
<li>🌤️ Weather: Apple Weather</li>
<li>🎙️ Podcasts: I barely listen to any, but when I do, Apple Podcasts</li>
<li>🎶 Music: Apple Music</li>
<li>🛹 Clipboard manager: <a href="https://maccy.app/">Maccy</a></li>
<li>🔐 Passwords: <a href="https://1password.com/">1Password</a></li>
<li>💸 Budgeting: Apple Numbers</li>
<li>🐘 Mastodon: <a href="https://tapbots.com/ivory/">Ivory</a> (Mac and iPhone)</li>
<li>💁🏻‍♂️ Social: <a href="https://joinmastodon.org/">Mastodon</a> and <a href="https://join-lemmy.org/">Lemmy</a> (sporadically)</li>
<li>🎮 Gaming: PS5</li>
<li>🖼️ Screenshots: <a href="https://cleanshot.com/">CleanShot X</a></li>
<li>📝 Notes: <a href="https://notion.so">Notion</a></li>
<li>🧮 Code Editor: <a href="https://code.visualstudio.com/">Visual Studio Code</a></li>
<li>👨🏻‍💻 Terminal: <a href="https://iterm2.com/">iTerm 2</a></li>
<li>🔎 Search: <a href="https://kagi.com">Kagi</a></li>
</ul>

          ]]></content:encoded>
          <media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://rsinfo.vercel.app/images/posts/default-apps-2023/cover.jpeg"/>
          <media:content xmlns:media="http://search.yahoo.com/mrss/" medium="image" url="https://rsinfo.vercel.app/images/posts/default-apps-2023/cover.jpeg"/>          
        </item>
      
        <item>
          <guid>https://rsinfo.vercel.app/belonging-somewhere</guid>
          <title>Belonging Somewhere</title>
          <description>I could always see parts of myself belonging to some groups or places, but never really felt like I was truly a part of anything.</description>
          <link>https://rsinfo.vercel.app/belonging-somewhere</link>
          <pubDate>Sat, 04 Nov 2023 17:21:47 +0000</pubDate>
          
          <content:encoded><![CDATA[
            <div style="margin: 50px 0; font-style: italic;">
              If anything looks wrong, 
              <strong>
                <a href="https://rsinfo.vercel.app/belonging-somewhere">
                  read on the site!
                </a>
              </strong>
            </div>

            <p>Throughout my life, I’ve never really felt like I belonged somewhere. I could see parts of myself belonging to some groups or places, but never really felt like I was truly a part of anything.</p>
<p>During my childhood, I had some friends, and there was a group of kids/teens in my street that I would often hang out with, but to me it was always because of the activities we’d do, and not because I enjoyed being around them, or thought I was similar to them. We’d play football (<em>soccer</em>) in the street, play with our Beyblades or maybe play some Winning Eleven on our PS1s, but whenever the activity wasn’t one of these things, I just didn’t want to be there. I felt like an outsider that was just part of that group temporarily.</p>
<p>Now, this probably (certainly) is related to me being on the Autism spectrum (something I didn’t know back then), which does <em>literally</em> mean I wasn’t like them. The thing is, that feeling has kind of followed me through my whole life.</p>
<h2 id="local-culture">Local Culture</h2>
<p>I live in the southernmost state of Brazil, a state that is known to have a local culture that’s very different from the rest of the country. Nowadays, I know that there’s no such thing as an homogeneous Brazilian culture. Brazil is pretty much an amalgamation of thousands of different cultures, indigenous, african, european, asian, and the results of all of those meeting together. That’s what makes it great. But back then, to me, Brazilian culture was whatever was shown on national TV (I didn’t have access to local channels). And honestly, nothing shown there looked like anything we had here. So, it was hard to see myself as part of this country.</p>
<p>Around 10 years ago, I started a long-distance relationship with a girl that lived about 700km (430 miles) from me. Against all odds we made it work and we’re now happily married! Anyway, I remember when her parents came to visit my city for the first time. Her dad loved the “gaúcho” culture, and was looking forward to coming to my state and seeing firsthand what it was like, and to eat an authentic gaúcho barbecue. Little did he know… that’s not what it’s like here either.</p>
<blockquote>
<p>[!info]
&quot;Gaúcho&quot; is how the people born in the state of Rio Grande do Sul (like me) are called. The name is also used a lot in Uruguay and Argentina, since those countries share a border with my state and also share a lot of the same culture.</p>
</blockquote>
<p>You see, I do live in the state known for all that stuff, but the region I live in was populated waaaay later in history, by…. italian immigrants.</p>
<hr>
<h3 id="historical-context">Historical Context</h3>
<p>Back in the 1800s, the Empire of Brazil wanted to populate some areas of the south, partly to protect the land from neighboring countries, partly to push away the indigenous people. But what they also wanted was to “whiten the population”, so they started the process of bringing europeans from countries currently going through economic crisis, and bringing people that wanted to start over here. In this region, the majority came from Germany (in the 1820s), and Italy (in the 1870s).</p>
<p>This region was unpopulated before because it was hard to do so - it is very mountainous and with really dense forestation, so nobody wanted the trouble of building things here - not when they had better (easier) options still. When the immigrants came, they didn’t have much of a choice. They didn’t speak Portuguese, and all the best pieces of land were already taken. The Serra was the only place they could build on and own a piece of land. From what I’ve heard from my grandparents (and they heard from theirs), the government didn’t do much to help, so they pretty much grew here in a partially isolated manner - with their own culture brought from their origin countries and the life they built here.</p>
<hr>
<p>So, when my in-laws came here for the first time, they were surprised (and somewhat disappointed) that it was nothing like what they thought it would be. Instead of barbecue everywhere, we eat pasta and polenta. The accent was different. The architecture was different. Of course, since I live in the biggest city of the region we did eventually start getting drops of culture from everywhere, most of it being from the gaúcho culture, since it’s the nearest, but still it’s definitely not as native as they had expected.</p>
<p>I’m not really a fan of going out and seeing all of this culture firsthand (at least I wasn’t; as I&#39;m getting older I’m starting to enjoy it more), but I did have my fair share of family gatherings and events that definitely had italian roots. So, whenever I saw people talk about Brazil or my state, I could never see myself or the people around me in any of it. My logical conclusion is that I didn’t belong to my country or state at all, and maybe, since I was an “internet citizen” since I was a kid and had a lot of (virtual) contact with cultures from around the world that felt more like me, maybe my place in the world would be somewhere else!</p>
<p>During my late teen years and early 20s, this idea of leaving the country was always present, and I’ve tried dipping my toes a couple times. I tried going to Canada to study English for a month to see how I’d like there, but unfortunately my visa was denied twice, and I gave up. Then I went to Europe for tourism, which was really fun! I thought that since my family came from there, then naturally that’d be the place I’d belong to.</p>
<p>Last year, I moved to Italy for 3 months, in order to get my italian citizenship recognized. The original idea was to stay there after those 3 months, find a place to live, and leave Brazil behind. But, as the date approached, my wife and I realized we weren’t really comfortable with the idea of leaving everything behind and jumping into the unknown. So, we decided to use those 3 months as a test to see how much we liked it, and if we missed Brazil at all. We were wise.</p>
<p>Those 3 months were… tough. Of course, I was naturally uncomfortable with all the changes involved in moving across the Atlantic, but we moved into a really, <strong>really</strong> small town (with around 300 people), stayed in a house that had at least 300 years and we were in the middle of nowhere. Now, I’m really trying to not be unfair and judge an entire country by just a small town, and I do believe Italy is a great place to live. But, after all that, I think the biggest feeling my wife and I had was not that we hated where we were - but that we missed our <strong>home</strong> so much.</p>
<p>Suddenly, it all became clear. Even though we lived in an <em>italian-brazilian</em> place, it still was <em>brazilian</em>. That mix of different people might be more subtle than in other parts of the country, but it’s still there. And it’s still <strong>amazing</strong>. The people, the weather, the food, the music, it’s all unique to this small, very special part of the world. Special because it’s mine.</p>
<hr>
<p>As a recently diagnosed autistic person, I’m now learning a lot about myself, and I’ve realized I’ve always struggled with my sense of identity. How can I learn who I am if I never see much of myself anywhere? It’s not an easy journey, and honestly I don’t think it has an end. Our identity changes all the time and is molded by what’s around us. This feeling of belonging is unique to each person, some find it at an early age, some never do. I always thought I’d be the latter.</p>
<p>Today, I was watching local TV and they were covering a festival celebrating local culture. More specifically, the italian-brazilian culture that developed here after all these years. I watched that and thought: <em>“Yeah, I belong here”</em>.</p>

          ]]></content:encoded>
          <media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://rsinfo.vercel.app/images/posts/belonging-somewhere/cover.jpg"/>
          <media:content xmlns:media="http://search.yahoo.com/mrss/" medium="image" url="https://rsinfo.vercel.app/images/posts/belonging-somewhere/cover.jpg"/>          
        </item>
      
        <item>
          <guid>https://rsinfo.vercel.app/mario-kart-tailwind</guid>
          <title>“Classic rock, Mario Kart, and why we can't agree on Tailwind”</title>
          <description>Great article from Josh Collinsworth explaining why Tailwind is good and bad for the exact same reasons.</description>
          <link>https://rsinfo.vercel.app/mario-kart-tailwind</link>
          <pubDate>Sat, 14 Oct 2023 15:07:19 +0000</pubDate>
          
          <content:encoded><![CDATA[
            <div style="margin: 50px 0; font-style: italic;">
              If anything looks wrong, 
              <strong>
                <a href="https://rsinfo.vercel.app/mario-kart-tailwind">
                  read on the site!
                </a>
              </strong>
            </div>

            <blockquote>
<p>Likewise, I suspect most people on opposing sides of the Tailwind debate actually completely agree on Tailwind itself. I don’t think our divide centers on atomic CSS, or utility classes; I think the contention comes from valuations we made long before we ever chose our tools. Where one of us sees a selling point, the other sees a flaw.– Josh Collinsworth, in <a href="https://joshcollinsworth.com/blog/tailwind-is-smart-steering?utm_source=matt-fantinel">Classic rock, Mario Kart, and why we can&#39;t agree on Tailwind</a></p>
</blockquote>
<p>I&#39;ve found this gem of an article a while ago, and have been thinking constantly about it ever since. I think its idea of things being good and bad for the same reasons is spot on - and also the reason why we&#39;ll never agree on them.</p>
<p>I also dislike the idea of Tailwind, which made me never interested in using it. I prefer having total control of my styles and enjoy a clear separation between templates and styles. This, I guess, makes me a &quot;crafter&quot;.</p>

          ]]></content:encoded>
          
                    
        </item>
      
        <item>
          <guid>https://rsinfo.vercel.app/open-web-and-the-masses</guid>
          <title>The Open Web and "the masses"</title>
          <description>A rant about the Open Web and how it is not for everyone - but that's okay.</description>
          <link>https://rsinfo.vercel.app/open-web-and-the-masses</link>
          <pubDate>Tue, 19 Sep 2023 21:28:46 +0000</pubDate>
          
          <content:encoded><![CDATA[
            <div style="margin: 50px 0; font-style: italic;">
              If anything looks wrong, 
              <strong>
                <a href="https://rsinfo.vercel.app/open-web-and-the-masses">
                  read on the site!
                </a>
              </strong>
            </div>

            <p>Back when I started using the internet, most of its content was split between millions of different websites and platforms. They were all accessible via search engines, and there were plenty of websites that existed only to aggregate content from others. There were social networks (Orkut was a huge hit in Brazil), but their scale never reached the levels we see today, and overall, <strong>if you wanted to see anything, you’d have to look for it.</strong></p>
<p>Cut to today, most of the content is either hosted on a handful of platforms or at least found inside them. Large scale social networks and search engines that are increasingly displaying information without requiring you to open another website have made it incredibly easy to find content you’d never find otherwise.</p>
<p>This convenience has led to a boom in internet usage. Before, you had to be a “tech person” or at least slightly interested in tech to be able to understand how the internet worked, and then be able to find the good stuff. This transformation in how we find and see things would be great, if not for a huge, non-obvious problem: we are now locked in to those platforms.</p>
<p>Ideally, that wouldn’t be a big deal. Most of those platforms are free, right? Well, not really. You pay with your data, with being the subject of psychological experiments, and with the price of becoming dependent on it. If you don’t know what I’m talking about, I highly recommend watching <a href="https://www.thesocialdilemma.com/">The Social Dilemma documentary</a> on Netflix (I know, another locked-in platform. But there’s some nice content on the website itself).</p>
<p>To many people, deleting a Facebook/Instagram/Twitter account would mean they will no longer see updates from things they care about (mixed with things they don’t). To many journalists/writers/brands, deleting an account would mean losing the majority of their traffic. Some companies even base their entire business on a single platform, as can be often seen in Brazil where WhatsApp is often the only way to contact/hire/buy something.</p>
<p>So, can we really call the web open, or free? If we are virtually obligated to sign up and* *accept the terms and conditions of at least one overly powerful corporation to be able to have a “normal life”, can we really say we have a choice?</p>
<p>Maybe.</p>
<h2 id="swimming-against-the-tide">Swimming Against The Tide</h2>
<p>There’s been quite a resurgence of some technologies and concepts that go against all that. Mostly, in the form of personal blogs and them being accessed via RSS readers. Plus, decentralized social media is now a thing and has gathered a relatively significant audience, especially since Twitter’s destruction.</p>
<p>If you don’t know what RSS readers and decentralized social media are, yeah, that’s their main issue. They are systems that aim to give you some of the convenience of social media feeds back, but without the downsides!</p>
<ul>
<li><strong>RSS</strong> is a method of sharing content in a standardized way. A lot of websites have RSS feeds (including mine), which are files that hold the content of, for example, all the blog posts. This means that if you use a RSS reader app, you can read whatever I write, and all the new posts will be automatically delivered to you! You just have to subscribe.<ul>
<li>RSS has existed for a long time, and most websites had a feed. When social media got popular, however, the number of websites with a RSS feed started getting smaller. Nowadays, it seems that the number of websites offering them has started growing again.</li>
<li>There are a bunch of RSS reader apps, in all shapes and forms. Some of the ones I know are <a href="https://feedly.com/">Feedly</a> (free, for all platforms), <a href="https://netnewswire.com/">NetNewsWire</a> (free, for iPhone, iPad and Mac), <a href="https://feedbin.com/home">Feedbin</a> (subcription, for Web, iPhone and iPad) and the one I use is <a href="https://readwise.io/read">Readwise Reader</a> (subscription, for Web, iPhone and Android)</li>
</ul>
</li>
<li><strong>Decentralized Social Media</strong> are, as implied, social media services that communicate with one another. I wrote a few months ago about <a href="https://rsinfo.vercel.app/from-twitter-to-mastodon">my migration from Twitter to Mastodon</a>, and Mastodon is only one of many in an universe of projects that can talk with one another. What does this mean?<ul>
<li>It means that, even if I have my profile on a specific Mastodon server, I can still follow and interact with people that created their account on a different social media. So, nobody is virtually obligated to have an account in a specific place;</li>
<li>It also means that I can take all my connections with me in case I wanna move from one service to another. I’m never stuck using a service I don’t like just because my friends or followers are there;</li>
</ul>
</li>
</ul>
<p>My use of the internet is now heavily based on both of these systems; I follow some news websites’ RSS feeds so I can read the news in a single place while drinking a cup of coffee; I follow cool people&#39;s blogs via RSS so I can read all the cool stuff they’re writing about; and I can also follow the same cool people on Mastodon (even though some use something else) to see they complain about the heat or make bad jokes in their social media.</p>
<p>This is very nice! And the best thing is - if I ever wanna start using another app, or change devices, I can do that without losing anything. It’s liberating. It’s the <strong>Open Web</strong>.</p>
<h2 id="but-how-feasible-is-it">But how feasible is it?</h2>
<p>Most of the previous section was spent explaining concepts. They’re not really that complex, but the fact that they need any explanation at all is already a sign that they’re not feasible for “the masses”.</p>
<p>You see, if you are still reading this, you&#39;re probably in a small group of people that actually cares about their online experience. For most people, being locked in a service isn&#39;t really a concern, which is why those services grow so big. It’s unfortunate, but the convenience those services provide is (or was, at some point, when they got us hooked) so big that I can’t think of anything that could create any kind of mass exodus from them. The closest we’ve ever got to it was the Twitter → Mastodon migration, and that was around what, 10 million people? 10 million is a lot for Mastodon, but only a fraction of Twitter’s userbase.</p>
<hr>
<p>But honestly, that’s fine. As I’ve recently started to realize more and more, it really doesn’t matter if what I’m using or doing is popular or not. If I do things a certain way, the only person it needs to work for is me. And honestly, the social bubble I’m in is really fond of the Open Web too! There are nice discussions, and it never feels like a small group. In fact, there’s always new people around!</p>
<p>I think I’m gonna create a page with suggestions of nice RSS feeds to follow. One more thing to my to-do list, I guess 😅</p>

          ]]></content:encoded>
          <media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://rsinfo.vercel.app/images/posts/open-web-and-the-masses/cover.jpeg"/>
          <media:content xmlns:media="http://search.yahoo.com/mrss/" medium="image" url="https://rsinfo.vercel.app/images/posts/open-web-and-the-masses/cover.jpeg"/>          
        </item>
      
        <item>
          <guid>https://rsinfo.vercel.app/review-zelda-tears-of-the-kingdom</guid>
          <title>My Review of The Legend of Zelda: Tears of the Kingdom</title>
          <description>A spoiler-free review of the ultimate Zelda game</description>
          <link>https://rsinfo.vercel.app/review-zelda-tears-of-the-kingdom</link>
          <pubDate>Sat, 16 Sep 2023 14:29:19 +0000</pubDate>
          
          <content:encoded><![CDATA[
            <div style="margin: 50px 0; font-style: italic;">
              If anything looks wrong, 
              <strong>
                <a href="https://rsinfo.vercel.app/review-zelda-tears-of-the-kingdom">
                  read on the site!
                </a>
              </strong>
            </div>

            <blockquote>
<p>[!success]
This review is <strong>spoiler-free</strong>, so you can safely read it even if you haven&#39;t played or finished the game yet.</p>
</blockquote>
<p>The Legend of Zelda is my favorite game series of all time. Understandably, I was pretty excited for Tears of the Kingdom to come out. And it took its time! Announced in 2019, two years after the release of its predecessor (Breath of the Wild), a lot of people thought it would have a shorter development cycle, considering it seemed to feature the same world as Breath of the Wild&#39;s, the graphics were the same, and the engine was already done. How wrong we were!</p>
<p>Instead, Tears of the Kingdom (which I&#39;m gonna call &quot;TOTK&quot; from here on for brevity) had at least a 5-year development cycle, almost as long as BOTW&#39;s. We had a global pandemic in the meantime, which definitely slowed things down. Still, it was a lot of time for &quot;just a sequel&quot;. And, to be honest, while the first trailers were exciting because they pointed to a return to BOTW&#39;s world, they also were a bit lackluster, as they didn&#39;t show much new.</p>
<p>You see, Breath of the Wild&#39;s release was a pivotal moment in the gaming industry. In theory, it didn&#39;t introduce a lot of new things - open world games have existed for a while, even the first Legend of Zelda from 1986 was like that! But in practice, it brought a world that was so fun to explore, so seamless to traverse, and its gameplay had so many possibilities, that there was nothing quite like it. It also reinvented the series, which had been stagnant for some years, with games of high quality but that weren&#39;t really hitting the mark.</p>
<p>That was in 2017, though, and games have evolved since then. With BOTW&#39;s relevance and success, a lot of games started taking it as an inspiration (and almost every open world game was compared to it somehow). So, when TOTK was shown and it didn&#39;t seem to offer a lot new, I was a bit worried it&#39;d be more of the same.</p>
<p>And then <strong>BAM!</strong> that final trailer shows up.</p>
<iframe style="width: 100%;aspect-ratio:16/9;border-radius:10px;box-shadow:var(--image-shadow);" src="https://www.youtube-nocookie.com/embed/uHGShqcAHlQ" frameborder="0" allow="autoplay; encrypted-media" allowfullscreen></iframe>

<p><em>It is incredible!</em> It shows new story bits, but more importantly, a <strong>lot</strong> of new gameplay mechanics, abilities, and some of them are so unique that I don&#39;t think anyone could have imagined they&#39;d be in a Zelda game. And so, after years of waiting for the game to come out and an extra month of waiting for my copy to be delivered, I finally played it.</p>
<h2 id="the-new-abilities">The New Abilities</h2>
<p>The game begins quite differently than it did in BOTW. In this game, the idea of being able to go anywhere anytime is still present, but not taken to extremes (no, you can&#39;t go straight to the final boss right after the tutorial). We have a linear story-focused tutorial, where the main plot begins, and then we are introduced to Link&#39;s new abilities in this game. They are a huge step up from BOTW&#39;s abilities, which were fun but feel very limited now.</p>
<p>There are 4 main abilities:</p>
<ul>
<li>Ultrahand, which lets you manipulate most objects in the game, and then <em>stick</em> them on other objects. It&#39;s an improved version of Magnesis from BOTW, and probably the one you use the most;</li>
<li>Recall, which lets you make an object go back in time (and space). You can make some really great combos with this and Ultrahand, like using Ultrahand to hold a platform up high, then let it fall, and use Recall to have it go back up with you on top of it;</li>
<li>Fuse, which lets you fuse any material to your weapon/shield/arrows, improving its attack power or giving some status effects;</li>
<li>Ascend, which lets you <em>swim</em> through any solid material, as long as its right on top of you. Honestly, I thought this one was going to be the lamest one, but it was the biggest surprise! I used it so much and always felt smart when I did;</li>
</ul>
<p>The abilities are less specialized, but more powerful, which gives you so much freedom to use them! 80h into the game, I was still figuring out new ways to use and combine them.</p>
<h2 id="improvements-over-botw">Improvements over BOTW</h2>
<p>I believe TOTK fixes or remediates all of BOTW&#39;s problems. The story isn&#39;t told only through a series of flashbacks (though flashbacks are still a thing); the world feels much more alive (which makes sense after BOTW); the soundtrack is more varied; and weapon durability is fixed.</p>
<p><em>Weapon durability is fixed? Does that mean they don&#39;t break anymore?</em> No, actually they break much faster now 😅. You see, the main problem with BOTW&#39;s weapon durability system is that it was very frustrating. Fighting monsters was often not worth it because it&#39;d make your weapons break, and there was a big chance that whatever new weapons you&#39;d get from fighting them would be worse.</p>
<p>In TOTK, all weapons are now &quot;decayed&quot;, which means their durability is even lower. But, remember the Fuse ability? Whenever you fuse a material to your weapons, they become stronger and more durable. And most of the better materials are obtained from... killing monsters! So, chances are, if you fight monsters you&#39;ll probably end up with better materials that make your weapons stronger than before! It&#39;s as it should be.</p>
<p>I admire that, after all the backlash this system had in BOTW, they didn&#39;t simply remove it, and instead figured out a way to make that game system enjoyable and unique. Mix-and-matching weapons and materials was a fun part of the game, and made it a lot more varied.</p>
<h2 id="hylian-engineering">Hylian Engineering</h2>
<p>Ultrahand lets you attach objects to each other, and there are a ton of objects in the world, including new Zonai devices, which include things like motorized wheels, steering sticks, and fans. They could have half-assed this mechanic and limit how you can attach things to each other, or the number of objects you can use. But nope, they went all the way. That final trailer gives you a taste of just how flexible it is, with Link riding a tank made of stone, with wheels and arms (at the 2:33 mark), and that only scratches the surface.</p>
<p>I had a lot of fun building things! Honestly, most of the stuff I built either didn&#39;t work or was a car that was slower than walking, but the fun of experimenting was worth it. By the end of the game, I was already building flying machines to cross Hyrule with.</p>
<p><img src="https://rsinfo.vercel.app/images/posts/review-zelda-tears-of-the-kingdom/link-and-zelda.JPG" alt="Link and Zelda in their royal clothes in a forest"></p>
<h2 id="story">Story</h2>
<p>It&#39;s hard to talk about the story without spoiling, but I just want to say: it is <strong>very good</strong>. Even with all the freedom and gameplay possibilities of the game, it doesn&#39;t feel like the story takes a backseat this time. It has incredible moments, great pacing, and honestly one of the best endings I&#39;ve ever seen in a game. It brings back some Zelda conventions but also has some unexpected twists that keep it from being predictable. Zelda games were never known for having a super complex and nuanced story, but as far as heroic adventure games go, this is one of the best.</p>
<h2 id="problems">Problems</h2>
<p>This review has been very positive so far, which doesn&#39;t mean the game doesn&#39;t have problems. But honestly, they are a bit hard to identify now because they&#39;re very minor and they don&#39;t stain the overall experience. You might notice them while playing, but they don&#39;t stick out in your memory after you play, if that makes sense.</p>
<p>The main issue of the game might be a huge deal to some people, but less so to others. The thing is, <strong>this game has so much of everything!</strong> There are so many mechanics, sidequests, places to explore, things to find and collect, stories to see, people to save. And honestly, besides some of the collectibles, which are understandably many because the world is so big, all of them are pretty high quality. I never found a sidequest that I just didn&#39;t want to do.</p>
<p>The problem is, it can become quite overwhelming. If you&#39;re one of those people that feel overwhelmed by having many (optional) things to do, you will feel overwhelmed with this game. When I first started playing I felt like that, and I wanted to do everything, because it was so good. Of course, eventually the feeling of <strong>having</strong> to do everything made it a bit of a chore to play. I realized this and also realized that the game was not making me do any of those things at all. It was just giving me the freedom of choosing what I liked best. So, I started focusing on some of my favorite things and decided to progress the main story until I got to the ending.</p>
<p>Not everyone will be able to do that, though. And I can totally see those people giving up on the game because it&#39;s just too much.</p>
<p><img src="https://rsinfo.vercel.app/images/posts/review-zelda-tears-of-the-kingdom/balloon.JPG" alt="Screenshot of the game, with a hot air balloon flying, with the sunrise in the horizon"></p>
<h2 id="verdict">Verdict</h2>
<p>Tears of the Kingdom is the ultimate Zelda game - and to me, also the ultimate open-world game. I finished the main story and did a lot of side content, but after 95 hours, I only played a fraction of what the game has to offer.</p>
<p><img src="https://rsinfo.vercel.app/images/posts/review-zelda-tears-of-the-kingdom/tropical-village.JPG" alt="Screenshot of the game, showing a tropical village with palm trees and huts. A lot of people are partying around bonfires"></p>
<p>I believe its impact is not as big as Breath of the Wild&#39;s was, though, at least not to me personally. That was a rebirth of the series, and it came at a moment of big changes in my life. TOTK, in comparison, doesn&#39;t fully reinvent anything, but instead improves (greatly) all the reinventions that BOTW did. It&#39;s not fair to judge a game by its impact alone though. If every single game reinvented everything, then reinvention wouldn&#39;t matter.</p>
<p>If BOTW was a 10/10 to me, because of its impact and just how good it was, then there&#39;s no way TOTK, which improves on BOTW in every single way, could be anything less than that.</p>
<p>So, yeah, <span>Tears of the Kingdom is a 10/10</span>. It is a masterpiece, one of the best games I&#39;ve ever played, and I&#39;ll remember it fondly for years to come. It will be <strong>very</strong> hard for the Zelda team to ever top this game, but if anyone can do it, it&#39;s them.</p>

          ]]></content:encoded>
          <media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://rsinfo.vercel.app/images/posts/review-zelda-tears-of-the-kingdom/cover.jpg"/>
          <media:content xmlns:media="http://search.yahoo.com/mrss/" medium="image" url="https://rsinfo.vercel.app/images/posts/review-zelda-tears-of-the-kingdom/cover.jpg"/>          
        </item>
      
        <item>
          <guid>https://rsinfo.vercel.app/automatically-manage-node-versions</guid>
          <title>How to automatically manage Node versions</title>
          <description>Tired of manually switching Node versions for different projects? Discover how to automate the process using nvm.</description>
          <link>https://rsinfo.vercel.app/automatically-manage-node-versions</link>
          <pubDate>Sun, 10 Sep 2023 17:26:42 +0000</pubDate>
          
          <content:encoded><![CDATA[
            <div style="margin: 50px 0; font-style: italic;">
              If anything looks wrong, 
              <strong>
                <a href="https://rsinfo.vercel.app/automatically-manage-node-versions">
                  read on the site!
                </a>
              </strong>
            </div>

            <p>If you&#39;re like me, you&#39;re constantly jumping between projects, and often those projects need different versions of NodeJS. Ideally, all of them would be using (or compatible with) the latest version, but in reality a lot of those projects are old and you just don&#39;t have the time to update them and make sure all dependencies play nice.</p>
<p>When jumping between them, it&#39;s usually a pain to remember which Node version to use and have to switch to that version. Tools like <a href="https://github.com/nvm-sh/nvm">nvm</a> make it easy to switch, but it&#39;s still a manual task that we often forget to do.</p>
<p>Turns out, you can use nvm to automatically switch the NodeJS version when you <code>cd</code> into a folder! All you need is a file in your project and a few lines of magic in your bash/zsh profile.</p>
<h2 id="configuring-your-shell-profile-to-change-node-versions">Configuring your shell profile to change Node versions</h2>
<p>The first step is to edit your shell profile file, so that every time you <code>cd</code> into a folder, it checks if there&#39;s a <code>.nvmrc</code> file and if so, it switches to that Node version.</p>
<h3 id="if-using-zsh">If using zsh</h3>
<p>If you&#39;re using zsh, you can add the following to your <code>.zshrc</code> file:</p>
<pre><code class="language-shell">~filename .zshrc

# Automatically use Node version specified via .nvmrc file

# place this after nvm initialization!
autoload -U add-zsh-hook
load-nvmrc() {
  local node_version=&quot;$(nvm version)&quot;
  local nvmrc_path=&quot;$(nvm_find_nvmrc)&quot;

  if [ -n &quot;$nvmrc_path&quot; ]; then
    local nvmrc_node_version=$(nvm version &quot;$(cat &quot;${nvmrc_path}&quot;)&quot;)

    if [ &quot;$nvmrc_node_version&quot; = &quot;N/A&quot; ]; then
      nvm install
    elif [ &quot;$nvmrc_node_version&quot; != &quot;$node_version&quot; ]; then
      nvm use
    fi
  elif [ &quot;$node_version&quot; != &quot;$(nvm version default)&quot; ]; then
    echo &quot;Reverting to nvm default version&quot;
    nvm use default
  fi
}
add-zsh-hook chpwd load-nvmrc
load-nvmrc
</code></pre>
<h3 id="if-using-bash">If using bash</h3>
<p>With bash, you can add the following to your <code>.bash_profile</code> file:</p>
<pre><code class="language-bash">~filename .bash_profile

# Automatically use Node version specified via .nvmrc file

# place this after nvm initialization!
load_nvmrc() {
  local node_version=&quot;$(nvm version)&quot;
  local nvmrc_path=&quot;$(nvm_find_nvmrc)&quot;

  if [ -n &quot;$nvmrc_path&quot; ]; then
    local nvmrc_node_version=$(nvm version &quot;$(cat &quot;${nvmrc_path}&quot;)&quot;)

    if [ &quot;$nvmrc_node_version&quot; = &quot;N/A&quot; ]; then
      nvm install
    elif [ &quot;$nvmrc_node_version&quot; != &quot;$node_version&quot; ]; then
      nvm use
    fi
  elif [ &quot;$node_version&quot; != &quot;$(nvm version default)&quot; ]; then
    echo &quot;Reverting to nvm default version&quot;
    nvm use default
  fi
}

if [ -n &quot;$BASH_VERSION&quot; ]; then
  PROMPT_COMMAND=&quot;load_nvmrc; $PROMPT_COMMAND&quot;
fi
</code></pre>
<h2 id="creating-a-nvmrc-file">Creating a .nvmrc file</h2>
<p>Inside your project folder, create a file called <code>.nvmrc</code> and add the Node version you want to use. For example, if you want to use Node 14.18.0, you&#39;d add the following to the file:</p>
<pre><code class="language-shell">v14.18.0
</code></pre>
<p><strong>You need to do this for every project</strong> that needs a specific NodeJS version. If you don&#39;t add a <code>.nvmrc</code> file, nvm will use the default.</p>

          ]]></content:encoded>
          <media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://rsinfo.vercel.app/images/posts/automatically-manage-node-versions/Cover.png"/>
          <media:content xmlns:media="http://search.yahoo.com/mrss/" medium="image" url="https://rsinfo.vercel.app/images/posts/automatically-manage-node-versions/Cover.png"/>          
        </item>
      
        <item>
          <guid>https://rsinfo.vercel.app/iron-maiden-killers-concept-album</guid>
          <title>Iron Maiden's "Killers" is a concept album</title>
          <description>Seriously, hear me out</description>
          <link>https://rsinfo.vercel.app/iron-maiden-killers-concept-album</link>
          <pubDate>Fri, 16 Jun 2023 00:00:00 +0000</pubDate>
          
          <content:encoded><![CDATA[
            <div style="margin: 50px 0; font-style: italic;">
              If anything looks wrong, 
              <strong>
                <a href="https://rsinfo.vercel.app/iron-maiden-killers-concept-album">
                  read on the site!
                </a>
              </strong>
            </div>

            <p>So, today I was doing the dishes and decided to listen to some music on my headphones. I was in the mood for some Iron Maiden, so I shuffled my playlist of my favorites from them (which includes almost every one of their songs 😆). The first track to play was <em>Drifter</em>, the last song from their second album, <em>Killers</em>. It&#39;s a really good song so I decided to play the entire album instead.</p>
<p>I&#39;ve listened to this album countless times, but I&#39;d never really paid attention to the lyrics. So, as the album played, I was surprised by the small <em>plot twist</em> at the end of <em>Murders In The Rue Morgue</em>, which was one of the songs I never really paid much attention to the lyrics. I was like <em>&quot;wait, what?!&quot;</em> and decided to pay more attention to the lyrics of the rest of the album. And then it hit me: <span>Killers is a concept album</span>, with all songs being sung by the same character!</p>
<blockquote>
<p>[!warning]
The album touches on the subjects of murder, suicide and drugs, so be wary of proceeding if this is a sensitive topic for you.</p>
</blockquote>
<p>So, let&#39;s go through each song and see how they fit together. Feel free to follow along with the music:</p>
<iframe style="border-radius:12px" src="https://open.spotify.com/embed/album/5REF2imQI3lMAmeWcDXE3D?utm_source=generator" width="100%" height="352" frameBorder="0" allowfullscreen="" allow="autoplay; clipboard-write; encrypted-media; fullscreen; picture-in-picture" loading="lazy"></iframe>

<h2 id="the-ides-of-march">The Ides Of March</h2>
<p>This song is instrumental, so there&#39;s not much to analyse here (the music is awesome though!). All we have is the name of the song, which refers to the fate of Julius Caesar, most famously retold by Shakespeare, after he was warned to “beware the Ides of March”; he was brutely murdered on that date.</p>
<p>So, yeah, the album starts with a warning of what&#39;s to come. It&#39;s no secret that a concept album called &quot;Killers&quot; is going to be about murder, right?</p>
<h2 id="wrathchild">Wrathchild</h2>
<p>Here we get introduced to the narrator (which we&#39;ll call &quot;Wrathchild&quot; from now on). He seems to have had a very troubled childhood, as seen below:</p>
<blockquote>
<p>I was born into a scene of angriness and greed<br>Dominance and persecution<br>My mother was a queen, my dad I&#39;ve never seen<br>I was never meant to be</p>
</blockquote>
<p>This obviously isn&#39;t good and a child that goes through that kind of trauma will likely have issues in the future - as seen in the next verse, where the Wrathchild talks about an obsessive wish to meet his father.</p>
<blockquote>
<p>And now I spend my time looking all around<br>For a man that&#39;s nowhere to be found<br>Until I find him, I&#39;m never gonna stop searching<br>I&#39;m gonna find my man, gonna travel around
(...)<br>Say it doesn&#39;t matter, ain&#39;t nothin&#39; gonna alter<br>The course of my destination<br>know I&#39;ve got to find some serious peace of mind<br>Or I know I&#39;ll just go crazy</p>
</blockquote>
<p>Already feeling the consequences of a troubled childhood, the Wrathchild starts traveling around in search of his father. Which leads us to...</p>
<h2 id="murders-in-the-rue-morgue">Murders In The Rue Morgue</h2>
<p>Honestly the lyrics of this song are much more straightforward since it&#39;s a more direct narration of what&#39;s going on. I&#39;m gonna bring over only the most relevant parts:</p>
<blockquote>
<p>I was strolling through the streets of Paris<br>And then I heard a piercing scream And I rushed to the scene of the crime<br>But all I found was the butchered remains Of two girls layin&#39; side by side</p>
</blockquote>
<p>The Wrathchild (who was traveling around in search of their father) is now in Paris and suddenly finds the scene of a murder in the street.</p>
<blockquote>
<p>There&#39;s some people coming down the street<br>At last someone heard my call<br>Can&#39;t understand why they&#39;re pointing at me<br>I never done nothing at all<br>But I got some blood on my hands<br>Because everybody&#39;s shouting at me<br>I can&#39;t speak French so I couldn&#39;t explain<br>And like a fool I started running away</p>
</blockquote>
<p>People start accusing the Wrathchild as the murderer, and he can&#39;t defend himself since he doesn&#39;t speak the local language. He starts running away out of panic, and then starts being persecuted by the law, which makes him flee France through the southern border, to Italy.</p>
<blockquote>
<p>If I could go to somebody for help<br>To get me out of trouble for sure<br>But I know that it&#39;s on my mind<br>That my doctor said I&#39;ve done it before</p>
</blockquote>
<p>.... Ooooh! That last line is a big plot twist! This means that the Wrathchild might actually be the murderer, he just doesn&#39;t remember it, and his doctor has told him something similar has happened before. To me, this strongly implies <a href="https://en.wikipedia.org/wiki/Dissociative_identity_disorder">Dissociative Identity Disorder (DID)</a>, which often originates from trauma (the troubled childhood), and would explain how the Wrathchild could have murdered someone and not remember it. It also explains the &quot;I got some blood on my hands&quot; line earlier in the song, which apparently wasn&#39;t a metaphor...</p>
<p>It&#39;s also worth noting that it seems that the <em>killer</em> personality might be the one that&#39;s causing the urge to run away, as that personality knows what it&#39;s done.</p>
<h2 id="another-life">Another Life</h2>
<blockquote>
<p>As I lay here lying on my bed<br>Sweet voices come into my head<br>(...)<br>There&#39;s a feeling that&#39;s inside me<br>Telling me to get away, yeah<br>But I&#39;m so tired of living<br>I might as well end today</p>
</blockquote>
<p>This song&#39;s lyrics and pretty short. Here, the Wrathchild talks about hearing voices in his head, and these voices are telling him to &quot;get away&quot;. It&#39;s probably the voice of the <em>killer</em> personality from the previous song. The Wrathchild is tired of living and contemplates suicide.</p>
<h2 id="genghis-khan">Genghis Khan</h2>
<p>This is another instrumental song and doesn&#39;t really tie in to the rest of the album&#39;s theme - except for the fact the Genghis Khan killed a lot of people, I guess?</p>
<h2 id="innocent-exile">Innocent Exile</h2>
<blockquote>
<p>My life is so empty, nothing to live for<br>My mind is all confusion, &#39;cos I defied the law<br>When you weren&#39;t there to help me, I lost my mind and ran<br>I never had no trouble before this all began, yeah</p>
</blockquote>
<p>In this song, the Wrathchild is still suffering the consequences of the Murder in the Rue Morgue. They claim their mind is confused (which makes sense because of DID).</p>
<p>Another <strong>really</strong> interesting line is when he says he &quot;never had no trouble before this all began&quot;. Usually cases of DID occur because the mind is trying to protect itself from the trauma. So, it makes sense that this personality feels like it never had any trouble before, as it <span>doesn't remember any of the trauma</span>. All the bottled up anger was instead channeled into the <em>killer</em> personality.</p>
<blockquote>
<p>They say I killed a woman, they know it isn&#39;t true<br>They&#39;re just trying to frame me, and all because of you, yeah</p>
</blockquote>
<p>This last line feels like one personality talking to another. The Wrathchild appears to be aware that the <em>Killer</em> exists, and is talking directly to it. However, it doesn&#39;t seem like he realizes that they are in fact the same person.</p>
<h2 id="killers">Killers</h2>
<p>In the title track, the lines between the personalities start to blur. Think about it - so far there has been only one killer in the album, but the track is called Killers, <em>plural</em>.</p>
<p>The first verse of the song is narrated by the Wrathchild:</p>
<blockquote>
<p>You walk through the subway, his eyes burn a hole in your back<br>A footstep behind you, he lunges prepared for attack<br>Scream for mercy, he laughs as he&#39;s watching you bleed<br>Killer behind you, his blood lust defies all his needs</p>
</blockquote>
<p>While the second verse is narrated by the <em>Killer</em> personality, but <strong>pay attention to the last line</strong>:</p>
<blockquote>
<p>My innocent victims are slaughtered with wrath and despise<br>The mocking religion of hatred that burns in the night<br>I have no one, I&#39;m bound to destroy all this greed<br><strong>A voice inside me compelling to satisfy me</strong></p>
</blockquote>
<p>The other 3 lines are sang by the <em>Killer</em>, but that last one seems to be sang by the Wrathchild, since the voice inside him is the <em>Killer</em>.</p>
<p>At the end of the song, the line between the two personalities seem to have disappeared completely. It&#39;s really similar to the first verse of the song, but the pronouns are all mixed up now, and we don&#39;t really know who is talking anymore.</p>
<blockquote>
<p>You walk through the subway, <strong>my</strong> eyes burn a hole in your back<br>A footstep behind you, <strong>he</strong> lunges prepared for attack<br>Scream for mercy, <strong>he</strong> laughs as <strong>he</strong>&#39;s watching you bleed<br>Killer behind you, <strong>my</strong> blood lust defies all <strong>my</strong> needs<br>Ooh look out, <strong>I</strong>&#39;m coming for you!</p>
</blockquote>
<p>🤯</p>
<h2 id="prodigal-son">Prodigal Son</h2>
<p>This song was the hardest to make sense of, but I think I figured out how it fits overall. In this song, the Wrathchild seems to be back in control, but has become aware of the <em>Killer</em> personality, and aware that they are the same person.</p>
<p>A &quot;Prodigal Son&quot; is a person that leaves home to live a reckless life, and then makes a repentant return. This is exactly what the Wrathchild is doing in this song. He is repenting for the murders he committed, and is scared of his inner urges and scared of ending his own life.</p>
<blockquote>
<p>Listen to me, Lamia, listen to what I&#39;ve got to say<br>I&#39;ve got these feelings and they won&#39;t go away<br>I&#39;ve got these fears inside that&#39;ll bring me to my knees<br>Oh, help me, Lamia, or I&#39;m sure I&#39;ll die, oh, please<br>I feel unsettled, now I know that I&#39;ve done wrong<br>I&#39;ve messed around with mystic things and magic for far too long<br>I feel I&#39;m being paid with this nightmare inside me<br>The devil&#39;s got a hold on my soul and he just won&#39;t let me be</p>
</blockquote>
<p>Here it becomes clear that the Wrathchild now understands better what&#39;s been going on, and starts asking Lamia for help. He mentions &quot;mystic things and magic&quot; which could be a reference to the uncommon and unknown nature of his disorder (which could be seen as some sort of &quot;magic&quot; or &quot;pact with the devil&quot;). Maybe he sees the <em>Killer</em> as the devil taking hold of his soul.</p>
<p><strong>But who is Lamia?</strong> I&#39;ve found some info about her being a monster in Greek Mythology. But what caught my attention was this line from <a href="https://en.wikipedia.org/wiki/Lamia">the Wikipedia article</a>:</p>
<blockquote>
<p>The &quot;Lamia&quot; was a bogeyman or bugbear term, invoked by a mother or a nanny to frighten children into good behavior.</p>
</blockquote>
<p>It makes sense for a traumatized person to recall his childhood and think of the &quot;bogeyman&quot; that used to be used to scare him into behaving. The Wrathchild definitely feels like he deserves some sort of punishment in order to atone for his sins.</p>
<h2 id="purgatory">Purgatory</h2>
<p>This absolute banger of a song has some cryptic lyrics, but I&#39;m confident they are about the Wrathchild trying to get away from his pain by resorting to drugs, possibly LSD.</p>
<blockquote>
<p>I split my brain, melt through the floor<br>Over clouds my mind will fly<br>Forever now I can&#39;t think why<br>My body tries to leave my soul<br>Is it me, I just don&#39;t know</p>
</blockquote>
<p>&quot;Split my brain&quot; could be a reference to the DID, and &quot;melt through the floor&quot; could be a reference to the effects of LSD. The sensation of the soul leaving the body is a commonly reported effect of the drug.</p>
<blockquote>
<p>Oh, another time, another place<br>Oh, another smile on another face<br>Please take me away, take me away, so far away</p>
</blockquote>
<p>These effects, while confusing, appear to be a welcome escape from the Wrathchild&#39;s pain. He seems to be able to picture a different life where he is actually happy, and wants to be taken to that place. The name of the song, Purgatory, makes a lot of sense in this context, as he seems to be in a state that&#39;s not really good, but it&#39;s at least better than the life he&#39;s had.</p>
<h2 id="drifter">Drifter</h2>
<p>The last song of the album depicts the Wrathchild after being severely affected by the drugs. He is now a drifter, and seems to be wanting to &quot;cure&quot; other people of their pain by bringing them over to the same &quot;purgatory&quot; he&#39;s been living in.</p>
<blockquote>
<p>Gonna get you feeling so secure<br>Listen, child, don&#39;t you see there&#39;s a cure?<br>Anyway, got to get you away<br>Feels so good, think it&#39;s gonna be a new day</p>
</blockquote>
<p>The song (and the album) then ends with the Wrathchild fading out &quot;singing his song&quot;. It&#39;s not really a happy ending, but one that makes a lot of sense, doesn&#39;t it?</p>
<h2 id="wrapping-up">Wrapping up</h2>
<p>So.... that&#39;s it. I hope you enjoyed going down this rabbit hole with me. I&#39;m pretty sure a lot of this wasn&#39;t intended by the band, but it&#39;s my interpretation and that&#39;s good enough for me.</p>
<p>Up the Irons! 🤘</p>

          ]]></content:encoded>
          <media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://rsinfo.vercel.app/images/posts/iron-maiden-killers-concept-album/cover.png"/>
          <media:content xmlns:media="http://search.yahoo.com/mrss/" medium="image" url="https://rsinfo.vercel.app/images/posts/iron-maiden-killers-concept-album/cover.png"/>          
        </item>
      
        <item>
          <guid>https://rsinfo.vercel.app/container-queries</guid>
          <title>Container Queries Are Here!</title>
          <description>Responsive web development will never be the same again.</description>
          <link>https://rsinfo.vercel.app/container-queries</link>
          <pubDate>Thu, 16 Feb 2023 00:00:00 +0000</pubDate>
          
          <content:encoded><![CDATA[
            <div style="margin: 50px 0; font-style: italic;">
              If anything looks wrong, 
              <strong>
                <a href="https://rsinfo.vercel.app/container-queries">
                  read on the site!
                </a>
              </strong>
            </div>

            <p>With the release of <a href="https://www.mozilla.org/en-US/firefox/110.0/releasenotes/">Firefox 110</a>, <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Container_Queries">CSS container queries</a> are now supported in all major browsers! It has joined Chromium (since v105) and Safari (since v16) in adding support to what I consider a revolution on responsive web development, especially to people who build UIs in a component-driven way.</p>
<h2 id="what-are-container-queries">What are container queries?</h2>
<p>Usually when we do responsive development, we use media queries to change the layout of our components based on the viewport/screen/window size. So, for example, we can have a card component that&#39;s displayed like this on a laptop:</p>
<p><img src="https://rsinfo.vercel.app/images/posts/container-queries/Pre-CQ-Desktop.png" alt="A large window frame with a card taking up 100% of its width. Since it&#39;s a large window, the card will display its contents horizontally."></p>
<p>And, if the window size is smaller (for example on mobile), we can use a media query to change how the card is displayed:</p>
<p><img src="https://rsinfo.vercel.app/images/posts/container-queries/Pre-CQ-Mobile.png" alt="A small window frame with a card taking up 100% of its width. Since it&#39;s a small window, the card will display its contents vertically."></p>
<p>This can be done with code like this:</p>
<pre><code class="language-html">&lt;style&gt;
    .card {
        display: flex;
        flex-direction: row;
    }

    @media (max-width: 600px) {
        .card {
            flex-direction: column;
        }
    }
&lt;/style&gt;

&lt;div class=&quot;card&quot;&gt;
    &lt;!-- card content --&gt;
&lt;/div&gt;
</code></pre>
<p>So far, so good. But what if the card doesn&#39;t take up the entire width of the screen? We might want to display it in a sidebar with much less horizontal space, and have another card in the main content area, taking up the rest of the screen width. Here&#39;s how we want it to look:</p>
<p><img src="https://rsinfo.vercel.app/images/posts/container-queries/Sidebar-Example.png" alt="A large window frame with a sidebar taking up a third of its space. A card is displayed in the sidebar, taking up 100% of its width. The card will display its contents vertically. The main content area takes up the rest of the screen width. A card is displayed in the main content area, taking up 100% of its width. The card displays its contents horizontally."></p>
<p>But how can we do this, if the screen is not small enough to trigger our media query and display the card&#39;s contents vertically? Previously, the ways of doing this were either to use JavaScript (by checking the window width every time it changes and then toggling a class in the card component) or using <code>flex-wrap: wrap</code>, which is better than using JavaScript, but really hard to get right.</p>
<p>This is where container queries come in. With container queries, we can change the layout of our components based on the size of the container they&#39;re in. So, instead of using the viewport size to control how the card is displayed, we can use the size of the card&#39;s container.</p>
<h2 id="how-to-use-container-queries">How to use container queries</h2>
<p>Starting from the problem described above, we can use container queries to fix it like this:</p>
<pre><code class="language-html">&lt;style&gt;
    .container {
        /* A containment context needs to be declared on the container element */
        container-type: inline-size;
    }

    .card {
        display: flex;
        flex-direction: row;
    }

    /* 
    Instead of @media, we use @container to use its size instead
  */
    @container (max-width: 600px) {
        .card {
            flex-direction: column;
        }
    }
&lt;/style&gt;

&lt;div class=&quot;container&quot;&gt;
    &lt;div class=&quot;card&quot;&gt;
        &lt;!-- card content --&gt;
    &lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;container&quot;&gt;
    &lt;div class=&quot;card&quot;&gt;
        &lt;!-- card content --&gt;
    &lt;/div&gt;
&lt;/div&gt;
</code></pre>
<p>Now, if the card&#39;s container is smaller than 600px, the card will display its contents vertically. If it&#39;s larger, it will display its contents horizontally.</p>
<h2 id="nested-containers">Nested Containers</h2>
<p>In situations where we would have nested containers, things can get a bit messy. That&#39;s why you can also name a container, using the <code>container-name</code> property, and then use that name in the <code>@container</code> rule. In this example, we want the card to use the <code>.outer-container</code>&#39;s size as a base, instead of its immediate parent container&#39;s size:</p>
<pre><code class="language-html">&lt;style&gt;
    .outer-container {
        container-type: inline-size;
        container-name: outer-container;
    }

    .inner-container {
        container-type: inline-size;
        container-name: inner-container;
    }

    .card {
        display: flex;
        flex-direction: row;
    }

    @container outer-container (max-width: 600px) {
        .card {
            flex-direction: column;
        }
    }
&lt;/style&gt;

&lt;div class=&quot;outer-container&quot;&gt;
    &lt;div class=&quot;inner-container&quot;&gt;
        &lt;div class=&quot;card&quot;&gt;
            &lt;!-- card content --&gt;
        &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class=&quot;inner-container&quot;&gt;
        &lt;div class=&quot;card&quot;&gt;
            &lt;!-- card content --&gt;
        &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;
</code></pre>
<p><em>Easy, right?</em></p>
<h2 id="fallback-for-older-browsers">Fallback for older browsers</h2>
<p>As mentioned before, the latest versions of all major browsers support this feature. However, some users might take a while to update their browsers and your site might look broken in the meantime. To avoid this, you can add a <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Conditional_Rules/Using_Feature_Queries">feature check</a> in your CSS that checks for container queries support and only apply the styles if the browser supports it:</p>
<pre><code class="language-css">@supports (container-type: inline-size) {
    /* container queries styles */
}

@supports not (container-type: inline-size) {
    /* fallback styles */
}
</code></pre>
<p>As for fallback styles, I recommend giving <code>flex-wrap: wrap</code> a try. It&#39;s not that easy to use, but you can emulate the behavior of container queries in a way that&#39;s <em>good enough</em> for the users who haven&#39;t updated their browsers yet.</p>
<h2 id="wrapping-up">Wrapping Up</h2>
<p>Years ago, when I started learning about responsive development and working with components, I eventually hit a barrier when I couldn&#39;t find a good way of making components adapt to their size like this. Which is why I&#39;m so excited this is finally happening! It&#39;s an exciting time to be a web developer and I can&#39;t wait to see what&#39;s next.</p>

          ]]></content:encoded>
          <media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://rsinfo.vercel.app/images/posts/container-queries/cover.jpg"/>
          <media:content xmlns:media="http://search.yahoo.com/mrss/" medium="image" url="https://rsinfo.vercel.app/images/posts/container-queries/cover.jpg"/>          
        </item>
      
        <item>
          <guid>https://rsinfo.vercel.app/css-hover-media-query</guid>
          <title>Conditional Hover Styles in CSS</title>
          <description>Have you ever crafted a nice hover effect for an element in your website, then opened it on mobile and saw that effect erroneously appear when that element is tapped on?</description>
          <link>https://rsinfo.vercel.app/css-hover-media-query</link>
          <pubDate>Sun, 12 Feb 2023 00:00:00 +0000</pubDate>
          
          <content:encoded><![CDATA[
            <div style="margin: 50px 0; font-style: italic;">
              If anything looks wrong, 
              <strong>
                <a href="https://rsinfo.vercel.app/css-hover-media-query">
                  read on the site!
                </a>
              </strong>
            </div>

            <p>Have you ever crafted a nice hover effect for an element in your website, then opened it on mobile and saw that effect erroneously appear when that element is tapped on? That’d be nice perhaps, if it weren’t for the fact that the effect just… stays there.</p>
<p>That happens because touch-based browsers apply the hover effect to an element when it’s tapped on regardless of hover capabilities and keep that effect active until you tap something else. Why do they do this? My guess is backwards compatibility, as many websites built with a mouse cursor in mind can hide important information behind a hover action, like for example displaying a tooltip.</p>
<p>Luckily, if you want to avoid having the hover effect applied when it shouldn’t be (and instead using <code>:focus</code> and <code>:active</code> selectors properly), there’s a CSS media query to help with that:</p>
<pre><code class="language-css">@media (hover: hover) {
    .my-component {
        /* Styles here */
    }
}
</code></pre>
<p>If you wanna do the opposite (add styles only to devices that do not support hover), you can use <code>hover: none</code> instead:</p>
<pre><code class="language-css">@media (hover: none) {
    .my-component {
        /* Styles here */
    }
}
</code></pre>
<p>And there you go! This is a nice thing to keep in mind whether you build mobile-first or desktop-first, as adding that media query to hover styles at the same time you&#39;re developing the styles themselves will avoid any unintended effects.</p>

          ]]></content:encoded>
          <media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://rsinfo.vercel.app/images/posts/css-hover-media-query/cover.jpg"/>
          <media:content xmlns:media="http://search.yahoo.com/mrss/" medium="image" url="https://rsinfo.vercel.app/images/posts/css-hover-media-query/cover.jpg"/>          
        </item>
      
        <item>
          <guid>https://rsinfo.vercel.app/who-runs-our-code</guid>
          <title>Who Runs Our Code</title>
          <description>In a world with tons of business requirements, conversion metrics, and a stampede of new technologies, front-end development can easily become oblivious of one thing: where our code runs.</description>
          <link>https://rsinfo.vercel.app/who-runs-our-code</link>
          <pubDate>Fri, 10 Feb 2023 00:00:00 +0000</pubDate>
          
          <content:encoded><![CDATA[
            <div style="margin: 50px 0; font-style: italic;">
              If anything looks wrong, 
              <strong>
                <a href="https://rsinfo.vercel.app/who-runs-our-code">
                  read on the site!
                </a>
              </strong>
            </div>

            <p>In a world with tons of business requirements, conversion metrics, and a stampede of new technologies, front-end development can easily become oblivious of one thing: where our code runs.</p>
<blockquote>
<p>[!info]
When I say front-end developer, I don&#39;t just mean those who work on the web. I mean everyone who writes code that runs directly on a user&#39;s machine - be it a website, a mobile app, a desktop program, or even an IoT driver.</p>
</blockquote>
<p>Software development is hard. And not just because of coding itself (which might be the easiest part sometimes), but mostly because in the end, developing commercial software is a great balancing act. We need to balance time, quality, features and expectations all the time.</p>
<p>In an ideal situation, we should have all the time we need to make sure all our components are bug-free, testable, accessible, generic, performant and intuitive. The main problem is, developers are often the only ones who read the code, and therefore the only ones in a company that care about more than 2 of the items above.</p>
<p>Still, it’s valid to take a shot every once in a while and try to push for higher standards. <span>In a way you’re borrowing the user’s machine to run your code</span>, and if you care about your user you wanna make sure that code is the best it could be.</p>

          ]]></content:encoded>
          <media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://rsinfo.vercel.app/images/posts/who-runs-our-code/cover.jpg"/>
          <media:content xmlns:media="http://search.yahoo.com/mrss/" medium="image" url="https://rsinfo.vercel.app/images/posts/who-runs-our-code/cover.jpg"/>          
        </item>
      
        <item>
          <guid>https://rsinfo.vercel.app/from-twitter-to-mastodon</guid>
          <title>From Twitter to Mastodon</title>
          <description>Turns out the elephant network feels much lighter than the bird one.</description>
          <link>https://rsinfo.vercel.app/from-twitter-to-mastodon</link>
          <pubDate>Tue, 07 Feb 2023 00:00:00 +0000</pubDate>
          
          <content:encoded><![CDATA[
            <div style="margin: 50px 0; font-style: italic;">
              If anything looks wrong, 
              <strong>
                <a href="https://rsinfo.vercel.app/from-twitter-to-mastodon">
                  read on the site!
                </a>
              </strong>
            </div>

            <p>I’m one of the many people that stopped using Twitter after the latest… 💩 <em>developments</em> since it was purchased by Elon Musk. My account still exists, but I’ve deleted all of my tweets and uninstalled the mobile app, and haven’t opened the website in a good while.</p>
<p>Like many, I’ve moved to Mastodon, and so did ~90% of the people I used to follow. Initially it did feel a bit rough! This forced change required me to adapt and learn how the platform works. But I’m glad I did it!</p>
<p>Nowadays my Mastodon community is almost the same as my previous Twitter one, with a few added people, but it feels tighter. It’s hard to explain, but it seems like I feel much closer to them. I guess the lack of a recommendation algorithm (timeline is always in reverse chronological order) makes people actually see each others’ posts, and liking/replying/boosting(retweeting) is way more common.</p>
<p>There’s one category of Twitter account that hasn’t really moved to Mastodon yet: brands. I used to follow some brands on Twitter just to keep up to date on stuff, and brands like Notion and Arc do a great job with their accounts! But I’m not sure I wanna see that on Mastodon, at least not on that level. The best part of it is how it’s built and used by <em>real people</em>, and not brands or influencers simply seeking engagement. You know, kinda like Twitter in its early days.</p>
<p>If you wanna follow me in there, feel free to do so! I’m on <a href="https://hachyderm.io/@fantinel">hachyderm.io/fantinel</a> , or you can search me in there by <a href="https://hachyderm.io/@fantinel">@fantinel@hachyderm.io</a>. Happy tooting!</p>

          ]]></content:encoded>
          <media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://rsinfo.vercel.app/images/posts/from-twitter-to-mastodon/cover.png"/>
          <media:content xmlns:media="http://search.yahoo.com/mrss/" medium="image" url="https://rsinfo.vercel.app/images/posts/from-twitter-to-mastodon/cover.png"/>          
        </item>
      
        <item>
          <guid>https://rsinfo.vercel.app/2022-year-in-review</guid>
          <title>2022 In Hindsight</title>
          <description>A year of big changes, both to me and to the world.</description>
          <link>https://rsinfo.vercel.app/2022-year-in-review</link>
          <pubDate>Mon, 19 Dec 2022 00:00:00 +0000</pubDate>
          
          <content:encoded><![CDATA[
            <div style="margin: 50px 0; font-style: italic;">
              If anything looks wrong, 
              <strong>
                <a href="https://rsinfo.vercel.app/2022-year-in-review">
                  read on the site!
                </a>
              </strong>
            </div>

            <p>2022 is ending and it brought a lot of changes to the lives of many - me included. I&#39;m not able to say all of them were good, but they also bring opportunities of personal and societal growth, and for me at least, a little glimpse of hope.</p>
<h2 id="last-years-predictions">Last Year&#39;s Predictions</h2>
<p><a href="https://rsinfo.vercel.app/2021-year-in-review">Last year</a> I wrote about a few things that were hopefully gonna happen this year and I got half of them right:</p>
<ul>
<li>💍 I <strong>did</strong> get married! The love of my life and I did make it official. We had a nice, somewhat small ceremony and reception for family and friends, and everything was very emotional and beautiful. We already had been living together for 4 years, so the wedding did not represent a big change in our lives, but as a celebration of love it did it&#39;s job of being fun and keeping hearts and bellies full and warm.</li>
<li>🇮🇹 I <strong>did</strong> move temporarily to Italy, and lived there for 3 months. It was an interesting experience, I got to know a different culture, learn another language, and experience what life can be on another corner of the world. I also was able to get an Italian citizenship since my family is originally from there. That being said, those 3 months made me miss my home so much! It was one of those &quot;you never miss it &#39;til it&#39;s gone away&quot; type of situations. I missed the culture, the people, the food and the weather, not to mention the improved political situation after the elections gave me a bit of hope for the country. Ironically, I came back from Italy with an Italian citizenship but more Brazilian than ever 🇧🇷.</li>
<li>🚫📝 I <strong>did not</strong> write more on this blog, compared to last year. I only released 2 blog posts (about <a href="https://rsinfo.vercel.app/plausible-ethical-analytics">Plausible</a> and <a href="https://rsinfo.vercel.app/github-copilot-thoughts">GitHub Copilot</a>) and updated my <a href="https://rsinfo.vercel.app/blog-development-sveltekit">SvelteKit post</a> this year. I thought the big changes were gonna bring me inspiration, but what they did was really suck all my energy away 😮‍💨.</li>
<li>🚫🚀 I <strong>did not</strong> release or develop any personal projects this year either. I had ideas and even toyed with some proofs-of-concept, but nothing concrete came out of it. They were pushed back to 2023!</li>
</ul>
<h2 id="personal-changes">Personal Changes</h2>
<p>This was a really busy year personally. The first few months I was busy planning my wedding, then later planning my trip to Italy, while working multiple projects at the same time to be able to finance all that. And while handling the anxiety of those things, I was also struggling a bit to get used to seeing people again after quarantine, and re-learning to socialize was being mentally draining as well. This difficulty socializing made me pursue another big thing: my ASD diagnosis. It was confirmed and I think that helped me understand myself much better. Things are improving 😊.</p>
<p><img src="https://rsinfo.vercel.app/images/posts/2022-year-in-review/italy.png" alt="Picture taken from behind the Altar of the Fatherland in Rome, Italy. On the foreground, a statue of the first king of Italy mounted on a horse. In the background, the italian flag and the cityscape of Rome, with old, historical buildings below a blue sky. || full-bleed" title="Altar of the Fatherland in Rome, Italy. Photo by me."></p>
<h2 id="world-changes">World Changes</h2>
<p>Coming from two years of pandemic and big changes due to that, the world seems to be entering a new phase now, getting used to handling Covid (which is still a very real threat) and starting to see the more lasting effects it has caused on society, with the psychological effects of isolation and loss, and with the bursting of economic bubbles that were formed during the pandemic.</p>
<p>The big boom some industries had when the quarantine started (mostly related to e-commerce and digital work tools) seems to have winded down, which is causing a lot of companies to downsize or shut down completely, causing mass layoffs. This is awful, of course, but my hope is that this serves as a wake-up call to make companies start considering more sustainable models of business instead of just seeking exponential growth over everything else.</p>
<p>Something else that&#39;s been coming for years, but seem to have reached a new milestone in 2022: AI-generated content. Both art-focused AI (like this blog post&#39;s cover image), through services like Dall-E, Midjourney and Stable Diffusion, or text-based AIs like ChatGPT and GitHub Copilot have been the center of a lot of discussions regarding the ethics and potential of such technology. On one hand, artists, writers and programmers might be worried that the AIs will make them obsolete. Plus, the potentials of spreading AI-generated content as truth could have (even more) devastating effects to democracy. On the other hand, some of them can really have a positive effect on our daily jobs, as I wrote about in <a href="https://rsinfo.vercel.app/github-copilot-thoughts">the post where I shared my thoughts about GitHub Copilot</a>. I do believe their use will have to be regulated sooner rather than later, so we can minimize the downsides without halting their progress, which is really mindblowing.</p>
<h2 id="professional-life">Professional Life</h2>
<p>With such a busy and tiresome year, I haven&#39;t got to learning many <em>new</em> things, and instead focused on becoming better at what I already work with. I&#39;ve worked a lot with React and NextJS this year. I&#39;ve covered my opinions on both of them <a href="https://rsinfo.vercel.app/2021-year-in-review">last year</a>, and they haven&#39;t really changed.</p>
<p>WordPress is something I&#39;d worked a little bit with in the past, but now I&#39;ve started working more with it as well. It&#39;s definitely a different way of working compared to modern JS stacks, but it&#39;s kind of refreshing in a way. Plus, I believe seeing firsthand how this kind of stack works brings a new perspective and maybe even ways of improving how we build with the newer ones.</p>
<p>One of the things I get excited the most learning about is <a href="https://www.blueacornici.com/blog/5-major-elements-of-atomic-design/">Atomic Design</a> - not a tech stack, but instead an architectural concept. Seeing it being implemented in different kinds of projects make me really admire the pattern and I&#39;m hoping I can apply it to other projects - including this website - and writing about it soon.</p>
<h2 id="fun">Fun</h2>
<p>My favorite part of these &quot;Year In Review&quot; posts - the entertainment content I enjoyed the most in 2022!</p>
<h3 id="tv-and-movies">TV and Movies</h3>
<p>Not much new on this section, as I&#39;ve mostly rewatched stuff I liked this year (including <a href="https://rsinfo.vercel.app/2020-year-in-review#tv-and-movies">Mr. Robot</a> for the third time - still my favorite series!)</p>
<ul>
<li><strong>Superstore</strong> was the best sitcom I&#39;ve watched this year. I think it nails the comedy while also touching on important subjects, like fighting for workers rights and unionizing. Plus, I think it&#39;s the only series I&#39;ve watched that acknowledged the pandemic and added it to its plot really well.</li>
<li><strong>Better Call Saul</strong> was already mentioned here last year when I watched seasons 1-5, but this year I&#39;ve watched season 6, which was the last one. It was entrancing, exciting and bleak - exactly what you&#39;d expect from the Breaking Bad universe. The finale was a perfect ending not just to this particular series but to the whole Breaking Bad universe. I highly recommend watching it <strong>after</strong> Breaking Bad though, as it spoils some of that series, even though it&#39;s mostly a prequel.</li>
</ul>
<h3 id="games">Games</h3>
<ul>
<li><strong>Bloodborne</strong>... wow. I had never played a From Software game before, and it was such a journey. Hard, yes, but fair. I always knew what I did wrong when I died. I always wanted to try again and do a bit better every time. But the star in this game is the setting and atmosphere. It starts in a somber Victorian-era city, where you face some beastly humans and werewolves. Soon you&#39;re facing creatures that are a bit different but still fit in the same world. Eventually, though, the game descends into full-on Eldritch/Cosmic Horror and it&#39;s awesome. I&#39;ve never seen a game capture that vibe so well. Every new enemy or boss you encounter is accompanied by a <em>&quot;what the heck is this?!?&quot;</em> and fighting them is always a box of surprises. Best game I&#39;ve played in 2022 and one of the best I&#39;ve ever played.</li>
</ul>
<p><img src="https://rsinfo.vercel.app/images/posts/2022-year-in-review/bloodborne.jpeg" alt="Official artwork of Bloodborne. To the right, a person wearing black Victorian-era clothes, a gun and a meat cleaver is seen from the back. In the background, a dark, gothic city by night." title="Official artwork of Bloodborne"></p>
<ul>
<li><strong>Elden Ring</strong> was the game I was the most excited to play after playing Bloodborne, as it&#39;s made by the same company. I was not disappointed. It delivered great combat, exploration, soundtrack and lore, which combined into another one of the best games I&#39;ve ever played. I wrote <a href="https://rsinfo.vercel.app/reviews/elden-ring/">a more in-depth review of the game</a> where I talk about what I enjoyed the most.</li>
<li><strong>Red Dead Redemption 2</strong> is SO GOOD. You can play it many ways: as an old-west life simulator, a cowboy shootout action game, a hunting and fishing game, or even just explore and photograph the scenery. It has so much content, even after 50+ hours I still kept finding events and secrets totally unlike what I&#39;d seen before. You can get completely lost in this game without even progressing the story. But you really should progress the story, as it&#39;s one of the best written ones I&#39;ve ever experienced. The characters are the real focus here, as they&#39;re all masterfully written and you get really attached to them and care for what happens to them. I cried like a baby in the ending.</li>
<li><strong>The Last of Us Part II</strong> is a bleak, brutal sequel to what was already a pretty brutal game. The story is the focus once again, but the gameplay was vastly improved over the first game. They took a creative route when telling this game&#39;s story, making you experience it through two completely different points of view. This plays with your emotions, as the game&#39;s brutal nature may bring out strong emotions in you, just to invert those feelings completely by showing you the other side of the situation. I loved this game, but I&#39;m not sure I wanna play it again, because I feel like it takes a toll on your mind. Still, I recommend experiencing it at least once.</li>
<li><strong>Rocket League</strong> is, year after year, my favorite game to just <em>have fun</em>. The formula is just so good and it never gets old.</li>
</ul>
<h3 id="music">Music</h3>
<p>New category! I wanted to write a bit about music since it&#39;s really important in my life.</p>
<ul>
<li><strong>The Gods We Can Touch</strong> by <strong>AURORA</strong> is a fantastic album by a one-of-a-kind artist. It&#39;s a pop album, but dips a lot into many genres and sounds really fresh and unique. The lyrics are beautiful as always, plus I got to see a lot of these songs played live! Aurora is one of my favorite artists and this is her best album <em>yet</em>.</li>
<li><strong>IMPERA</strong> by <strong>Ghost</strong> is a monumental album from start to finish. It&#39;s incredible how Ghost is able to make each album sound like a completely different era, and coming from the disco-ish Prequelle, IMPERA is a punch in the face with golden era metal. A lot of it sounds like Ozzy&#39;s &quot;No More Tears&quot; era, with acoustic guitar riffs morphing into heavy guitar riffs. But it still sounds unmistakingly Ghost. Plus, it has a metal reggaeton song! That&#39;s awesome.</li>
<li><strong>Infinite Granite</strong> by <strong>Deafheaven</strong> was a lucky find. I knew a couple songs by Deafheaven and while I enjoyed them, the gutural vocals never really pleased me. In Infinite Granite, they were replaced by soft vocals, while keeping the hypnotic, multi-layered instrumentals that I fell in love with immediatelly. I still listen to it on repeat because it&#39;s just so pleasant to listen to.</li>
</ul>
<p><img src="https://rsinfo.vercel.app/images/posts/2022-year-in-review/infinite-granite.jpeg" alt="Album cover of the Infinite Granite album. It&#39;s a bunch of small blue particles grouping together to form some sort of a circle." title="Cover of Infinite Granite, by Deafheaven."></p>
<h2 id="what-to-expect-in-2023">What to Expect in 2023</h2>
<p>I am hoping for 2023 to be a <strong>less exciting</strong> year, honestly. With so many changes this year, I want next year to be a good, chill year to recover and build up on what my life is right now. Hopefully, that means more time and energy to build nice things, and consequently write more.</p>
<p>I&#39;m planning on refactoring the code structure on this website, adopting Atomic Design, and publishing that alongside a nice article explaining all about it. Plus, releasing at least one of the side projects that I&#39;ve built the proof-of-concept for this year.</p>
<p>Above all, I want 2023 to be <span>C O Z Y</span>. That&#39;s a good word.</p>
<h2 id="wrapping-up">Wrapping up</h2>
<p>Thank you for reading all of this! I hope you&#39;ve had a great 2022, but more than that, I wish you a very <em>cozy</em> 2023!</p>

          ]]></content:encoded>
          <media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://rsinfo.vercel.app/images/posts/2022-year-in-review/cover.jpg"/>
          <media:content xmlns:media="http://search.yahoo.com/mrss/" medium="image" url="https://rsinfo.vercel.app/images/posts/2022-year-in-review/cover.jpg"/>          
        </item>
      
        <item>
          <guid>https://rsinfo.vercel.app/github-copilot-thoughts</guid>
          <title>Thoughts on GitHub Copilot</title>
          <description>I was initially skeptical about it, but I've come to appreciate it more and more as I use it.</description>
          <link>https://rsinfo.vercel.app/github-copilot-thoughts</link>
          <pubDate>Mon, 05 Sep 2022 00:00:00 +0000</pubDate>
          
          <content:encoded><![CDATA[
            <div style="margin: 50px 0; font-style: italic;">
              If anything looks wrong, 
              <strong>
                <a href="https://rsinfo.vercel.app/github-copilot-thoughts">
                  read on the site!
                </a>
              </strong>
            </div>

            <p>I started using GitHub Copilot around May this year as part of its free beta, and my opinion on it has changed a bit during this time. I was initially skeptical about it, but I&#39;ve come to appreciate it more and more as I use it.</p>
<h2 id="what-it-is">What it is</h2>
<p>First off, let&#39;s see what Copilot has to say about itself:</p>
<p><img src="https://rsinfo.vercel.app/images/posts/github-copilot-thoughts/copilot-describing-itself.png" alt="Screenshot of GitHub Copilot describing itself: &#39;GitHub Copilot is a code completion tool that uses machine learning to suggest code snippets based on the context of your code. It&#39;s available as a VS Code extension, and it&#39;s free to use for now.&#39;" title="It got the idea right, however the pricing info is outdated: it&#39;s now $10/month."></p>
<p>So, yeah, it&#39;s a code completion tool. You can think of it as <a href="https://code.visualstudio.com/docs/editor/intellisense">Intellisense</a> on steroids, but really it&#39;s much more than that. It is much smarter and is capable of detecting your code style, the context of what you&#39;re writing, and even the intent of what you&#39;re trying to do. So, if you&#39;ve just created a form input for a phone number and start writing a function on a related file, you&#39;ll see it automatically suggest some phone number validation logic.</p>
<p>I think what surprises me the most on a daily basis is how it interacts with code comments. You see, I often write comments detailing the next steps my code should take. In the example below, I&#39;ve only written the comment, Copilot did the rest:</p>
<pre><code class="language-typescript">// Check if a task with same title already exists
// Throw error if yes
const checkDuplicate = (task: Task) =&gt; {
    const duplicate = tasks.find((t) =&gt; t.title === task.title);
    if (duplicate) {
        throw new Error(`Task with title ${task.title} already exists`);
    }
};
</code></pre>
<p>The opposite can also happen. Sometimes I write some complex functions and Copilot helps me make comments to explain what&#39;s going on. It&#39;s not perfect, but it&#39;s pretty good!</p>
<h2 id="what-it-isnt">What it isn&#39;t</h2>
<p>\\<span>Copilot is not something that's going to take away your job</span>. At least not soon. The reason is in its name itself: it is a Copilot, meant to be by your side while you&#39;re coding and help you out with busy work, not completely replace you. It&#39;s really not capable of doing that.</p>
<p>You&#39;re still responsible for the code it writes, and for the code you ship. Whatever code it suggests you&#39;ll still have to review, as it may contain flaws that are either obvious or really hidden.</p>
<p>It&#39;s also not a replacement for a good IDE. It&#39;s a tool that works on top of your IDE, and it&#39;s not going to replace it. It&#39;s not going to help you debug your code, or refactor it, or do anything that requires you to think. It&#39;s just a tool to help you write code faster, and perhaps save you some time Googling for the correct syntax.</p>
<p>I also found it kinda useless when writing HTML or CSS. It wouldn&#39;t suggest more than the absolute obvious and was more often than not wrong about what I intended to write, so it almost always got in the way. I only started enjoying it more after using it for more logic-heavy code.</p>
<h2 id="licensing-issues">Licensing issues</h2>
<p>The main controversy around GitHub Copilot is related to the licensing of the code used to train it. You see, Copilot is trained on open source code uploaded to GitHub, and a lot of that code is under the GPL license. This means that if any code under that license is used on your project, you&#39;re obligated to release your code under the GPL license as well. This is kind of a big deal, but GitHub&#39;s CEO has claimed that <a href="https://twitter.com/natfriedman/status/1409914420579344385">training machine learning systems on public data falls under &quot;fair use&quot;</a>.</p>
<p>I&#39;m not knowledgeable enough on the subject to have a well-formed opinion on this, but I&#39;m inclined to disagree with him. If a developer using Copilot is still responsible for the generated code, the GPL license should still apply. Plus, I&#39;m really fond of <a href="https://rsinfo.vercel.app/open-source-x-free-software">Free Software</a> and the more shared knowledge we have, the merrier.</p>
<p>Until a consensus is reached, GitHub has added the option to disable public code suggestions on <a href="https://github.com/settings/copilot">Copilot Settings</a>, so you can disable them if you&#39;re worried about licensing issues.</p>
<p><img src="https://rsinfo.vercel.app/images/posts/github-copilot-thoughts/copilot-settings.png" alt="Screenshot of a GitHub Copilot settings displaying the option to block suggestions from public code."></p>
<h2 id="is-it-worth-the-price">Is it worth the price?</h2>
<p>I started using Copilot on the free beta, and after it ended I decided to keep using it, even for $10/month. It all depends on how much time it saves you. After using it for a good while I figured out that the time it saves me every month makes Copilot pay for itself. It has a free trial, so you can try it out and see if it&#39;s the same for you.</p>
<p>You can check out all the details on the official <a href="https://github.com/features/copilot/">GitHub Copilot website</a>.</p>

          ]]></content:encoded>
          <media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://rsinfo.vercel.app/images/posts/github-copilot-thoughts/cover.jpg"/>
          <media:content xmlns:media="http://search.yahoo.com/mrss/" medium="image" url="https://rsinfo.vercel.app/images/posts/github-copilot-thoughts/cover.jpg"/>          
        </item>
      
        <item>
          <guid>https://rsinfo.vercel.app/review-elden-ring</guid>
          <title>Review: Elden Ring</title>
          <description>My thoughts on what probably is the biggest game release of 2022.</description>
          <link>https://rsinfo.vercel.app/review-elden-ring</link>
          <pubDate>Mon, 01 Aug 2022 00:00:00 +0000</pubDate>
          
          <content:encoded><![CDATA[
            <div style="margin: 50px 0; font-style: italic;">
              If anything looks wrong, 
              <strong>
                <a href="https://rsinfo.vercel.app/review-elden-ring">
                  read on the site!
                </a>
              </strong>
            </div>

            <blockquote>
<p>[!info]
TL;DR: It&#39;s incredible and worth all the praise it&#39;s got. Not perfect, but really close to it.</p>
</blockquote>
<p>Elden Ring was probably the most hyped up game of the past couple of years, and its release in February (2022) was met with a lot of media coverage and players raving about how incredible it was.</p>
<p>I wasn&#39;t hyped at all about the game, mainly because I had never played a From Software (the game&#39;s developer) game before. Dark Souls was a big hit when it came out, but I was never into difficult games, and I didn&#39;t have a console to play it on (I was one of the 6 people that owned a Wii U, but not a PlayStation or Xbox). However, with all that talk surrounding Elden Ring I couldn&#39;t just ignore its existence. The game was really expensive though, and I didn&#39;t feel like spending R$300 to play something I thought I wouldn&#39;t enjoy. So, I downloaded Bloodborne (free on PS Plus), another From Software game with good reviews, which I figured would give me a taste if I liked this kind of game or not.</p>
<p>I was completely amazed by that game, and it became one of my all-time favorites. After finishing that one and immediatelly tweeting about wanting a sequel, I had no choice but to play Elden Ring next.</p>
<h2 id="the-game">The Game</h2>
<p>A few minutes into the game and you&#39;re presented with its selling point: you open a door and you&#39;re now free to explore an entire world, full of mysteries and dangers. Right in front of you is a boss that <span>will totally destroy you</span> if you try to beat it, and it&#39;s an important lesson of what to expect in the game: you need to be prepared. You circle around that boss and make a note on the map to come back to it later. Then you proceed into a forest and find some soldiers that you can defeat. You&#39;re not sure why you&#39;re fighting them or why they wanna kill you, but it&#39;s fun, so you do it. Then you find an entire camp full of them, including one with a more menacing armor, a big shield and a spear. You try to face it and it kills you <i>once. Twice. Three times</i>. You get really close to beating it, your hands start sweating with anticipation, and you finally do it! Metaphorical tears of joy roll down your face and you feel really good about what you just accomplished. Then you realize that was just a regular enemy, that will respawn every time you rest. <b>There&#39;s so much more to uncover.</b></p>
<p>That&#39;s the main hook of all games in the &quot;Soulsborne&quot; series, and it works really well. It uses frustration to build up an extremely satisfying reward when you win. Elden Ring did not change that, instead it mixed that feeling with an open world that gives you more ways to cool down between tough fights, or multiple ways to get stronger to prepare. It took me over 30 hours to have my character strong enough to tackle that boss right after the first door of the game. That was like 1/3 of my play time, and it was probably the best part of it. Every discovery was something brand new, and many encounters provided a fair challenge.</p>
<p><img src="https://rsinfo.vercel.app/images/posts/review-elden-ring/tree-sentinel.jpg" alt="Elden Ring screenshot. In it, the player is fighting a huge knight in golden armor riding a horse, also in golden armor." title="The Tree Sentinel is likely the first boss you&#39;ll encounter, but not the first one you&#39;ll defeat."></p>
<p>However, I feel that the feeling of challenge was really uneven throughout the game. When both my character and I were not well prepared or strong enough, it felt more rewarding when I got a win. Later in the game, I was so overleveled for some bosses that I didn&#39;t get that feeling of adrenaline during a big fight, nor the big endorphine release when I defeated them. And that did not come from me grinding XP somewhere. I was just enjoying the game, exploring every nook and cranny I could find, and getting stronger as I did that.</p>
<p>To be fair, I do think making a game like this completely balanced is nigh impossible. Not only there are dozens of different builds you can make for your character, but also every player will have a different journey, ending up with more or less Runes (the currency you use to buy levels and improve your character) than others. So, on a technical level, I truly understand the complexity of balancing this and still think they did a good job overall. It just was a bit underwhelming on my specific case.</p>
<h2 id="the-story">The Story</h2>
<p>Elden Ring, just like other From Software games, has almost no story. It has a huge and rich lore, though. For most of the game, you simply have no idea what&#39;s going on. It&#39;s by hearing some cryptic dialogue, reading item descriptions, and observing the world around you that you can start to put together the puzzle surrounding the game. Or, you can watch some really good YouTube videos explaining the lore behind the game, which make you finally understand why things are the way they are.</p>
<p>I like this.</p>
<p>It has a bit of a more realistic approach to storytelling - your character is part of that world, and as such you&#39;d probably be acquainted to some of the more common stories and myths in there, and definitely not be aware at all of the secrets and twists of the royal family of demigods. Having to go out of your way to figure things out makes you more attached to the game in a way, and makes you care more. Old games used to do this for technical reasons, but there&#39;s definitely an appeal here. I do understand it&#39;s not very accessible though.</p>
<p><img src="https://rsinfo.vercel.app/images/posts/review-elden-ring/malenia-and-radahn.jpg" alt="Elden Ring art. A long-haired swordswoman seems hurt, holding her arm with one hand, and a katana on another. In front of her, a huge warrior with a red mane stands tall with arms crossed." title="The demigods have an interesting backstory and while you interact little with them, knowing that backstory makes their appearances much more meaningful."></p>
<p>The lore itself is great. It&#39;s a more common fantasy setting, with dragons, wizards, gods, but it feels unique by adding a lot of nuance to it, and making it centered on a family of very unique characters that you either befriend or fight during the game. These characters are well-written and have a lot of depth, and looking into how they got to be what they are now is a really cool way to spend time when you&#39;re not playing the game.</p>
<p>Had I not played this immediately after playing Bloodborne, I think I&#39;d have enjoyed it more. Bloodborne was just so unique and atmospherically perfect, this one didn&#39;t really get to the same level. But it&#39;s still one of the best game worlds I&#39;ve ever adventured in.</p>
<h2 id="the-world">The World</h2>
<p>The Lands Between (the name of the in-game world) is a beautiful place, and all of its areas tell a bit of the story surrounding everything. You have vast green areas, a huge lake surrounded by mist, a mountain around a volcano, icy peaks, a golden city, and an area that&#39;s almost literal hell and that will kill you so many times you&#39;ll kinda start to like it. Almost everything is fully explorable from the start of the game, though you might face some &quot;natural barriers&quot; in the form of enemies you&#39;re still not ready to face.</p>
<p><img src="https://rsinfo.vercel.app/images/posts/review-elden-ring/liurnia.jpg" alt="Screenshot of Elden Ring. It&#39;s taken from the top of a cliff, showing a beautiful landscape. To the left, many rocky mountains and a golden tree. To the center, a huge lake covered in mist, and a castle sitting on top of a cliff farther back. To the right, more rocky cliffs with trees and another golden tree."></p>
<p>\\<span>The world is fully realized, and there are rewards in every corner.</span> However, it&#39;s not the best part of the game.</p>
<p>In some parts of the world are places called Legacy Dungeons - they&#39;re areas that work just like the older games (like Dark Souls or Bloodborne) did: smaller, more linear areas, with great level design and that offer a more curated, if limited, experience. Those are still the best parts of the game, not its open world. I really hope they continue to be a thing in future games.</p>
<h2 id="the-bad">The Bad</h2>
<p>The sidequests, really. They&#39;re kinda bullshit. Not their content per se, but they rely so much on &quot;randomly coming across a character on a very random part of a gigantic open world&quot; that it&#39;s nearly impossible to complete one of them without following an online guide. Quest markers would make this better and still keep the same level of immersion.</p>
<h2 id="verdict">Verdict</h2>
<p>I think the best thing I can say about this game is that after I&#39;ve beat it (which took me 92 hours), I immediately started the game over again, to play with a different character. Even after so many hours, I was still wanting more. Though not my favorite game ever, it was still one of the best.</p>
<p>I hereby give this game a sparkling <span>10/10</span> score!</p>

          ]]></content:encoded>
          <media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://rsinfo.vercel.app/images/posts/review-elden-ring/cover.png"/>
          <media:content xmlns:media="http://search.yahoo.com/mrss/" medium="image" url="https://rsinfo.vercel.app/images/posts/review-elden-ring/cover.png"/>          
        </item>
      
        <item>
          <guid>https://rsinfo.vercel.app/plausible-ethical-analytics</guid>
          <title>Ethical Analytics are Plausible, at Last</title>
          <description>Web Analytics is such a morally ambiguous area that I’ve avoided it for years, but now I can finally do it with peace of mind.</description>
          <link>https://rsinfo.vercel.app/plausible-ethical-analytics</link>
          <pubDate>Tue, 01 Feb 2022 00:00:00 +0000</pubDate>
          
          <content:encoded><![CDATA[
            <div style="margin: 50px 0; font-style: italic;">
              If anything looks wrong, 
              <strong>
                <a href="https://rsinfo.vercel.app/plausible-ethical-analytics">
                  read on the site!
                </a>
              </strong>
            </div>

            <p>Analytics have become intrinsic to software development in the past decade. On the marketing side, analytics allow us to measure the success of marketing campaigns, optimize the wording, measure ad results, or simply keep track of the growth of the audience. On the development side, it allows to more easily detect points of failure, bad patterns or UX hiccups.</p>
<p>These benefits however, usually come at a price: <span>in-depth analytics tend to store way too much information about the user</span>, and the user is often unaware of how much is being collected. It&#39;s a decision the user doesn&#39;t really make; we make it for them. <em>(Yes, I know, legally the user often accepts cookies or terms of service... but the reality is that almost nobody reads or understands that.)</em></p>
<p>On platforms like Google Analytics, there is a lot of information we can see, however none of them personally identifies the user. That&#39;s good, right? Well, not really: Google can personally identify (and does through its Ads business) them, and by using Google Analytics or similar products on your site, you&#39;re feeding them your user&#39;s information for a really low price - otherwise, why would these analytics be free?</p>
<p>Luckily, there are ways to get most of the needed metrics without compromising anybody&#39;s privacy, and even get a better experience in the end.</p>
<h2 id="ethical-analytics">Ethical Analytics</h2>
<p>Recently increasing concerns about online privacy have sprouted a lot of ethical analytics services, that aim to collect only necessary, anonymous data. Services like <a href="https://matomo.org/">Matomo</a> and <a href="https://usefathom.com/">Fathom</a> provide an experience that is simple and to-the-point, and I&#39;ve heard nothing but praise about both services. For myself though, I&#39;ve picked <a href="https://plausible.io/">Plausible Analytics</a>, which I use on this website and in some of my side projects.</p>
<p>It&#39;s important to point out, though, that none of those are free. Since they don&#39;t collect personal data and don&#39;t monetize it, they must charge for their service. The prices are pretty low though, and unless it&#39;s a hobby project you have no intention of monetizing, that cost will be absorbed really quickly and the gains will make it worth it.</p>
<h3 id="plausible">Plausible</h3>
<p>Plausible is a small company from Europe that makes Plausible Analytics, a privacy-friendly alternative to Google Analytics. The reasons I&#39;ve picked Plausible instead of others are that:</p>
<ul>
<li>It&#39;s open source;</li>
<li>It can be self-hosted in case you already have your own server;</li>
<li>It&#39;s intuitive: a quick glance through the dashboard and you&#39;re already able to understand everything that&#39;s in there. <a href="https://plausible.io/fantinel.dev">Check out mine</a>;</li>
<li>It&#39;s sustainable: their business model allows them to grow organically and <a href="https://plausible.io/blog/bootstrapping-saas">the project is already profitable</a> without any kind of external funding (and <a href="https://twitter.com/PlausibleHQ/status/1282678251148763137">they have no plans of accepting it</a>);</li>
<li>They offer <a href="https://plausible.io/docs/proxy/introduction">ways of bypassing adblockers</a>;</li>
<li>It&#39;s simply a great product.</li>
</ul>
<p><img src="https://rsinfo.vercel.app/images/posts/plausible-ethical-analytics/dashboard.png" alt="Screenshot of the Plausible dashboard, showing number of visitors, top sources, top pages, visitors by city, and device information." title="Clicking on some data blocks allow you to filter data - so you can still understand how your users behave differently depending on a number of factors."></p>
<h4 id="custom-goals">Custom Goals</h4>
<p>The data that Plausible collects by default should be enough for most use cases. However, there is still some information that is not gathered that you might want to have. For cases like that, Plausible offers the <a href="https://plausible.io/docs/custom-event-goals">Custom Event Goals API</a>.</p>
<p>With a simple function call, you can send data to the Plausible API and track some behaviors or extra information. For example, if you want to track the percentage of your users that click on &quot;Sign up&quot;, you can fire a custom event for that. These are also filterable in the dashboard, which means you can compare where most of the users that sign up come from.</p>
<p>In my case, I wanted to know the percentage of users that use light/dark mode in their browser or system. There is <a href="https://github.com/plausible/analytics/discussions/622">an open Feature Request to add this functionality</a> to Plausible that has received some interest, but while that isn&#39;t implemented, I built my own detection using the Custom Events API:</p>
<pre><code class="language-javascript">// Use Plausible to track the % of people that have a dark/light mode preference
if (plausible) {
    if (window.matchMedia &amp;&amp; window.matchMedia(&#39;(prefers-color-scheme: dark)&#39;).matches) {
        plausible(&#39;Dark Mode Enabled&#39;);
    } else if (window.matchMedia &amp;&amp; window.matchMedia(&#39;(prefers-color-scheme: light)&#39;).matches) {
        plausible(&#39;Light Mode Enabled&#39;);
    } else {
        plausible(&#39;No Dark/Light Preference&#39;);
    }
}
</code></pre>
<p><strong>Note:</strong> <em>tracking Custom Events without user interaction like this breaks the &quot;Bounce Rate&quot; metric. By firing an event, Plausible interprets that the user has interacted with your site, and therefore the Bounce Rate goes to zero. If the Bounce Rate metric is important to you, this might not be a good idea.</em></p>
<h2 id="wrapping-up">Wrapping Up</h2>
<p>I apologize if this post felt like an ad. It is not. Web Analytics is such a morally ambiguous area that I&#39;ve avoided it for years, and now I can finally grab some metrics with a peace of mind. Regardless of what service you choose and prefer, having privacy-friendly alternatives is good for everyone. With Plausible being one of my favorite pieces of software at the moment, I felt it was right to write a bit about it and spread the word.</p>
<p>Thanks for reading!</p>

          ]]></content:encoded>
          <media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://rsinfo.vercel.app/images/posts/plausible-ethical-analytics/cover.jpg"/>
          <media:content xmlns:media="http://search.yahoo.com/mrss/" medium="image" url="https://rsinfo.vercel.app/images/posts/plausible-ethical-analytics/cover.jpg"/>          
        </item>
      
        <item>
          <guid>https://rsinfo.vercel.app/2021-year-in-review</guid>
          <title>2021 In Review</title>
          <description>Another year, another yearly review post. 2021 felt like pretty much 2020 part II for a lot of people, me included.</description>
          <link>https://rsinfo.vercel.app/2021-year-in-review</link>
          <pubDate>Thu, 09 Dec 2021 00:00:00 +0000</pubDate>
          
          <content:encoded><![CDATA[
            <div style="margin: 50px 0; font-style: italic;">
              If anything looks wrong, 
              <strong>
                <a href="https://rsinfo.vercel.app/2021-year-in-review">
                  read on the site!
                </a>
              </strong>
            </div>

            <p>Another year, another yearly review post. 2021 felt like pretty much 2020 part II for a lot of people, me included. The ongoing pandemic still affected our lives, and even though most people in my country are now vaccinated (including me), the danger still exists and preventive measures are still necessary. But it&#39;s nice to be able to start doing things and going places we haven&#39;t been able to for a while. I personally think this situation is still going to drag on for a while, but we&#39;ll adapt to it with time.</p>
<h2 id="mental-health">Mental Health</h2>
<p><a href="https://rsinfo.vercel.app/2020-year-in-review">Last year</a>, I wrote a bit about doomscrolling, and how it started affecting me until I decided to avoid this behavior. I tried to keep avoiding it this year, and I think I succeeded. I&#39;m not blind to what&#39;s going on - I still know <span>the world is a dumpster fire</span> at the moment and in many ways it was even worse than 2020 - but I think I was successful in not dwelling on the bad news and the daily absurdities going on.</p>
<p>That doesn&#39;t mean my mental health didn&#39;t take a hit though. The year started with the loss of a person I held dear - a victim of the inexcusable vaccination delays and genocidal actions of our leaders - and I felt like I lost a bit of control over my work-life-balance for a portion of the year.</p>
<p>This year I also started therapy though, which I feel is a good way to deal with the growing anxiety from the past few years. I&#39;ve been able to know more about myself and how my brain works, so I can focus on what I found out to improve my life, one day at a time.</p>
<h2 id="work-life">Work Life</h2>
<p>Early this year I changed jobs, and started working as a contractor. This has given me more freedom to make my own hours and allowed me to work with a more diverse set of people. It took me a while to use this freedom the right way, though. For a few months I felt like my work-life balance was off, and I felt like my energy was being drained fast. Luckily I was able to notice the early signs of a burnout and took a step back to avoid it. I am now working on my 2nd project as a contractor and I feel that getting the work hours under control allowed me to do my work better, since my mind gets the time to rest.</p>
<h2 id="learning-and-comparing">Learning and Comparing</h2>
<p>Most of the learning I did this year was on my day job, and not personal projects. Last year, I worked a lot with Angular and Vue 2. This year, I worked with Vue 3, React and PHP (😩), and on my personal time I started to practice my Svelte skills. That&#39;s a lot of frameworks!</p>
<p>Although every project is different, working with components makes you solve similar problems all the time. And after having worked with basically all mainstream frameworks for a bit, I feel like I can see pros and cons to each of them:</p>
<h3 id="angular">Angular</h3>
<ul>
<li><strong>Pros:</strong> it&#39;s very opinionated, which means there are always recommended ways of doing something. This makes the code consistent, and using TypeScript by default makes it much easier to maintain big projects. I like the template syntax and the separation between HTML, CSS and TS. I also can definitely see why it&#39;s a choice in many enterprise environments: the majority of Angular projects I&#39;ve seen have similar structure, which makes devs productive really quickly after being hired.</li>
<li><strong>Cons:</strong> it&#39;s very opinionated, which means it&#39;s not as flexible as other options. The focus on clear separation of concerns and TypeScript can also be a burden for smaller apps. Sometimes you want to make a quick prototype or just build something simpler, and it&#39;s easy to find Angular overkill.</li>
</ul>
<h3 id="vue">Vue</h3>
<ul>
<li><strong>Pros:</strong> I really like the premise of Vue being &quot;incrementally adoptable&quot;. This makes Vue really simple on the surface and hides many of its complexities. The template syntax is similar to Angular and it&#39;s easy to keep concerns separated if you want to.</li>
<li><strong>Cons:</strong> In my personal experience I felt like the Composition API, introduced in Vue 3, goes against my favorite things in Vue previously. Instead of being an extension to HTML/JS, it makes you completely rethink how to build the components, and I feel like it makes things more complicated than they should be. Also, the ecosystem around it (plugins, components, etc) took a big hit with the transition from v2 to v3, because it had many breaking changes.</li>
</ul>
<h3 id="react">React</h3>
<p>My experience with React has not been as extensive as the other ones here, so I think I&#39;m still not past the point of &quot;initial impressions&quot;. Still, here are my thoughts:</p>
<ul>
<li><strong>Pros:</strong> Super flexible, and with a ginormous ecosystem to back it up. You can write a React app in so many ways and there&#39;s always an open-source plugin or component for what you want to do. The existence of NextJS makes using React a better experience.</li>
<li><strong>Cons:</strong> Ok, I really don&#39;t like JSX. I usually like to keep concerns separated and using JS to build the HTML like this is not my cup of tea. I find it hard to understand at a glance, and feel like it overrides the default web stack too much. Unlike the other frameworks, when I use React I feel like I&#39;m developing a React app instead of a web app. Also, in contrast to Angular, the flexibility of React makes it so that React projects can be so different from one another you&#39;d have a difficult time adapting, even though they use the same framework (this is mitigated by meta-frameworks like NextJS, which are very opinionated, thankfully).</li>
</ul>
<h3 id="svelte">Svelte</h3>
<p>I have a clear favorite here, but I feel that Svelte hits the sweet spot in many ways.</p>
<ul>
<li><strong>Pros:</strong> I like the template syntax (not as clean as Vue&#39;s or Angular&#39;s, but similar enough), the clear separation of concerns, and how it likes to stay out of your way. Most of all though, I love how Svelte makes me just feel like I&#39;m building a &quot;vanilla&quot; web page, but with added goodies. <span>It extends the web instead of replacing it.</span></li>
<li>The fact that it is a compiler frees it from the need for a Virtual DOM, which then makes the code you need to write much simpler. No need for <em>useState</em>, <em>useEffect</em>, or keeping track of two-way binding to maintain state between components - you just have to set the variables and Svelte does the rest. I just think about my logic, not about how the framework works.</li>
<li>Its official meta-framework, SvelteKit, also has great defaults. It works by using native HTML tags instead of trying to emulate them. Instead of a <code>&lt;Link&gt;</code>, just use <code>&lt;a&gt;</code>. Instead of using JS to post data, just use a <code>&lt;form&gt;</code>. This makes the app leaner, more accessible, and work with JS disabled by default.</li>
<li><strong>Cons:</strong> Svelte is relatively new, and therefore its ecosystem is still lacking. I&#39;ve had trouble properly integrating a SvelteKit project with Storybook or Jest, for example, since Kit is still in Beta. There are also many components that don&#39;t have a Svelte version yet, and while some of them have a &quot;Vanilla JS&quot; option that usually works, it&#39;s still not as seamless as it could be.</li>
</ul>
<h2 id="personal-projects">Personal Projects</h2>
<p>I didn&#39;t work on many personal projects this year, as I was already learning a lot on my day job. I did, however, <span>completely rewrite my website!</span></p>
<p>I really liked the previous one, but I wanted to change some things about it and use something more flexible than Jekyll. So I completely redesigned it using Figma - while retaining some design elements from before - and rewrote it with SvelteKit. <a href="https://fantinel.dev/blog-development-sveltekit/">I wrote a blog post talking more about the experience</a>, which also became my most-read post of all time. Nice!</p>
<p>Speaking of blog posts, <span>I doubled the amount of posts published compared to last year!</span> Which means I wrote.... <strong>4</strong> (excluding this one). I wanted to write more, but compared to the 2 posts from last year, it&#39;s still an improvement, <em>right</em>?</p>
<h2 id="fun">Fun</h2>
<p>Not everything is code and gloom - I also do some fun things every once in a while.</p>
<h3 id="tv-and-movies">TV and Movies</h3>
<ul>
<li><strong>Ted Lasso</strong> is the TV equivalent of a hug. I’ve never seen a show that can balance comedy, wholesomeness and an enthralling story and characters so well. It touches on delicate subjects in a way that still makes you feel good, and yet is capable of sending the intended message. Honestly can’t find anything I dislike about it.</li>
<li><strong>Better Call Saul</strong> was surprisingly good. I initially dismissed it as being just a spin-off of a popular show, but it slowly evolved into a tightly-woven drama that keeps me at the edge of my seat. The stakes are lower here than they are in Breaking Bad, but I feel like I care more about the characters on this one.</li>
</ul>
<h3 id="games">Games</h3>
<ul>
<li><strong>The Last of Us</strong> was surprisingly surprising for me. I am 8 years late to the party here, but I didn&#39;t have a PlayStation since the PS1, and not only I hadn&#39;t played this game, I never felt like doing so. I usually favor creative gameplay instead of a complex story, but finally gave it a go this year. Wow. It was an amazing experience from start to finish, though I admit it felt more like a more immersive movie than a game. That being said, I don&#39;t think any movie can match the immersion that a game with a good story can provide.</li>
<li><strong>No Man’s Sky</strong> is a mix of exploration and existential crisis. There are a lot of things to do (though not all of them have much depth), but the main gameplay loop of exploring planets and seamlessly traversing between them is addictive. Plus, the main story was surprisingly good, with a lot of amazing quotes from the Travellers in that universe. A bit of existential crisis was the icing on the cake.</li>
</ul>
<p><img src="https://rsinfo.vercel.app/images/posts/2021-year-in-review/no-mans-sky.jpg" alt="Screenshot of No Man&#39;s Sky, showing a robotic humanoid holding a tablet and looking directly at the camera. Below, a textbox says: &quot;Existence is beautiful, if you let it be. Life is not a question. There does not need to be an answer."></p>
<ul>
<li><strong>Metroid Dread</strong> was a lot of fun! I never liked games of this genre (Metroidvania) until I played Hollow Knight, last year. I felt like finally giving Metroid a chance since it was the first main entry in 19 years and the reviews were stellar. I was not disappointed. I feel like it doesn&#39;t match Hollow Knight in its worldbuilding and ambientation, but the gameplay in Metroid Dread felt much more fluid, making almost everything in it a joy.</li>
<li><strong>Dungeons &amp; Dragons</strong> has continued to be one of the highlights of my weeks. My party still played online this year, but it was a lot of fun. We finally finished the Curse of Strahd campaign after 502 days. The finale was so epic we decided to have it illustrated by the amazing <a href="https://www.gholz.art/">Guilherme Holz</a>.</li>
</ul>
<p><img src="https://rsinfo.vercel.app/images/posts/2021-year-in-review/dnd.png" alt="Illustration of a party of RPG heroes. From left to right: an blonde woman with angelical wings, readying a bow with an arrow made of light; a bald man wearing leather armor and holding a spectral spear, thrusting it into a vampire with red eyes; a tall, blonde woman with heavy armor, a shield and a sword made of light; and an old halfling holding a wooden staff and a beer mug." title="It was kind of poetic to have a bolt of holy light (in the form of a spear) be the end of one who brought so much darkness to the land. From left to right: Ylanis, Alesteir (me), Aliana and Garreth. The guy getting stabbed is Strahd, the big bad evil guy."></p>
<h2 id="what-to-expect-in-2022">What to Expect in 2022</h2>
<p>First of all, <span>I'm getting married! 💍</span> The love of my life and I are finally making it official.</p>
<p>Later in the year I&#39;m also temporarily moving to Italy for a few months with my (soon-to-be) wife. It&#39;s going to be some sort of test drive - we&#39;ll return to Brazil before the year ends and then decide if living abroad is something we want or not.</p>
<p>As for this blog, I hope to again write more than I did this year. I have a few ideas in the oven, but have been struggling to write them down. Hopefully the big life changes are the inspiration I need.</p>
<p>I also have some ideas for some personal projects that may or may not see the light of day. Let&#39;s see how it goes.</p>
<h2 id="wrapping-up">Wrapping Up</h2>
<p>2021 was overall a weird year, but I feel 2022 is going to have more going on. I wish you happy holidays and that you have a memorable 2022. See you then!</p>

          ]]></content:encoded>
          <media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://rsinfo.vercel.app/images/posts/2021-year-in-review/cover.jpg"/>
          <media:content xmlns:media="http://search.yahoo.com/mrss/" medium="image" url="https://rsinfo.vercel.app/images/posts/2021-year-in-review/cover.jpg"/>          
        </item>
      
        <item>
          <guid>https://rsinfo.vercel.app/blog-development-sveltekit</guid>
          <title>How I built a blog with Svelte and SvelteKit</title>
          <description>An overview of the experience I've had using these amazing projects.</description>
          <link>https://rsinfo.vercel.app/blog-development-sveltekit</link>
          <pubDate>Wed, 08 Sep 2021 00:00:00 +0000</pubDate>
          
          <content:encoded><![CDATA[
            <div style="margin: 50px 0; font-style: italic;">
              If anything looks wrong, 
              <strong>
                <a href="https://rsinfo.vercel.app/blog-development-sveltekit">
                  read on the site!
                </a>
              </strong>
            </div>

            <p>I&#39;ve recently re-launched my personal website and blog, that&#39;s now reached its 3rd version. There was nothing wrong with the previous one, but I wanted to both give it a small visual refresh and learn something new. So, after a month or so of working on it on my free time, <span>voilà</span>, you&#39;re seeing it right now!</p>
<blockquote>
<p>[!info]
While the code for this website is open-source, it has a lot of content that&#39;s very specific to myself. So, if you want to use it as a template to get your own website started, I&#39;ve created a <strong>public template that you can use as a starting point</strong>!</p>
</blockquote>
<p><a href="https://github.com/matfantinel/sveltekit-static-blog-template" title="button || color=secondary">Check out the starting template here!</a></p>
<h2 id="about-svelte-and-sveltekit">About Svelte and SvelteKit</h2>
<p><a href="https://svelte.dev/">Svelte</a> is a new cool kid on the JS block - it was launched in 2016, but it really started getting traction when its 3.0 version was launched in 2019. It is a competitor to the big JS frameworks - React, Vue, Angular - but, instead of simply being an alternative way of doing things, it differentiates itself on a fundamental level: <span>it is a compiler, not a framework.</span></p>
<p>This means that it does its job at build time, not at runtime. While other frameworks (React, for example) need JavaScript code that runs on the client in order for your components to work properly, Svelte does not, because it interprets your code on build time, and only ships exactly what it needs to run. This means websites made with Svelte can be much smaller in size and faster because it has less code to run.</p>
<p><a href="https://kit.svelte.dev/">SvelteKit</a> is a framework built on top of that. It is an opinionated set of rules that helps you get a Svelte app built pretty quickly. You can compare it to NextJS (for React) or Nuxt (for Vue). It has great defaults and encourages good practices, like server-side rendering, for example. At the time of building this website, SvelteKit was still in Beta. However, progress is steady and its API seems to be already stable, so it&#39;s unlikely there will be any breaking changes before 1.0 arrives.</p>
<p>Using both of the above allowed my website to have two important characteristics:</p>
<ul>
<li>Every single page is rendered at build time (server-side rendering). This means that as long as the HTML and CSS files are downloaded, it will look as it was meant to be;</li>
<li>JavaScript is not needed. Try disabling JavaScript on your browser. You&#39;ll still be able to read this blog post and everything will look the same.</li>
</ul>
<h2 id="progressive-enhancement">Progressive Enhancement</h2>
<p>One of the concepts that really caught my eye with Svelte is the idea of Progressive Enhancement: <span>making sure your app runs for everyone, and making it progressively more featureful if the user's device supports it</span>. My website is a pretty simple project, but still there are instances of this:</p>
<p>If there&#39;s no JavaScript, the website uses the browser&#39;s native navigation API. Which means you can navigate between pages normally without any client-side code. <em>However</em>, if JavaScript is available, a client-side router will be used to make the transition between pages smoother and faster. This means that even if the user&#39;s device doesn&#39;t support JS for any reason, the site will still be completely functional.</p>
<blockquote>
<p>[!info]
We tend to think of JavaScript being disabled as a user choice, but that is usually not the case. Think of someone using their phone on a weak 3G connection that fails to load the .js files, or someone in the subway that lost signal while loading the page. It happens often and being able to show your content even in these conditions is a great way of not losing a visitor.</p>
</blockquote>
<p>And you know what I had to do to support this? <em>Nothing</em>. Just using <code>&lt;a&gt;</code> elements is enough, as SvelteKit will intercept those if needed (JS enabled), or simply leave it to the browser otherwise.</p>
<h2 id="design">Design</h2>
<p>I&#39;m not a designer, but I like to pretend I am. So, instead of designing-as-I-go when developing the website, I decided to fully design it on <a href="https://www.figma.com/">Figma</a> before starting development. I figured that using it to design stuff is the best way to learn the platform, and I really finished this design much better at Figma than I was before. Auto-layout is fantastic since it works so much like CSS Flexbox, so I was able to approach it with a similar thought-process as I have when developing stuff.</p>
<p>The design itself was something I came up with, and it&#39;s an amalgamation of ideas and inspirations that were stored in my head. When building it, I wasn&#39;t entirely sure where the inspiration came from, but now it is apparent to me that most of it comes from some websites I love: <a href="https://www.joshwcomeau.com/">Josh Comeau&#39;s</a> and <a href="https://georgefrancis.dev/">George Francis&#39;</a>.</p>
<p>After the design was complete, I finally began developing it. Since there are some things that you can only find out while developing it and giving it more attention, I made some small tweaks to the design while implementing it. Still, the final result was <em>really</em> similar to the initial design. I count that as a success!</p>
<p><img src="https://rsinfo.vercel.app/images/posts/blog-development-sveltekit/design-vs-result.png" alt="Screenshot of the design and end result of the website. Both look really similar!" title="The design (left) and the result (right)"></p>
<h2 id="routing">Routing</h2>
<blockquote>
<p>[!info]
Initially, SvelteKit used a <em>file</em>-based routing, as opposed to the current <em>folder</em>-based routing. This article has been updated to reflect those changes. If you were familiar with the previous system, <a href="https://github.com/sveltejs/kit/discussions/5774#discussioncomment-3294867">this comment by the SvelteKit team</a> might help you understand the changes.</p>
</blockquote>
<p>SvelteKit uses a folder-based routing system. This means that your routes are dictated by the folder structure inside <code>routes</code> in your project. Every route <strong>must</strong> have a folder, except for the root (&#39;/&#39;).</p>
<p>Inside each folder, you can add files that build up your page. Typically, in other frameworks, you would have a <code>index.{html/js/jsx}</code> file where everything the page needed would be loaded from. In SvelteKit, you can have multiple files, each representing a different part of the page.</p>
<p>The only required file is <code>+page.svelte</code>. This is where you can add your markup, components, styles and logic. However, it&#39;s likely that your page might need to load some data to be displayed. This can be done on another file, <code>+page.js</code>, in the same folder. There, you can add a <code>load</code> function where you&#39;ll have access to query params and other things and be able to load all the data your page needs.</p>
<p>The cool thing about that is that SvelteKit will use the content of the <code>+page.js</code> file <strong>both server-side and client-side</strong>, depending on the situation. However, if the data you need can only be loaded on the server (like for example querying a database or using a secret key), you can name it <code>+page.server.js</code> instead. Both would do the same thing, however <span>the naming difference makes it much easier on a quick glance to identify what runs where.</span></p>
<p>So, an example of what the basic file structure for my website would look like:</p>
<pre><code>└── routes
    ├── +layout.svelte
    ├── +page.svelte # / (root page)
    ├── resume
        └── +page.svelte # /resume
    ├── blog
        ├── +page.svelte # /blog
        └── +page.js # Loads data to show on /blog
    ├── blog-post-name
        └── +page.md # Blog post content (Markdown file)
</code></pre>
<p>Having multiple files in a folder might look a bit cumbersome at first, but it makes their purpose <strong>much</strong> clearer. The great reasoning behind this pattern is that it gives you a single way of doing routing instead of multiple, which makes things more standardized and easier to understand later on. Remember, SvelteKit is opinionated on purpose, and I think folder-based routing is more readable and I&#39;d say more flexible than other file-based routing solutions, although it is a bit more verbose.</p>
<p>The <code>+layout.svelte</code> file is a base layout for all the pages inside the route. Which means that I can have shared code for all pages in there. See the example below, where I added the header and footer components to the layout, and load the content of the route itself in the <code>&lt;slot&gt;</code> element:</p>
<pre><code class="language-svelte">~filename +layout.svelte
&lt;Header /&gt;

&lt;main&gt;
    &lt;slot /&gt;
&lt;/main&gt;

&lt;Footer /&gt;
</code></pre>
<h3 id="layout-groups">Layout Groups</h3>
<p>Having a <code>+layout.svelte</code> file is a great way to avoid re-writing the same base layout multiple times. However, sometimes you might want to have a different layout for a group of pages. For example, I wanted the blog posts to have some extra elements that the rest of the pages didn&#39;t have, like a title and related posts at the bottom.</p>
<p>For that, I used a <strong><a href="https://kit.svelte.dev/docs/advanced-routing#advanced-layouts-group">layout group</a></strong>, defining that the post page shouldn&#39;t use the main layout, but instead have its own.</p>
<p>To create a layout group, I&#39;ve created a folder inside of <code>routes</code> with the name of the new layout <code>blog-article</code>, wrapped in parentheses to indicate it uses its own layout. The routes directory ended up like this:</p>
<pre><code>└── routes
    ├── +layout.svelte
    ├── +page.svelte # / (root page)
    ├── resume
        └── +page.svelte # /resume
    ├── blog
        ├── +page.svelte # /blog
        └── +page.js # Loads data to show on /blog
    ├── (blog-article)
        ├── +layout.svelte # This layout applies only to this folder
        ├── +layout.js # Loads data to show on the layout file
        ├── [slug]
            ├── +page.md # Blog post content (Markdown file)
</code></pre>
<p>Keep in mind that, just like pages, layout files can also have their data-loading counterparts: <code>+layout.js</code> and <code>+layout.server.js</code>.</p>
<h2 id="the-blog">The blog</h2>
<p>The main challenge for me was in processing Markdown (.md) files of the blog posts into actual Svelte code. Unlike Jekyll, which I was using previously for this blog, SvelteKit doesn&#39;t have anything built-in for this (yet) and online resources are a bit scarce (which is normal, since it&#39;s still in beta).</p>
<p>I had three requisites for this:</p>
<ul>
<li>I wanted to write blog posts in Markdown, because of its ease, and also so I wouldn&#39;t have to rewrite all the existing posts;</li>
<li>I wanted to be able to use Svelte components inside the blog posts as well, for more interactive elements;</li>
<li>It has to be rendered on build time so the blog can be deployed as a static site;</li>
</ul>
<p>I had heard about something similar to what I wanted, called MDX. It allows everything I wanted, however, it was React-based and I couldn&#39;t use it. Luckily, I found out about <a href="https://mdsvex.com/">MDsveX</a>, a project with the same goal as MDX, but for Svelte!</p>
<p>After setting it up, having the Markdown content rendered was very straightforward. However, I need to use some of the post&#39;s data to load stuff into the <code>+layout.svelte</code> file, like the title, image, date and related posts. Plus, I wanted to be able to get a list of all blog posts and be able to filter them, to show on the &quot;Recent Posts&quot; cards on the home page, as well as the blog page itself.</p>
<h3 id="extracting-post-data">Extracting post data</h3>
<p>I found out when searching that we can import all the .md files as modules, and process them via JS, since this code will run on the server. I ended up creating a <code>posts.js</code> file to centralize this logic, and did the following:</p>
<pre><code class="language-javascript">~filename posts.js
// Import the markdown files for each post
const imports = import.meta.globEager(&#39;./posts/*.md&#39;);

const posts = [];
for (const path in imports) {
    const post = imports[path];
    if (post) {
        // For each of them, MDsveX will do the heavy lifting. The &quot;metadata&quot;
        // is automatically recovered from the Frontmatter
        posts.push({
            ...post.metadata
        });
    }
}

// Filter the post and order them by published date
const filteredPosts = posts
    .filter((post) =&gt; !post.hidden)
    .sort((a, b) =&gt;
        new Date(a.date).getTime() &gt; new Date(b.date).getTime()
            ? -1
            : new Date(a.date).getTime() &lt; new Date(b.date).getTime()
            ? 1
            : 0
    );

// Expose this info to other files
export default filteredPosts;
</code></pre>
<p>With that data being exported from that file, I can reuse it in the places I need:</p>
<h4 id="blog-post-page">Blog post page</h4>
<p>On the <code>routes/(blog-article)/+layout.js</code> file, I can now import the posts and look for the one I should display (by comparing slugs). After that, I&#39;ll pass the data I need back to the <code>+layout.svelte</code> file.</p>
<p>On the <code>routes/[slug]/+page.svelte</code> file, I can now import the posts and look for the one I should display (by comparing slugs). After that, I&#39;ll get its module and use the special <code>&lt;svelte:component&gt;</code> (<a href="https://svelte.dev/docs#svelte_component">see docs</a>) tag to use it inside the page.</p>
<pre><code class="language-javascript">~filename (blog-article)/+layout.js
import { filteredPosts } from &#39;$lib/data/posts&#39;;

export async function load({ url }: { url: { pathname: string } }) {
    const { pathname } = url;
    const slug = pathname.replace(&#39;/&#39;, &#39;&#39;);
    const post = filteredPosts.find((post) =&gt; post.slug === slug);

    return {
        post
    };
}
</code></pre>
<pre><code class="language-svelte">~filename (blog-article)/+layout.svelte
&lt;script&gt;
    // Declare the data variable that comes from the server
    // And extract its post property
    export let data;
    $: ({ post } = data);
&lt;/script&gt;

&lt;!-- Here we can use the post data we need --&gt;
&lt;h1&gt;{post.title}&lt;/h1&gt;
</code></pre>
<h4 id="listing-all-posts">Listing all posts</h4>
<p>Now the post page is done, we need a way to display all the posts on the main blog page. We already have them sorted and filtered in the <code>posts.js</code> file, so all I have to do is fetch that data and iterate on it to display them all.</p>
<p>Since the posts data comes from the server, it needs to run there. I&#39;ll use a <code>blog/+page.server.js</code> file to fetch that data and send it to the client-side page.</p>
<pre><code class="language-javascript">~filename blog/+page.server.js
import { error } from &#39;@sveltejs/kit&#39;;
import posts from &#39;$lib/posts&#39;;

export async function load() {
    const result = Object.keys(posts).map((index) =&gt; {
        const { slug, title, date, excerpt, tags, readingTime } = posts[index];
        return {
            slug,
            title,
            date,
            excerpt,
            tags,
            readingTime
        };
    });

    if (result) {
        return {
            posts: result
        };
    }

    throw error(500, `Could not load blog posts`);
}
</code></pre>
<p>And, on the page itself:</p>
<pre><code class="language-svelte">~filename blog/+page.svelte
&lt;script&gt;
    export let data;
    let { posts } = data;
&lt;/script&gt;

{#each posts as post}
    &lt;BlogPostCard {post} /&gt;
{/each}
</code></pre>
<h3 id="rss">RSS</h3>
<p>Something that SvelteKit currently does not provide a solution for is a RSS feed. Previously, mine was built automatically by Jekyll and I never had to do anything to get it working. While this wasn&#39;t the case right now, I&#39;m sure once SvelteKit is stable and mature, solutions for this will be available so no manual work has to be done.</p>
<p>I made mine by taking advantage of <a href="https://kit.svelte.dev/docs/routing#server">SvelteKit&#39;s endpoints</a> by creating a <code>+server.js</code> file, and serving a XML file that is generated at build time. I import the filtered posts from the <code>posts.js</code> file I created earlier, and use the metadata to build the content of the RSS file. You can check out <a href="https://github.com/matfantinel/sveltekit-static-blog-template/blob/main/src/routes/rss.xml/%2Bserver.ts">the source code</a> for implementation details.</p>
<h3 id="sitemap">Sitemap</h3>
<p>Another thing that&#39;s still not built-in to SvelteKit is the sitemap. It&#39;s great for SEO, especially for newer websites, so I researched a good way of adding one. Luckily, someone already built a tool to generate them automatically, and there is already a discussion to build it into SvelteKit directly. Check out <a href="https://github.com/bartholomej/svelte-sitemap">svelte-sitemap</a> for generating your own.</p>
<h2 id="wrapping-up">Wrapping Up</h2>
<p>My first experience with Svelte and SvelteKit was, overall, fantastic. It simplifies many parts of development and having server-side-rendering as a default option really drives forward their purpose of simplifying web both for users and developers.</p>
<p>Though I definitely did not use all of Svelte&#39;s strengths on this project, since it doesn&#39;t need dynamic data and an application state, I&#39;ll be working with that soon enough. Its ecosystem is not as big as its competitors&#39;, since Svelte is still small compared to them, but they&#39;re doing something right with their new approach, as Svelte is the most loved web framework according to <a href="https://insights.stackoverflow.com/survey/2021#section-most-loved-dreaded-and-wanted-web-frameworks">2021&#39;s StackOverflow survey</a>. Not to mention that Svelte itself doesn&#39;t try to reinvent the wheel, and therefore is compatible with almost everything JavaScript.</p>
<p>The small issues I&#39;ve had while building this will definitely be gone soon, as they were caused by SvelteKit not being on a stable version yet. I&#39;m excited to see how much the ecosystem grows the next year; I&#39;ll definitely be keeping an eye on it!</p>
<p>Don&#39;t forget all the code for this website and blog are open source, feel free to use it and to propose changes if you&#39;d like!</p>
<p>Thanks for reading!</p>
<p><a href="https://github.com/matfantinel/sveltekit-static-blog-template" title="button || color=secondary">Check out the starting template here!</a></p>

          ]]></content:encoded>
          <media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://rsinfo.vercel.app/images/posts/blog-development-sveltekit/cover.jpg"/>
          <media:content xmlns:media="http://search.yahoo.com/mrss/" medium="image" url="https://rsinfo.vercel.app/images/posts/blog-development-sveltekit/cover.jpg"/>          
        </item>
      
        <item>
          <guid>https://rsinfo.vercel.app/web-images-modern-formats</guid>
          <title>Smarter, Lighter, Better Images: A Guide to Optimization</title>
          <description>Learn how to reduce page loading times and bounce rate.</description>
          <link>https://rsinfo.vercel.app/web-images-modern-formats</link>
          <pubDate>Sat, 30 Jan 2021 00:00:00 +0000</pubDate>
          
          <content:encoded><![CDATA[
            <div style="margin: 50px 0; font-style: italic;">
              If anything looks wrong, 
              <strong>
                <a href="https://rsinfo.vercel.app/web-images-modern-formats">
                  read on the site!
                </a>
              </strong>
            </div>

            <p>Do you know how big the images displayed on your website are? When you open a page, the browser starts downloading a bunch of files in order to display it. Research shows that <a href="https://httparchive.org/reports/state-of-images">images are the most requested asset type</a> and take up more bandwidth than any other resource. So, making sure they are as small as they can be can greatly improve the load times for your website. (spoiler alert: mine&#39;s become 85% faster!)</p>
<h2 id="more-efficient-formats">More efficient formats</h2>
<p>For a long time, JPGs and PNGs have been our standard image formats. However, they are not optimized for the web - their quality is often unnecessarily high and the download size is too big. Over time, many new formats have appeared, but two of them have become quite notable: <a href="https://en.wikipedia.org/wiki/WebP">WebP</a> and <a href="https://www.lambdatest.com/blog/avif-image-format/">AVIF</a>.</p>
<p>WebP has been introduced in 2010, and has slowly gained adoption since then. Since 2020, <a href="https://caniuse.com/webp">WebP is now supported in all modern browsers</a>. AVIF <a href="https://jakearchibald.com/2020/avif-has-landed/">was launched in 2020</a>, and its adoption has been faster. As of May 2023 it is supported by all major browsers except Edge. You can always check out the up-to-date support status on <a href="https://caniuse.com/avif">caniuse.com</a>.</p>
<h3 id="browser-support">Browser Support</h3>
<p><em>But how do we use those shiny new formats if not all browsers support them?</em></p>
<p>With the <code>&lt;img&gt;</code> element, we can make the browsers do the work for us. We can declare multiple sources for the same image, and the browser will try to load them in order. If they do not support a format, they will immediatelly jump to the next one. To do that, we use the <code>srcset</code> property to declare the optimal versions (avif and webp), and then use the <code>src</code> as usual to point to the fallback image (jpg or png).</p>
<p>So, what we want to do is declare those different sources in the following order:</p>
<p>AVIF -&gt; WebP -&gt; JPG (or PNG)</p>
<pre><code class="language-html">&lt;img 
  srcset=&quot;my-image.avif, my-image.webp&quot; 
  src=&quot;my-image.jpg&quot; 
  loading=&quot;lazy&quot; 
  decoding=&quot;async&quot; 
/&gt;
</code></pre>
<p>If you look at the resulting HTML in your website, you can see that the <code>&lt;img&gt;</code> element has a <code>src</code> defined, but when you hover over it, it shows what is the actual file that&#39;s being loaded. If you&#39;re on a supported browser, it will have loaded the AVIF file. If you&#39;re on Safari, it will have loaded the WebP one. Otherwise, if you&#39;re using IE or something (I&#39;m sorry), the original JPG or PNG file will be loaded.</p>
<p><img src="https://rsinfo.vercel.app/images/posts/web-images-modern-formats/generated-html.png" alt="Screenshot of the generated HTML code. Hovering over the PNG filename reveals that an AVIF file is being downloaded instead." title="The img tag shows the PNG file as source, but hovering the mouse over it reveals that the AVIF file is the one that actually loaded."></p>
<h2 id="load-smaller-images">Load smaller images</h2>
<p>You can optimize even further than that. See, in my example, I am loading an image with a width of 1200px, however, the size it&#39;s being displayed is only 319px wide. The <code>srcset</code> property supports different widths to load, depending on the screen size.</p>
<pre><code class="language-html">&lt;img
    srcset=&quot;my-image-380w.avif 380w, my-image-640w.avif 640w, my-image-960w.avif 960w&quot;
    sizes=&quot;(max-width: 979px) 100vw, 640px&quot;
    src=&quot;my-image.jpg&quot;
    loading=&quot;lazy&quot;
    decoding=&quot;async&quot;
/&gt;
</code></pre>
<p>The <code>srcset</code> property is smart. As the name implies, it is a set of sources, not just a single one. When we declare multiple file paths and add a width unit besides it, the browser looks at this data and tries to display the smallest possible image.</p>
<p>On the code snippet above, the browser will follow this: <span>If the size of the displayed image (on the page) is smaller or equal to 380px, it will load the file with 380px of width. Otherwise, it will try to load the next declared path (640px).</span></p>
<p><strong>However,</strong> not all parts of this process are smarty. The browser cannot know what is the final size of the image on the page before it actually loads it. Which is why the <code>sizes</code> property exists. Let&#39;s see how it works:</p>
<p>The <code>sizes</code> property defines what rule the browser will use to get the width it uses to choose the correct file in <code>srcset</code>. The default value is <code>100vw</code>. That means that, to check what width the image will have, the browser just gets the width of the browser window. If we know the exact size the image will have on load, we can declare it here, or if we don&#39;t know the exact size, we can estimate. We can use media queries to help us specify the sizes better as well.</p>
<p>Check out the value on the example: <code>(max-width: 979px) 100vw, 640px</code>. What that code does is: if the width of the viewport is equal or smaller than 979px, use 100vw. Else, use 640px.</p>
<p>It is easier to understand if we visualize it like this:</p>
<p><img src="https://rsinfo.vercel.app/images/posts/web-images-modern-formats/sizes.png" alt="Screenshots picturing how the sizes property affects the image loading on both mobile and desktop" title="On mobile, the image width is almost the same as the viewport, so it&#39;s okay to use 100vw. On desktop, we usually limit the image width, so 640px was the sweet spot in this particular case."></p>
<p>Of course, different websites have different needs and situations. Make sure to adapt the code to your specific need.</p>
<p>It&#39;s also worth noting that most phones use a HiDPI mode. This means that <span>even though the reported width for the phone above is 375px, the browser will likely use a higher resolution to load the images</span> (usually 2x), in order to serve a higher quality image.</p>
<h2 id="lazy-loading-and-async-decoding">Lazy Loading and Async Decoding</h2>
<p>You might have noticed the <code>loading=&quot;lazy&quot;</code> and <code>decoding=&quot;async&quot;</code> attributes in the code above. Those are relatively new options that are part of an ongoing effort to make the web faster.</p>
<p><code>decoding=&quot;async&quot;</code> tells your browser it can try to parallelize loading your image. When your page is loading, it tries to decode both text and images at the same time. On lower-end devices though, decoding heavy images can take a while, and this might block the rendering of the rest of the content. With this option, the browser will try to proceed rendering the rest of the content and render the image later. This can be a great improvement to perceived performance.</p>
<p><code>loading=&quot;lazy&quot;</code> is probably the most important of the two. It is an easy way of telling the browser to <span>only load the images when they get close to appearing in the viewport</span>. There is a threshold that is defined by the browser that controls how close it needs to be before it gets loaded, so you don&#39;t have to worry about them not showing up if the user scrolls fast. <span>This ensures that the initial load of the website is as lean as it can get, improving perceived performance and also saving you some money on server requests.</span></p>
<p><img src="https://rsinfo.vercel.app/images/posts/web-images-modern-formats/first-load-requests.png" alt="Screenshot of the browser tools showing network requests: There are only two images that have been downloaded." title="When the website is initially loaded, it only downloads what&#39;s needed: my avatar image and the preview of the first blog post, that will show up after scrolling a bit."></p>
<p><img src="https://rsinfo.vercel.app/images/posts/web-images-modern-formats/after-scrolling-requests.png" alt="Screenshot of the browser tools showing network requests: now, there are many more images downloaded." title="When I scroll down the page, the images are downloaded as they&#39;re close to appearing."></p>
<h2 id="results-in-practice">Results In Practice</h2>
<p>Since I like using my own website and blog as a testbed for new stuff that I learn, I have applied these optimizations to it. The results were incredible!</p>
<p>Note: after doing some tests, I have decided that the benefits of serving differently-sized images on my website were too small to justify the extra effort of handling all these extra images. So, the only optimizations I have really applied were the optimized file formats, lazy loading and async decoding. I also chose PNG as fallback type instead of JPG because some of my images have transparency in them, which JPG does not support.</p>
<p>The following data is taken from the home page of the website, since it has a lot of images:</p>
<p><img src="https://rsinfo.vercel.app/images/posts/web-images-modern-formats/results.png" alt="Screenshot of browser tool network requests, from before and after optimization. Before: 1.6MB download; After: 249KB download"></p>
<p>\\<span>The total download size decreased by a whopping 85%!!</span> That&#39;s an incredible difference, with no noticeable difference in quality. Your results may vary, as they depend on how much of your website&#39;s size is images.</p>
<p>Before the changes, out of 1.6MB total, 92% of it were images, 5% were fonts, 1% was HTML, and the remaining 2% were of JS and other things like the web manifest.</p>
<p>Now, out of 249kB, just 24% of it are images. Fonts now make up 27% of page size, and are likely the target of a future optimization post!</p>
<h2 id="the-hard-part">The Hard Part</h2>
<p>The hardest part of this process is converting the images to all necessary formats and sizes. It is a lot of effort to do manually even for a single image, and even worse if you&#39;re trying to optimize existing images like I was.</p>
<h3 id="generating-the-images">Generating the Images</h3>
<p>For my needs, I have developed a NodeJS script that uses the <a href="https://github.com/lovell/sharp">Sharp</a> library to do the magic for me. It accepts as parameters a source and a target folder, input file types (what files it will look for in the source folder), output file types (what types it will convert to), as well as the desired widths.</p>
<p>You can install the script as a NPM package, and then run it on a build command on your website!</p>
<p><a href="https://github.com/matfantinel/image-transmutation" title="button || color=secondary">Check out image-transmutation!</a>
<a href="https://github.com/matfantinel/sveltekit-static-blog-template/blob/main/package.json" title="button || color=secondary style=clear">See usage example</a></p>
<h3 id="using-the-images">Using the images</h3>
<p>To make this setup work, I had to do some changes on how images were used on my website.</p>
<p>Pre-existing conditions:</p>
<ul>
<li>All the images on my website were initially in a folder called &quot;images&quot;, with various subfolders;</li>
<li>I didn&#39;t want all the versions of an image (webp, avif, etc) to take up space on my repository, so I only have them generated on build time.</li>
</ul>
<p>Modifications I did:</p>
<ul>
<li>I have created a component to centralize all image-loading logic;</li>
<li>This component receives two parameters: the file path and the alt text;</li>
<li>If my project is running in dev mode, it won&#39;t add the srcset at all, as the optimized images won&#39;t exist;</li>
</ul>
<pre><code class="language-html">&lt;script lang=&quot;ts&quot;&gt;
    // This is a SvelteKit environment variable. If it&#39;s true, it means the project is running in dev mode.
    import { dev } from &#39;$app/environment&#39;;

    // Declare the accepted parameters
    export let src: string;
    export let alt: string;

    // Declare the formats used for images
    export let formats: string[] = [&#39;avif&#39;, &#39;webp&#39;, &#39;png&#39;];

    // Get just the file name without extension (so &quot;image.png&quot; becomes &quot;image&quot;)
    $: fileName = src.split(&#39;.&#39;)[0];

    // Function to build the srcset string
    function buildSrcset() {
        // If project is in dev mode, I don&#39;t want a srcset since images aren&#39;t optimized yet
        if (dev) return;

        let srcset = &#39;&#39;;

        // Cycle through formats and add them to the srcset
        for (let i = 0; i &lt; formats.length; i++) {
            srcset += `${fileName}.${formats[i]}`;

            if (i &lt; formats.length - 1) {
                srcset += &#39;, &#39;;
            }
        }

        return srcset;
    }
&lt;/script&gt;

&lt;!-- Now we just use the default img element! --&gt;
&lt;img srcset=&quot;{buildSrcset()}&quot; {src} {alt} loading=&quot;lazy&quot; decoding=&quot;async&quot; /&gt;
</code></pre>
<p>And to use this component inside another page:</p>
<pre><code class="language-html">&lt;image src=&quot;my-image.png&quot; alt=&quot;Example image&quot; /&gt;
</code></pre>
<p>The full component code and usage example can be seen at <a href="https://github.com/matfantinel/sveltekit-static-blog-template/blob/main/src/lib/components/atoms/Image.svelte">my SvelteKit blog template repository</a>. That might be more up to date than here, even!</p>
<h2 id="wrapping-up">Wrapping Up</h2>
<p>With such amazing results, it&#39;s hard not to recommend you to optimize the images in your website ASAP. There sure are more approaches and optimizations that can be done besides the ones presented on this article, as the web world is always changing. But optimizations are a great way of showing respect to your users (as well as gathering more of them). Your site loads more quickly, and it uses less data and resources.</p>
<p>As front-end developers, we must acknowledge that all we write runs on someone else&#39;s computer, the user&#39;s. So it is important that we respect them and make sure we just use the resources we need to.</p>
<p>I hope you enjoyed reading this! Take care and happy coding!</p>

          ]]></content:encoded>
          <media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://rsinfo.vercel.app/images/posts/web-images-modern-formats/cover.jpg"/>
          <media:content xmlns:media="http://search.yahoo.com/mrss/" medium="image" url="https://rsinfo.vercel.app/images/posts/web-images-modern-formats/cover.jpg"/>          
        </item>
      
        <item>
          <guid>https://rsinfo.vercel.app/fixing-favicons</guid>
          <title>How to fix your Favicons</title>
          <description>Favicons suck. Luckily, there are ways to make them suck less.</description>
          <link>https://rsinfo.vercel.app/fixing-favicons</link>
          <pubDate>Wed, 06 Jan 2021 00:00:00 +0000</pubDate>
          
          <content:encoded><![CDATA[
            <div style="margin: 50px 0; font-style: italic;">
              If anything looks wrong, 
              <strong>
                <a href="https://rsinfo.vercel.app/fixing-favicons">
                  read on the site!
                </a>
              </strong>
            </div>

            <p>Favicons kinda suck. They should be a simple icon that identifies your webpage on a bunch of scenarios, i.e. the icon displayed on the tab besides your website&#39;s title, or the icon on the mobile browser&#39;s bookmarks screen, or the icon on the phone&#39;s home screen.</p>
<p>Unfortunately, different browsers, OSs, and implementations throughout the years have ended up with many different files and meta tags, that we as developers need to handle otherwise we end up with missing or pixelated icons.</p>
<h2 id="easy-mode">Easy Mode</h2>
<p>I recently met my new best friend, <a href="https://realfavicongenerator.net/">Real Favicon Generator</a>. It took all these pains I just wrote about and just made it a breeze to handle. Best of all, it&#39;s customizable!</p>
<p>You just have to add in your existing favicon image (for best results, a SVG or high-quality PNG is recommended). From then on, the generator will display previews and allow customization of each category of favicon it will generate:</p>
<p><img src="https://rsinfo.vercel.app/images/posts/fixing-favicons/favicon-generator-customization.jpg" alt="Screenshot of Real Favicon Generator&#39;s customization" title="The customization options allow you to set different icons depending on device and OS, and even generate icons with background colors if needed."></p>
<p>At the bottom, you can even set up ways of avoiding caching issues, compression, and scaling algorithms (!). After all that, it will generate them all as set, give you a zip with all the files, and the HTML code to paste on your <code>&lt;head&gt;</code>. You can check the result on this very website (fantinel.dev). The favicon should look fantastic on every device/browser combination.</p>
<h2 id="manual-mode">Manual Mode</h2>
<p>So, there are 5 types of favicons that we need to add, if we want to support every current browser:</p>
<h3 id="1-desktop-browsers">1. Desktop browsers</h3>
<ul>
<li><code>favicon.ico</code>, for IE and any other legacy browsers. Optional if you don&#39;t want to support it;</li>
<li><code>favicon-16x16.png</code>, the classic one that&#39;s displayed on the tabs;</li>
<li><code>favicon-32x32.png</code>, used on Safari for macOS.</li>
</ul>
<h3 id="2-android-browsers">2. Android browsers</h3>
<ul>
<li><code>android-chrome-192x192.png</code>, shown on the tab card and when added to home screen;</li>
<li><code>android-chrome-512x512.png</code>, shown on the splash screen for when the website is installed to the phone. Optional if it&#39;s not a PWA;</li>
</ul>
<h3 id="3-ios-safari-and-some-android-browsers-like-samsung-internet">3. iOS Safari, and some Android browsers like Samsung Internet</h3>
<ul>
<li><code>apple-touch-icon.png</code>, a 180x180 file displayed when the website is added to home screen;</li>
</ul>
<h3 id="4-windows-810-start-menu-optional">4. Windows 8/10 start menu (optional)</h3>
<ul>
<li><code>mstile-150x150.png</code>, only used when your website is added to the start menu as a tile on Windows 8/10, and when not declared, defaults to <code>apple-touch-icon.png</code> instead.</li>
</ul>
<h3 id="5-macos-safari-pinned-tabs-optional">5. macOS Safari Pinned Tabs (optional)</h3>
<ul>
<li><code>safari-pinned-tab.svg</code> is used when users pin a tab on Safari for macOS. Basically, you declare a monochrome SVG and a theme color. Safari does the rest.</li>
</ul>
<p><img src="https://rsinfo.vercel.app/images/posts/fixing-favicons/safari-pinned-tabs-demo.jpg" alt="Demo of Safari pinned tabs favicon behavior"></p>
<p>With those files, you should be good to go on every single browser, by adding this to your <code>&lt;head&gt;</code>:</p>
<pre><code class="language-html">&lt;head&gt;
    &lt;link rel=&quot;apple-touch-icon&quot; sizes=&quot;180x180&quot; href=&quot;/apple-touch-icon.png&quot; /&gt;
    &lt;link rel=&quot;icon&quot; type=&quot;image/png&quot; sizes=&quot;32x32&quot; href=&quot;/favicon-32x32.png&quot; /&gt;
    &lt;link rel=&quot;icon&quot; type=&quot;image/png&quot; sizes=&quot;16x16&quot; href=&quot;/favicon-16x16.png?&quot; /&gt;
    &lt;link rel=&quot;manifest&quot; href=&quot;/site.webmanifest&quot; /&gt;
    &lt;link rel=&quot;mask-icon&quot; href=&quot;/safari-pinned-tab.svg&quot; color=&quot;#000000&quot; /&gt;
    &lt;link rel=&quot;shortcut icon&quot; href=&quot;/favicon.ico&quot; /&gt;
&lt;/head&gt;
</code></pre>
<h2 id="single-svg-favicon">Single SVG Favicon</h2>
<p>Something that&#39;s starting to become a thing is having a single SVG favicon. Theoretically, SVGs are infinitely scalable, and should look good on all sizes. Unfortunately, browser support is not there yet.</p>
<p><a href="https://caniuse.com/link-icon-svg">Can I Use</a> reports that, currently (January 2021), only recent versions of Firefox and Chromium-based browsers support this feature. This means that Safari, non-Chromium Edge, IE, and some mobile browsers do not support it. Therefore, unless you want your favicon to just not appear in those browsers, you&#39;d still have to use other file formats as well. The downside of this approach is that all favicons would look the same, and you won&#39;t be able to customize and have differently-shaped icons for mobile devices, for example.</p>
<pre><code class="language-html">&lt;head&gt;
    &lt;link rel=&quot;icon&quot; href=&quot;favicon.svg&quot; /&gt;
&lt;/head&gt;
</code></pre>
<h2 id="wrapping-up">Wrapping Up</h2>
<p>Favicons suck. Luckily, there are people working to make it suck less. With the approach presented on this article, your website should be able to display its best favicon on all browsers for years to come.</p>

          ]]></content:encoded>
          <media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://rsinfo.vercel.app/images/posts/fixing-favicons/cover.jpg"/>
          <media:content xmlns:media="http://search.yahoo.com/mrss/" medium="image" url="https://rsinfo.vercel.app/images/posts/fixing-favicons/cover.jpg"/>          
        </item>
      
        <item>
          <guid>https://rsinfo.vercel.app/github-profile-readme</guid>
          <title>Spicing Up your GitHub Profile with HTML and CSS</title>
          <description>Make your GitHub profile more appealing with what you do best: code!</description>
          <link>https://rsinfo.vercel.app/github-profile-readme</link>
          <pubDate>Sat, 02 Jan 2021 00:00:00 +0000</pubDate>
          
          <content:encoded><![CDATA[
            <div style="margin: 50px 0; font-style: italic;">
              If anything looks wrong, 
              <strong>
                <a href="https://rsinfo.vercel.app/github-profile-readme">
                  read on the site!
                </a>
              </strong>
            </div>

            <p>Last year, GitHub added a new cool feature for the user profile. You can now add a README file to it, and it will show up besides your profile pic. This is great for talking a bit about yourself and what you do, putting some contact info, or simply making a cool first impression.</p>
<h2 id="creating-the-repository">Creating the Repository</h2>
<p>For adding this to your profile, there&#39;s a little secret. Instead of an option in your &quot;Edit Profile&quot; settings, this is achieved by <span>creating a new repository with the same name as your GitHub username.</span></p>
<p><img src="https://rsinfo.vercel.app/images/posts/github-profile-readme/repo-creation.jpg" alt="Screenshot of GitHub repository creation" title="🎉️ Creating a new repo with the same name as your username immediatelly makes GitHub praise you for finding out this secret."></p>
<p>You can choose to initialize the repository with a README file already. After that, the content of this file will already start showing on your personal profile.</p>
<p>The README is just a Markdown file, which may make you think initially that you can only write in stuff with GitHub&#39;s default styling. However, when you get creative, there&#39;s a lot more you can do. You can add images and GIFs to it, sure, but SVGs are the real heros here. By adding SVG files to the Markdown file, you enable a lot of possibilities. SVG files support HTML tags and CSS styles (including animations!)</p>
<p>For adding HTML to the SVG, we can use the <code>&lt;foreignObject&gt;</code> tag. This is an element that can include elements from different XML namespaces. Which means that even though you&#39;re in a SVG namespace, you can use XHTML elements and all the features it supports, including the <code>&lt;style&gt;</code> tag for adding CSS.</p>
<p>As an example, check out the SVG file I use to add the &quot;tags&quot; with technologies to my profile:</p>
<pre><code class="language-html">&lt;svg fill=&quot;none&quot; viewBox=&quot;0 0 300 120&quot; width=&quot;300&quot; height=&quot;120&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot;&gt;
    &lt;foreignObject width=&quot;100%&quot; height=&quot;100%&quot;&gt;
        &lt;div xmlns=&quot;http://www.w3.org/1999/xhtml&quot;&gt;
            &lt;style&gt;
                .tags {
                    display: flex;
                    flex-wrap: wrap;
                    height: 100%;
                    width: 100%;
                }
                .tag {
                    background-color: #e3ffff;
                    border-radius: 0.25em;
                    color: #0ca4a5;
                    border: 1px solid #0ca4a5;
                    display: inline-block;
                    font-size: 0.75em;
                    line-height: 2em;
                    margin: 0.125em;
                    padding: 0 0.5em;
                    text-decoration: none;
                    font-family: sans-serif;
                }
            &lt;/style&gt;

            &lt;div class=&quot;tags&quot;&gt;
                &lt;div class=&quot;tag&quot;&gt;Angular&lt;/div&gt;
                &lt;div class=&quot;tag&quot;&gt;Vue(X)&lt;/div&gt;
                &lt;div class=&quot;tag&quot;&gt;JavaScript&lt;/div&gt;
                &lt;div class=&quot;tag&quot;&gt;TypeScript&lt;/div&gt;
            &lt;/div&gt;
            &lt;div class=&quot;tags&quot;&gt;
                &lt;div class=&quot;tag&quot;&gt;(S)CSS&lt;/div&gt;
                &lt;div class=&quot;tag&quot;&gt;Building UIs&lt;/div&gt;
                &lt;div class=&quot;tag&quot;&gt;Web Components&lt;/div&gt;
            &lt;/div&gt;
            &lt;div class=&quot;tags&quot;&gt;
                &lt;div class=&quot;tag&quot;&gt;Ionic&lt;/div&gt;
                &lt;div class=&quot;tag&quot;&gt;Electron&lt;/div&gt;
                &lt;div class=&quot;tag&quot;&gt;.NET&lt;/div&gt;
            &lt;/div&gt;
        &lt;/div&gt;
    &lt;/foreignObject&gt;
&lt;/svg&gt;
</code></pre>
<p>From there on, the possibilities are endless. On my profile, I added my personal logo SVG and the same drawing animation used on my own website.</p>
<p><img src="https://rsinfo.vercel.app/images/posts/github-profile-readme/my-profile.gif" alt="Animation on my GitHub Profile" title="Using CSS animations inside the SVG, I was able to mimic the animation on my website."></p>
<p>Feel free to check out <a href="https://github.com/matfantinel/matfantinel">the source code</a> to find out how it works.</p>
<h2 id="inspiration">Inspiration</h2>
<p>Some people have compiled <a href="https://github.com/abhisheknaiidu/awesome-github-profile-readme">a list of amazing examples and inspirations for your profile</a>. Some are minimalistic, others more complex, and some even get data from APIs (!). My favorite is <a href="https://github.com/BrunnerLivio">this one from Livio Brunner</a>, which definitely brings all the best things from 2000&#39;s web.</p>

          ]]></content:encoded>
          <media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://rsinfo.vercel.app/images/posts/github-profile-readme/cover.jpg"/>
          <media:content xmlns:media="http://search.yahoo.com/mrss/" medium="image" url="https://rsinfo.vercel.app/images/posts/github-profile-readme/cover.jpg"/>          
        </item>
      
        <item>
          <guid>https://rsinfo.vercel.app/2020-year-in-review</guid>
          <title>Looking Back at 2020</title>
          <description>2020 definitely wasn't our best year... but let's remember what was good about it.</description>
          <link>https://rsinfo.vercel.app/2020-year-in-review</link>
          <pubDate>Mon, 28 Dec 2020 00:00:00 +0000</pubDate>
          
          <content:encoded><![CDATA[
            <div style="margin: 50px 0; font-style: italic;">
              If anything looks wrong, 
              <strong>
                <a href="https://rsinfo.vercel.app/2020-year-in-review">
                  read on the site!
                </a>
              </strong>
            </div>

            <p>We all know this year hasn&#39;t been easy. That doesn&#39;t mean it had to be wasted. Regardless of how bad or good it has been for oneself individually, there are always lots of lessons we can learn from what we&#39;ve been through.</p>
<h2 id="more-than-one-pandemic">More Than One Pandemic</h2>
<p>I think one of the most obvious takeaways from this year is that we are not living just one pandemic (COVID-19), but also one that&#39;s equally worrisome and potentially even deadlier: misinformation. The sheer amount of false information and hatred being spread through both social media and real life is becoming bigger every passing day.</p>
<p>They can be shared by ignorance, personal or political interest, or simply to &quot;watch the world burn&quot;. It is painful to watch the world go backwards like this; especially when people close to you are affected as well.</p>
<h2 id="mental-health">Mental Health</h2>
<p>I am sure that regardless of any individual impact the pandemics have had, your mental health must have been impacted by all of this somehow. &quot;Doomscrolling&quot; became a thing, fueled by our time watching and reading terrible news while quarantining in the safety of our homes.</p>
<p>Initially, I was guilty of that too. Checking many times a day for news, how the pandemic was growing, getting angry at how our leaders were dealing with it, and more. Fortunately, I ended up realizing how harmful that was to my mental health, and that there was no good coming out of it. <span>A few minutes a day is enough to catch up on important news, the rest of the day can be spent on myself.</span> So instead of mindlessly scrolling through the doom and gloom on the internet, I started to work on more personal projects, learning new stuff, and playing games.</p>
<h2 id="learning-with-personal-projects">Learning with Personal Projects</h2>
<p>This year I worked on a few personal projects, and tried different approaches with them so I could learn new things. I didn&#39;t necessarily get really in-depth into most of the things I learned, but the knowledge I got definitely made me a better developer.</p>
<p><img src="https://rsinfo.vercel.app/images/posts/2020-year-in-review/pocket-companion.jpg" alt="Two screenshots of the Pocket Companion app, side by side. One displays all menu options, and the other shows a page for a great white shark."></p>
<ul>
<li><a href="https://rsinfo.vercel.app/ionic-animal-crossing-companion/">I built an Animal Crossing companion app</a>, with great utilities for when playing the game. I focused a lot on CSS animations for this one, while trying to mimic the official Nintendo app in looks. Learned a lot of things while building it:<ul>
<li>State management in Angular projects, with <a href="https://ngrx.io/">NgRx</a>;</li>
<li>Offline functionality with IndexedDB in the browser;</li>
<li>Improved CSS Animations;</li>
<li>Improved Ionic and PWA knowledge;</li>
<li>Improved performance knowledge, with Web Workers, Virtual Scrolling and Lazy Loading;</li>
</ul>
</li>
<li>I redesigned part of my website - I decided to change things up a bit, with an animated (but still lightweight) header background, a new logo, typography improvements, code highlighting, and more. I think it looks more professional than before, and represents my way of building things better as well;</li>
<li>I built <a href="https://github.com/matfantinel/resume">my Resume as a Web Component</a> - using StencilJS to build it, and CSS Grid for the layout. Both of those things were new to me, so it was pretty interesting;</li>
<li>I learned about <a href="https://rsinfo.vercel.app/css-scroll-snapping/">CSS Scroll Snapping</a> - a fantastic new CSS capability that helps with reducing the amount of JS in our websites;</li>
<li>I focused a lot on improving my design skills this year. While I&#39;m still a developer (and plan on continuing to be), designing things is something I find very fun. I learned messing with a few design-related things this year:<ul>
<li>Edit SVG files in Inkscape - still a lot to learn, but I&#39;m already capable of doing some edits to existing files;</li>
<li>Build high-fidelity mockups in Figma - being able to design more quickly than I was by building it was great for speeding up the process, and being able to collect feedback earlier was fantastic as well;</li>
</ul>
</li>
<li>I started to contribute a bit more to Open Source projects, like <a href="https://elementary.io">elementary OS</a>. Mainly with a still-in-progress website rebuild, but also with tons of feedback, issue reports, offering support and participating on discussions.</li>
</ul>
<h2 id="fun">Fun</h2>
<p>Since I committed myself to stop seeing bad things and focus on good ones, I resorted to at-home entertainment a lot this year. My highlights:</p>
<h3 id="tv-and-movies">TV and Movies</h3>
<ul>
<li><p><strong>Mr. Robot</strong> was a jaw-dropping series. I started watching it just this year, and binged to the finale quickly. It was an incredibly powerful series, with genius writing and cinematography. Highly recommend it to anyone, even if not a fan of the tech/hacking theme;</p>
</li>
<li><p><strong>Community</strong> was a great find; It&#39;s not a series I had ever heard of when it was still airing, as it never got popular here in Brazil. However, after hearing about it on the web and finding it on Netflix, I&#39;m so glad I started watching it. Loads of fun, full of references, internal jokes and Dan Harmon genius;</p>
</li>
</ul>
<h3 id="games">Games</h3>
<ul>
<li><p><strong>Animal Crossing New Horizons</strong> was one of the best things to happen this year. It&#39;s far from a perfect game, but it could not have been better for the current situation, providing an easy escape into a world free of our current burdens. It came out at the beginning of quarantine and still provides daily wholesomeness to this day;</p>
</li>
<li><p><strong>Dungeons &amp; Dragons</strong> was a surprising source of fun considering my party only played online this year. But even with social distancing, we managed to have a lot of fun. With <a href="https://foundryvtt.com/">FoundryVTT</a>, things are much easier to handle and it&#39;s not much harder to get immersed. I&#39;m even trying to be a DM of my own campaign... I&#39;m not sure it&#39;s going as well as I hoped, but hey, at least I&#39;m trying.</p>
</li>
<li><p><strong>Hollow Knight</strong>... I&#39;m so glad I played it. Being a Metroidvania, a genre I&#39;m not really a fan of, it completely hooked me with its worldbuilding, art style, atmosphere and frustratingly satisfying difficulty. A 10/10 for me, for sure;</p>
</li>
</ul>
<p><img src="https://rsinfo.vercel.app/images/posts/2020-year-in-review/hollow-knight.jpg" alt="Official artwork of Hollow Knight, showing the main character, a humanoid shadow wearing a horned helmet and holding a small sword, standing in a dark cave." title="Hollow Knight official artwork, by Team Cherry"></p>
<h2 id="writing">Writing</h2>
<p>Well, since this is only the third blog post this year, I definitely did not do much writing. I haven&#39;t felt inspired to do so, as I was often busy building nice things or winding down from all the mess that was going on. I&#39;ll repeat my intention of trying to write more next year, of course, since it shouldn&#39;t be hard to do at least more than in 2020.</p>
<h2 id="wrapping-up">Wrapping Up</h2>
<p>If you&#39;re still reading, thanks! You&#39;re probably my mom or fiancée. Anyway, 2020 was a very exciting year, even if not in a good way. Let&#39;s hope 2021 is a more boring one. See you then!</p>

          ]]></content:encoded>
          <media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://rsinfo.vercel.app/images/posts/2020-year-in-review/cover.jpg"/>
          <media:content xmlns:media="http://search.yahoo.com/mrss/" medium="image" url="https://rsinfo.vercel.app/images/posts/2020-year-in-review/cover.jpg"/>          
        </item>
      
        <item>
          <guid>https://rsinfo.vercel.app/css-scroll-snapping</guid>
          <title>CSS Scroll Snapping - Improve Scrolling without JS</title>
          <description>Learn how to snap scroll positions with CSS only.</description>
          <link>https://rsinfo.vercel.app/css-scroll-snapping</link>
          <pubDate>Mon, 03 Aug 2020 00:00:00 +0000</pubDate>
          
          <content:encoded><![CDATA[
            <div style="margin: 50px 0; font-style: italic;">
              If anything looks wrong, 
              <strong>
                <a href="https://rsinfo.vercel.app/css-scroll-snapping">
                  read on the site!
                </a>
              </strong>
            </div>

            <p>CSS is evolving constantly and the past few years have brought us amazing stuff. It is getting easier to make smooth and complete experiences without having to use JavaScript at all. Case in point: Scroll Snapping.</p>
<p>It is an easy way to guarantee that users will scroll to the correct portion of your page or of a container. Picture a landing page that is easily swipable/scrollable between sections, or swipable cards. Take in mind how Android&#39;s Recent Apps screen works, for example:</p>
<p><img src="https://rsinfo.vercel.app/images/posts/css-scroll-snapping/android-scroll-snapping.gif" alt="Android&#39;s Recent Apps screen has scroll mapping between app cards"></p>
<p>You can see that Android never allows the end of a scroll to be in a place between cards. There&#39;s a certain threshold that determines that the scroll will snap into the nearest card and put it in the center. All that while still keeping scrolling momentum, allowing you to go from one edge of the list to another in a single scroll if you want to.</p>
<p>Until recently, you&#39;d have to resort to JavaScript code to make a similar behavior on the web. But now, all you need is CSS, which makes things more performant, consistent and reliable! Browser support is already pretty good, with all major browser engines already supporting it fully. Check out browser support on <a href="https://caniuse.com/#feat=css-snappoints">caniuse.com</a>.</p>
<p>I&#39;ve recently added scroll snapping to my own website. You can check it out on the &quot;Work Experience&quot; section in the <a href="https://fantinel.dev">Home page</a>. It&#39;s specially great on mobile!</p>
<h2 id="how">How?</h2>
<p>There are two main CSS properties that make the magic happen, one for the parent element, and one for its children.</p>
<pre><code class="language-css">.parent {
    scroll-snap-type: y mandatory;
}
.child {
    scroll-snap-align: start;
}
</code></pre>
<h3 id="scroll-snap-type">scroll-snap-type</h3>
<p>This property tells the browser that the parent element uses scroll snapping. We are given some options on how snapping must work. <code>y</code> indicates that the scroll happens vertically, while <code>x</code> means horizontally. We can also pass the <code>mandatory</code> and <code>proximity</code> options.</p>
<p>We use <code>mandatory</code> to tell that the browser <em>must</em> snap to a snap point when the user stops scrolling. This means that if the next snap point becomes visible on the screen and scrolling stops, the browser will automatically snap to the next one. In the other end, with <code>proximity</code>, things are less strict. The browser will only snap to the next snap point if scrolling gets past a certain threshold. Both values are useful, their use will depend on the situation you&#39;re applying it to.</p>
<iframe height="500" style="width: 100%;" scrolling="no" title="scroll-snap-type: Mandatory vs Proximity" src="https://codepen.io/matfantinel/embed/preview/LYNPdpE?default-tab=result&theme-id=dark" frameborder="no" loading="lazy" allowtransparency="true" allowfullscreen="true">
  See the Pen <a href="https://codepen.io/matfantinel/pen/LYNPdpE">
  scroll-snap-type: Mandatory vs Proximity</a> by Matheus Fantinel (<a href="https://codepen.io/matfantinel">@matfantinel</a>)
  on <a href="https://codepen.io">CodePen</a>.
</iframe>

<h3 id="scroll-snap-align">scroll-snap-align</h3>
<p>This is a property you add to the children that specifies where the snap points will be in the element. Which means that, whenever the browser automatically snaps the scroll to the element, it will either go to the left/top edge (<code>start</code>), center (<code>center</code>), or right/bottom edge (<code>end</code>) of the element. This property pretty much only makes a difference if the children are bigger than the parent&#39;s display size.</p>
<h3 id="scroll-padding-and-scroll-margin">scroll-padding and scroll-margin</h3>
<p>To make things even better, we can use the <code>scroll-padding</code> (for parent) and <code>scroll-margin</code> (for children) properties. They add some space before/after the elements that are only considered when scrolling. The best way to implement them is by trying it out after you build your scroll snapping goodiness.</p>
<p>You can check the documentation over on <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Scroll_Snap">Mozilla Developer Network</a> for more info.</p>
<h2 id="wrapping-up">Wrapping Up</h2>
<p>Scroll snapping is a sign that the web is maturing. For years we&#39;ve been bloating websites with a lot of JavaScript for very simple visual tasks, and now CSS is slowly evolving to take some space back. It&#39;s an important evolution because Web technologies are being used to build every kind of application, and its native feature set needs to be good enough to compete with native or native-ish counterparts like Flutter, Swift, or Kotlin.</p>
<p>Thanks for reading!</p>

          ]]></content:encoded>
          <media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://rsinfo.vercel.app/images/posts/css-scroll-snapping/cover.jpg"/>
          <media:content xmlns:media="http://search.yahoo.com/mrss/" medium="image" url="https://rsinfo.vercel.app/images/posts/css-scroll-snapping/cover.jpg"/>          
        </item>
      
        <item>
          <guid>https://rsinfo.vercel.app/ionic-animal-crossing-companion</guid>
          <title>Developing an Animal Crossing companion app with Ionic</title>
          <description>No bells were spent while building this app.</description>
          <link>https://rsinfo.vercel.app/ionic-animal-crossing-companion</link>
          <pubDate>Tue, 28 Jul 2020 01:19:02 +0000</pubDate>
          
          <content:encoded><![CDATA[
            <div style="margin: 50px 0; font-style: italic;">
              If anything looks wrong, 
              <strong>
                <a href="https://rsinfo.vercel.app/ionic-animal-crossing-companion">
                  read on the site!
                </a>
              </strong>
            </div>

            <p>This year I&#39;ve played a lot of Animal Crossing New Horizons. It came out at the start of quarantine - and was extremely popular for providing an escape from that, with a virtual life that&#39;s free of the problems we&#39;re facing on the real one.</p>
<p>In the meantime, I was re-discovering <a href="https://ionicframework.com/">Ionic</a> and wanted to work on an app that would help me improve my knowledge of it, and as a bonus learn about other stuff I&#39;ve been interested in. So, I decided to work on a companion app for the game I&#39;ve been playing so much.</p>
<p>This post illustrates my experience developing it. It is not a tutorial or an in-depth guide. It&#39;s just meant to describe my experience, what I learned and any bumps in the way. In any case, the <a href="https://github.com/matfantinel/acnh-pocket-companion">source code is available on GitHub</a> for all to see and modify. If it ends up helping anyone else in the way, even better!</p>
<p><a href="https://pocketcompanion.fantinel.dev">You can check out the finalized app here</a>.</p>
<h2 id="creating-the-app">Creating the app</h2>
<p>Since I&#39;m testing Ionic (version 5 as of writing), I tried to check out as much of the experience they provide as I could. Even though you can create an app via their CLI, they also provide <a href="https://ionicframework.com/start">an online App Wizard</a> to do that visually. It&#39;s a pretty cool way to display the starting templates, easily setting theme colors, default icon and the JS Framework you&#39;ll use. I chose Angular for this one.</p>
<p><img src="https://rsinfo.vercel.app/images/posts/ionic-animal-crossing-companion/wizard.jpg" alt="Screenshot of Ionic&#39;s app creation wizard. It allows you to pick a name, an icon, a template, and a framework to start your app."></p>
<p>After setting it up, the wizard gives you a CLI command with an ID to run on your machine. Therefore it still uses the CLI in the end, but it&#39;s a nice touch for the starting experience.</p>
<p><img src="https://rsinfo.vercel.app/images/posts/ionic-animal-crossing-companion/all-set.jpg" alt="The wizard gives you a CLI command with an ID for you to run on your machine"></p>
<p>After running that command, the CLI prompted me if I wanted to integrate with <a href="https://capacitorjs.com/">Capacitor</a>, which is a tool that makes the app deployable to Android/iOS. I accepted, since I plan to release it on the Play Store at some point. The main goal is to release the app as a <a href="https://rsinfo.vercel.app/what-are-pwas-and-why-should-i-care-about-them/">PWA</a>, but an Android version wouldn&#39;t hurt, since the publishing process is almost-free and there&#39;s almost zero extra effort involved. Publishing it for iPhones is not a goal due to the cost and effort required to publish on the App Store.</p>
<p>After installation, I could run the app with <code>ionic serve</code>, which resulted in a template app with the settings I had set on the App Wizard.</p>
<p><img src="https://rsinfo.vercel.app/images/posts/ionic-animal-crossing-companion/initial-template.jpg" alt="Screenshot of a browser with browser tools open, and a mobile website with Ionic&#39;s default template."></p>
<p>The default folder structure is pretty straightforward and should be familiar to anyone who has ever worked with Angular before.</p>
<p><img src="https://rsinfo.vercel.app/images/posts/ionic-animal-crossing-companion/default-folder-structure.jpg" alt="Default folder structure on an Ionic Angular app"></p>
<h2 id="starting-development">Starting development</h2>
<p>Since I am a visual person, I decided to start work by changing the looks of the app first. This helps me stay motivated since I can see progress faster (because everything I do results in a visual change), and it also allows me to visualize the final product earlier, and gives me more time to think of good features or UX improvements.</p>
<p>Even though I generated my project using the Tabs template, I decided that I don&#39;t want tabs in my app. So I had to do a few changes to the routing configuration.</p>
<p>First, I created a new page that I can use as the initial screen for my app. Ionic CLI makes it easy to create pages and components. Just running <code>ionic generate page home</code> created a page called Home, and automatically adds its modules to the Angular config, and its route to the Angular Router.</p>
<p>After that, to remove the tabs, all I had to do was set the default route (<code>&#39;&#39;</code>) to redirect to home, and then I could delete all the Tab pages.</p>
<pre><code class="language-typescript">~filename app-routing.module.ts
import { NgModule } from &#39;@angular/core&#39;;
import { PreloadAllModules, RouterModule, Routes } from &#39;@angular/router&#39;;

const routes: Routes = [
    {
        path: &#39;&#39;,
        redirectTo: &#39;home&#39;,
        pathMatch: &#39;full&#39;
    },
    {
        path: &#39;home&#39;,
        loadChildren: () =&gt; import(&#39;./home/home.module&#39;).then((m) =&gt; m.HomePageModule)
    }
];
@NgModule({
    imports: [RouterModule.forRoot(routes, { preloadingStrategy: PreloadAllModules })],
    exports: [RouterModule]
})
export class AppRoutingModule {}
</code></pre>
<h2 id="theming-and-layout">Theming and Layout</h2>
<p>For me, this is the best part. Ionic makes it SO easy to change themes! There&#39;s a <code>variables.scss</code> file on the <code>theme</code> folder, where you can find Ionic&#39;s default color palette and change anything. But they provide <a href="https://ionicframework.com/docs/theming/color-generator">an amazing Color Generator</a> that can make all the palette calculations for you. Just put your primary/secondary/success/danger/etc colors in there, and it will output the code for you to paste on your app.</p>
<p><img src="https://rsinfo.vercel.app/images/posts/ionic-animal-crossing-companion/color-generator.jpg" alt="Screenshot of Ionic&#39;s color generator. When you set primary, secondary, and more colors by giving a HEX value, and Ionic automatically generates shade variants and gives you a live preview."></p>
<p>After some time styling, I modified the layout of the two page skeletons I wanna have, the Home page (that mimics the Nookphone in the game), and I styled the header of the other pages.</p>
<p><img src="https://rsinfo.vercel.app/images/posts/ionic-animal-crossing-companion/skeleton.gif" alt="Gif showing the home screen of my app. The home screen has 4 buttons: Passport, Island, To-Do and Daily Chores. Clicking on them opens a page."></p>
<p>Since I wanted to have the same header on all pages, I ended up creating a component for it. Since I had already two components and six pages, I decided to split them up in different folders (I honestly don&#39;t know why Ionic doesn&#39;t do that by default). My folder structure ended up like this:</p>
<p><img src="https://rsinfo.vercel.app/images/posts/ionic-animal-crossing-companion/modified-folder-structure.jpg" alt="The folder structure after my modifications"></p>
<p>Also, to be able to import the same component into multiple Pages (each page with its own module), I had to create the ComponentsModule. This required a bit of searching because I wasn&#39;t familiar with this approach yet. ComponentsModule by itself is very simple, I just import the Components there:</p>
<pre><code class="language-typescript">~filename components.module.ts
import { NgModule } from &#39;@angular/core&#39;;
import { CoolHeaderComponent } from &#39;./cool-header/cool-header.component&#39;;
import { IonicModule } from &#39;@ionic/angular&#39;;

@NgModule({
    declarations: [CoolHeaderComponent],
    imports: [IonicModule.forRoot()],
    exports: [CoolHeaderComponent]
})
export class ComponentsModule {}
</code></pre>
<p>The annoying part was having to add ComponentsModule to each of the pages. There probably is an easier way of handling this, but right now I decided to not dig too deep into it.</p>
<p>After making the skeleton of the app, I started working on some specific pages. I started with the home screen, that mimics a cell phone&#39;s app grid. I&#39;ll probably add more options as the app evolves, but for now this is good enough to build the layout with.</p>
<p>The next screen to be done was the <em>Island</em> one. It is a simple form with some text inputs, a datepicker and a couple of dropdowns. I used Ionic&#39;s default components for them and styled them with CSS so they fit the app&#39;s style better. Everything was pretty simple to do and worked great. Ionic&#39;s docs made it super easy to find the available options and easier ways to theme.</p>
<p>I wanted to add another thing to this screen too, though: a section containing the island&#39;s villagers, and a search box that allows the user to select them. Just adding another &quot;card&quot; to the UI and making it scroll would deliver what I want, but it wouldn&#39;t look <em>awesome</em>. GitHub&#39;s recently released mobile app has this bottom drawer that I personally found awesome:</p>
<p><img src="https://rsinfo.vercel.app/images/posts/ionic-animal-crossing-companion/github-drawer.gif" alt="GitHub&#39;s cool bottom drawer"></p>
<p>Luckily for me, someone&#39;s already worked on something like that for Ionic, which means I don&#39;t have to do it from scratch! <a href="https://github.com/AnthonyCifuentes/ion-slide-drawer">Click here</a> to check it on GitHub. Unfortunately it is not (at the time of writing) available as an installable component on NPM or somewhere else. But the code is simple and I just copied it over to my own project.</p>
<h2 id="state-management">State Management</h2>
<p>Since the entire point of this app is learning, I decided to use <a href="https://ngrx.io">NgRx</a>. It is a State Management library for Angular that works in a similar way to VueX or Redux. I&#39;ve worked with VueX recently and really like the concept, so I decided to make use of it here.</p>
<p>I started by adding it to my application with <code>npm i @ngrx/store @ngrx/effects @ngrx/store-devtools @ngrx/schematics --save</code>. If you wanna learn more about NgRx, I used <a href="https://indepth.dev/how-to-start-flying-with-angular-and-ngrx/">this amazing tutorial</a> to learn it for this app.</p>
<h2 id="database">Database</h2>
<p>The best way to store data in an app like mine - supposed to work on Android, iOS and the Web, but still entirely offline - is using the browser&#39;s IndexedDB. It&#39;s basically a simpler SQL database for your web app that lives inside the browser. <a href="https://developer.mozilla.org/en-US/docs/Web/API/IndexedDB_API">You can read more on MDN if you&#39;d like</a>.</p>
<p>While useful, IndexedDB has a very low-level API, which makes it hard to get started with. Which is why I chose to use <a href="https://dexie.org/">Dexie.js</a> as a wrapper for IndexedDB. It allows me to use a simple API to query data, while already doing the needed optimizations.</p>
<p>Simply installing Dexie.js and a quick read on its documentation allowed me to successfully store and read persistent data for my app.</p>
<h2 id="putting-some-other-cool-things-in-practice">Putting some other cool things in practice</h2>
<p>Since the main purpose of developing this app is learning, I decided to use some cool stuff I&#39;ve learned and put them in practice:</p>
<ul>
<li><a href="https://rsinfo.vercel.app/web-workers/">Web Workers</a>: on first run, the app uses a web worker to parse the game data (contained in large JSON files) in the background, so it can fill the database with the data used on Critterpedia</li>
<li>Virtual Scroll: on the Critterpedia listings, I used Virtual Scroll instead of pagination. I figured this was a better choice because while it can have a lot of items, it&#39;s a fixed number so no need to paginate. This way it maintains good performance on scrolling even on lower-end devices. Luckily, <a href="https://ionicframework.com/docs/api/virtual-scroll">Ionic provides a built-in component for that</a>!</li>
<li>Lazy loading images: since all items in the list have an icon that&#39;s displayed besides them, there are lots of images to download. Without lazy-loading, ALL images would be loaded right off the bat, even the ones way down the bottom of the list. With lazy loading, the browser automatically downloads only images as they would appear on screen by just setting the <code>loading</code> attribute: <code>&lt;img loading=&quot;lazy&quot;&gt;</code></li>
</ul>
<h2 id="running-on-android">Running on Android</h2>
<p>After having a few parts of my app done, I decided it was time to run in on my Android phone, to have a better look of how it will look and feel on an actual device.</p>
<p>The first step for this is installing Android Studio. Install instructions may vary depending on your operating system. I&#39;m on a Linux-based OS so I installed it from <a href="https://snapcraft.io/android-studio">Snapcraft</a>. You can follow the instructions from the <a href="https://ionicframework.com/docs/developing/android">Ionic docs</a> if you&#39;d prefer.</p>
<p>After installing Android Studio, we need to add an environment variable that points to the Android SDK. In the following command (Linux, Mac), replace the directory with the one where the Sdk is installed in your PC, then add it to the end of your <code>.bashrc</code> file:</p>
<pre><code class="language-shell">export ANDROID_SDK_ROOT=$HOME/Library/Android/sdk
</code></pre>
<p>Adding these next lines to the <code>.bashrc</code> file will also give you a quick way to access these Android tools if needed:</p>
<pre><code class="language-shell"># avdmanager, sdkmanager
export PATH=$PATH:$ANDROID_SDK_ROOT/tools/bin

# adb, logcat
export PATH=$PATH:$ANDROID_SDK_ROOT/platform-tools

# emulator
export PATH=$PATH:$ANDROID_SDK_ROOT/emulator
</code></pre>
<p>Now, we have to register Android as a platform for our app. Since we&#39;re using Capacitor to make this bridge, we need only a single command:</p>
<pre><code class="language-shell">ionic capacitor add android
</code></pre>
<p><em>If you get an error saying that &quot;Capacitor could not find the web assets directory&quot;, be sure to run <code>ionic build</code> to generate this directory first.</em></p>
<p>After that&#39;s done, you can open the project in Android Studio (it will be on a folder called <code>Android</code> at the root of your project). If you still haven&#39;t setup a device or emulator to run your app in, do it now. The <a href="https://ionicframework.com/docs/developing/android#android-studio">Ionic docs</a> show how to do both processes.</p>
<p>After a loooong while, Android Studio will have loaded all it needs to run your project. Just click on Run (Shift+F10). It should open on your phone/emulator!</p>
<h2 id="pwa-preparation">PWA preparation</h2>
<p>To be able to publish the app as a PWA, we need to add a Service Worker and a Manifest. Thankfully, Angular already has the CLI and the packages that allows us to do that easily. <code>ng add @angular/pwa</code> worked like a charm. This automatically added the needed files, and wired it up with the existing Angular modules automatically.</p>
<p>After that, I edited <code>ngsw-config.json</code> and <code>manifest.webmanifest</code> files with my app&#39;s name and colors, and I replaced all generated icons with my own. For more details on how to create PWAs with Angular, <a href="https://rsinfo.vercel.app/angular-pwa-how-to/">check my specific post for that</a></p>
<h3 id="routing-issue">Routing issue</h3>
<p>One issue I was having after publishing a PWA like that is that when refreshing my app on the browser, it was throwing a 404 error. This happened because the route had changed and Angular lost track of what it was supposed to open. I fixed this by changing a line in my <code>app-routing.module.ts</code> and adding <code>useHash: true</code> to the settings:</p>
<pre><code class="language-typescript">~filename app-routing.module.ts
@NgModule({
  imports: [
    RouterModule.forRoot(routes, { preloadingStrategy: PreloadAllModules, useHash: true })
  ],
  exports: [RouterModule]
})
</code></pre>
<h3 id="publishing">Publishing</h3>
<p>To host my PWA, I decided to use <a href="https://netlify.com">Netlify</a>. The publishing experience was quite easy and friction-free, and they also provide a free hosting plan which is perfect to host this demo-only-app. I will not document how the publishing proccess worked here because their UI is very intuitive and their docs would be way better than mine anyway.</p>
<h2 id="wrapping-up">Wrapping Up</h2>
<p>Developing this definitely took me a while - but that&#39;s because time&#39;s been quite scarce for me. Most of the development time was spent learning NgRx, which was definitely the most complex part of this application. It also took me a while to find a good IndexedDB wrapper before I settled on Dexie. The rest was quite straightforward - the app logic is simple, and what took the longest was making the app pretty and the animations smooth.</p>
<p>I think the result is quite good - definitely not professional, but more than enough for a hobby app. I learned a lot working on it and would definitely do it again. In case you missed it, <a href="https://pocketcompanion.fantinel.dev">here&#39;s another link to check out the result</a>, and its <a href="https://github.com/matfantinel/acnh-pocket-companion">source code</a>.</p>
<p>Thanks for reading!</p>

          ]]></content:encoded>
          <media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://rsinfo.vercel.app/images/posts/ionic-animal-crossing-companion/cover.jpg"/>
          <media:content xmlns:media="http://search.yahoo.com/mrss/" medium="image" url="https://rsinfo.vercel.app/images/posts/ionic-animal-crossing-companion/cover.jpg"/>          
        </item>
      
        <item>
          <guid>https://rsinfo.vercel.app/2019-year-in-review</guid>
          <title>Cool things I did and learned in 2019</title>
          <description>A quick look back at 2019 and what I learned during this year.</description>
          <link>https://rsinfo.vercel.app/2019-year-in-review</link>
          <pubDate>Sun, 29 Dec 2019 00:00:00 +0000</pubDate>
          
          <content:encoded><![CDATA[
            <div style="margin: 50px 0; font-style: italic;">
              If anything looks wrong, 
              <strong>
                <a href="https://rsinfo.vercel.app/2019-year-in-review">
                  read on the site!
                </a>
              </strong>
            </div>

            <p>Another year went by - Year 6 of my software development journey! I wanted to write this blog post to sum up stuff that I&#39;ve done or learned this year. Keep in mind this is being written off the top of my head - I did not keep a journal throughout the year, but hopefully that&#39;s something I&#39;ll do in 2020.</p>
<h2 id="complexity-is-your-enemy">Complexity is your enemy</h2>
<p>As programmers, we are puzzle-solvers. We like to think outside the box, applying different concepts, putting all of those nice things we&#39;ve learned everywhere. This.... often backfires. Most of the time what works best are the simplest solutions, which are also easier to maintain in the future by you or others. I&#39;ve seen this quote somewhere a while back: &quot;Programmers spend the first years of their careers mastering complexity only to realize they should master simplicity instead&quot;. I guess I&#39;m not in my first years anymore?</p>
<p>I&#39;ve changed my process in writing code to this:</p>
<ol>
<li>Understand the problem/goal;</li>
<li>Draw a simple mental picture of how to solve it (really simplify it);</li>
<li>Code in small steps and test them as you go;</li>
<li>Make it work. Code can look quite ugly in this step;</li>
<li>Optimize it, performance-wise;</li>
<li>⭐️ Try to explain how it works to yourself (mentally or by text), and then refactor the code to be as simple as possible;</li>
</ol>
<p>This last step might make the initial release take a little longer, but oh boy does it pay off whenever you or someone else has to maintain it.</p>
<h2 id="vanilla-js-is-the-best">Vanilla JS is the best</h2>
<p>Wait, I&#39;m not saying you shouldn&#39;t use any framework. If it helps you do your work better, go ahead! But &quot;Vanilla&quot; JS has come such a long way and there are so many amazing APIs coming out that using it solely is a valid option again. But more than that, those APIs are built in a way that popular frameworks can use them and communicate with each other with little effort. I&#39;ve covered a bit of this on <a href="https://rsinfo.vercel.app/microfrontends/">my Microfrontends post</a>, but there are more APIs that I&#39;ve discovered this year that are pretty awesome:</p>
<ul>
<li><a href="https://rsinfo.vercel.app/microfrontends/">Web Components/Shadow DOM/Custom Elements</a>;</li>
<li><a href="https://rsinfo.vercel.app/web-workers/">Web Workers</a>;</li>
<li><a href="https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API">IntersectionObserver</a>;</li>
<li>Not exactly new, but <a href="https://rsinfo.vercel.app/what-are-pwas-and-why-should-i-care-about-them/">PWAs</a> are increasingly awesome;</li>
</ul>
<h2 id="jekyll">Jekyll</h2>
<p>I&#39;m a bit late to the party, but this is still something I&#39;ve found out about in 2019. This website/blog you&#39;re seeing is built on top of Jekyll, a tool for making static websites.</p>
<p>Basically, you have HTML, CSS and JS. Add some special powers for using variables/loops inside that HTML code and ta-da! It works. Jekyll also allows you to create pages from Markdown (.md) files. I use it for blog posts like this one.</p>
<p>Since it&#39;s a static website, it means the code that&#39;s served to users/visitors is compiled just once and then served as HTML files. No servers or APIs necessary. It&#39;s pretty cool. You can check more about Jekyll <a href="https://jekyllrb.com/">here</a> and can check the source code for my website <a href="https://github.com/matfantinel/fantinel.dev">here</a>.</p>
<h2 id="open-source-is-awesome">Open Source is awesome</h2>
<p>I have released two open-source apps this year for elementaryOS (<a href="https://github.com/matfantinel/reminduck">Reminduck</a> and <a href="https://github.com/matfantinel/moneta">Moneta</a>). I gotta say, besides the fact that I was learning an entirely different development stack (Vala, GTK, Desktop native), the best &quot;new&quot; thing I enjoyed was doing it in the open.</p>
<p>These are not complex, commercial apps or anything like that. They&#39;re small utilities that I use on a daily basis and that were made open and released in hopes of helping anyone out there too. And I gotta say, having users like your software is great, but having them actively contribute to it is even better. As soon as they were released/made public, I started receiving pull requests, bug reports, feature requests, and translations from everywhere. <strong>It&#39;s so amazing that people from all over the world took interest in my little idea and helped improve them any way they could.</strong></p>
<p>But open source is not just other people contributing to your projects, it&#39;s also the opposite! I can improve other people&#39;s apps that I use, I can report bugs openly and help out, or just download the source code, change a few things just to fit my workflow better and run it. And not only apps, I can do that with the entire OS I run on my PC! Not to mention having access to other people&#39;s code allows you to learn from their work and saves you tons of time. Having a problem on your app and you know one that has solved that? Just check out what they did. Copy it, modify it, learn it, ship it. It&#39;s all good. <span>We wouldn't have to spend so much time reinventing wheels if more of our code was open.</span></p>
<p>Ah, this website is also open source. I used others as inspiration and took some code snippets too! So can you, feel free to fork it and modify anyway you want.</p>
<h2 id="working-remotely-is-fun-at-least-for-some-people">Working remotely is fun, at least for some people</h2>
<p>In August I started working remotely for the first time. I work from my home in Brazil with people from US, Europe and India. It was definitely refreshing to not have to commute and always be at a place that makes you feel good. Not only that, but the flexible hours allow me to work whenever I want and I can enjoy things that weren&#39;t possible on a regular &quot;9 to 5&quot; routine.</p>
<p>Although... I end up working the same hours as I did before. It feels &quot;right&quot; to work at this time, and I can enjoy my family at night, since they also work during the day. But it&#39;s nice to have the flexibility to have a break and a coffee somewhere else during the day if needed.</p>
<p>One of the main things people say about working from home is that sometimes it&#39;s hard to separate work time from free time. Fortunately, I didn&#39;t have that issue. My apartment is quite small, so I don&#39;t have a proper office and instead work on a desk on my bedroom, which means the temptation of lying down and sleeping is always beside me. I&#39;m so thankful I am able to resist that and get work done. And after work hours I can fully disconnect from it and not be stressed out, even if I stay on the computer. I totally understand why some people would not enjoy this and would be less productive, fortunately I was not the case.</p>
<p>The one thing I&#39;d say is worse in my case is communication. I&#39;m not an extremely social person - therefore I don&#39;t miss chitchat during the day with colleagues or anything like that. It&#39;s just that it&#39;s harder to explain code and concepts over a call or screen share. Not everyone is always readily available to explain things because of different timezones, so you have to figure more things out on your own. It&#39;s still doable though, and the days of &quot;just coding&quot; without interruptions are a dream. The pros outweight the cons.</p>
<h2 id="theres-never-enough-time">There&#39;s never enough time</h2>
<p>This year, I started getting into writing more open source software and started working from home. The latter means I can work more on house chores since there&#39;s no commute and I&#39;m always around! Still, there&#39;s never enough time for me to do what I want to do. I took time to write some elementaryOS apps, but I want to do some web apps too, and code some more, and play some games, watch series, movies, hang out with family, work, write on this blog, oof. This isn&#39;t a new discovery by any means, but I feel like it&#39;s getting worse every year. This is adult life, I guess.</p>
<h2 id="wrapping-up">Wrapping up</h2>
<p>Anyway, 2019 was a good year. I (of course) hope to do more and better in 2020, hopefully including more articles here. Hope you all have some nice holidays and a great new year!</p>

          ]]></content:encoded>
          <media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://rsinfo.vercel.app/images/posts/2019-year-in-review/cover.jpg"/>
          <media:content xmlns:media="http://search.yahoo.com/mrss/" medium="image" url="https://rsinfo.vercel.app/images/posts/2019-year-in-review/cover.jpg"/>          
        </item>
      
        <item>
          <guid>https://rsinfo.vercel.app/web-workers</guid>
          <title>Web Workers - Bringing Multithreading to the Front-End</title>
          <description>Improve your client-side performance by breaking heavy operations into multiple threads - backend style.</description>
          <link>https://rsinfo.vercel.app/web-workers</link>
          <pubDate>Wed, 14 Aug 2019 00:00:00 +0000</pubDate>
          
          <content:encoded><![CDATA[
            <div style="margin: 50px 0; font-style: italic;">
              If anything looks wrong, 
              <strong>
                <a href="https://rsinfo.vercel.app/web-workers">
                  read on the site!
                </a>
              </strong>
            </div>

            <p>In times of complex, feature-filled front-ends, we often get reports of freezes, frame drops, or overall slugginess in our apps. This is due to JavaScript&#39;s default behavior - a single thread is responsible for the interface, animations, and whatever CPU-intensive logic or I/O your app is doing.</p>
<p>This is because when JavaScript was created, back in 1995, it was never meant to be such a capable language, powering complex systems and heavy loads.</p>
<p>Usually, the best idea is to perform CPU-intensive work on the back-end, usually with a more performant language. This makes the experience similar to everyone, as it won&#39;t require much power from the user&#39;s machine. However, there are cases where we need to do this on the front-end, such as (but not limited to):</p>
<ul>
<li>Heavy filtering of data;</li>
<li>Conversions (like printing data to a PDF);</li>
<li>Deserializing huge and complex objects or arrays;</li>
<li>Complex calculations, like 3D objects for example.</li>
</ul>
<p>All of these heavy operations would cause the main thread - responsible for drawing your interface quickly and playing your animations smoothly - to not be that smooth.</p>
<p>This is where our star of the day comes in - Web Workers.</p>
<h2 id="what-do-these-web-workers-do">What do these Web Workers do?</h2>
<p>Imagine you are the boss (main thread). You call one of your employees (a worker) and tell them to do a specific task (a function). Then they go back to their own room (another thread) to do what you asked. In the meantime, you can do whatever you want, and as soon as your employee finishes the task, it comes back to you with the result. Now, in real life things aren&#39;t that simple, but you get the main idea, right?</p>
<p>Let&#39;s make something clear: Web Workers are an universal JavaScript feature, not limited to any specific framework. <a href="https://caniuse.com/#search=Worker">It even works on IE10+</a>!!! Pretty much the only requirement is that the worker logic stays in a different js file (worker.js, for example).</p>
<h2 id="lets-try-it-out">Let&#39;s try it out</h2>
<p><a href="https://github.com/mdn/simple-web-worker">Mozilla Developer Network (MDN)</a> has a great, simple example of how to use them. I&#39;ll explain it below:</p>
<p>First of all, on our main.js file, we need to create our Worker object, passing our Worker file as a parameter:</p>
<pre><code class="language-javascript">~filename main.js
if (window.Worker) {
    //just to make sure our browser supports it
    const myWorker = new Worker(&#39;worker.js&#39;);
}
</code></pre>
<p>The main thread is able to communicate with workers using the <code>postMessage</code> and <code>onMessage</code> functions.</p>
<p>Let&#39;s make our worker multiply two numbers for us!</p>
<pre><code class="language-javascript">~filename main.js
// we pass an array with all the parameters we want
myWorker.postMessage([123, 456]);
</code></pre>
<p>And then listen to a message sent back from our worker:</p>
<pre><code class="language-javascript">~filename main.js
myWorker.onmessage = function (e) {
    result.textContent = e.data;
};
</code></pre>
<p>We are now successfully passing and receiving data to/from our worker. Now, for the worker.js file:</p>
<pre><code class="language-javascript">~filename worker.js
onmessage = function (e) {
    let result = e.data[0] * e.data[1];
    postMessage(result);
};
</code></pre>
<p>Very simple, right? The multiplication was done in a different thread, and therefore did not interfere with our main thread. Keep in mind though, that <strong>setting up a Worker, starting another thread and passing parameters still take up minor resources from the main thread</strong>. For simple examples like this, performance will likely be worse than before. <strong>Web Workers are made for heavy tasks, so don&#39;t just use them everywhere</strong>.</p>
<h2 id="just-a-last-little-thing">Just a last little thing...</h2>
<p>When trying it out locally, you may find that your code... does not work. Neither Chrome nor Firefox allow running worker files from a local file system. This means that you have to be running your website in some sort of HTTP server in order for it to work.</p>
<p>If you have Python installed (most Linux or MacOS systems already do), just run: <code>python -m SimpleHTTPServer 8000</code> and you&#39;re good to go. You can access your files through localhost:8000.</p>
<p>If you don&#39;t, you can also use <a href="https://chrome.google.com/webstore/detail/web-server-for-chrome/ofhbbkphhbklhfoeikjpcbhemlocgigb">this Chrome extension</a> or any other method you prefer.</p>
<p>Thanks for reading!</p>

          ]]></content:encoded>
          <media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://rsinfo.vercel.app/images/posts/web-workers/cover.jpg"/>
          <media:content xmlns:media="http://search.yahoo.com/mrss/" medium="image" url="https://rsinfo.vercel.app/images/posts/web-workers/cover.jpg"/>          
        </item>
      
        <item>
          <guid>https://rsinfo.vercel.app/mongodb-error-datadb-on-linux</guid>
          <title>MongoDB on Linux - Data directory /data/db not found</title>
          <description>Fix the error that occurs when trying to run freshly-installed MongoDB on a Linux machine.</description>
          <link>https://rsinfo.vercel.app/mongodb-error-datadb-on-linux</link>
          <pubDate>Sun, 09 Jun 2019 00:00:00 +0000</pubDate>
          
          <content:encoded><![CDATA[
            <div style="margin: 50px 0; font-style: italic;">
              If anything looks wrong, 
              <strong>
                <a href="https://rsinfo.vercel.app/mongodb-error-datadb-on-linux">
                  read on the site!
                </a>
              </strong>
            </div>

            <p>When setting up a Linux server or development machine, you might need to install MongoDB. However, every single time I&#39;ve stumbled upon an error right when trying to start the <code>mongod</code> service, after following <a href="https://docs.mongodb.com/manual/tutorial/install-mongodb-on-ubuntu/">the official instructions</a>. The important line here is:</p>
<blockquote>
<p>[!error]
exception in initAndListen: NonExistentPath: Data directory /data/db not found., terminating</p>
</blockquote>
<p>This seems like an error on Mongo&#39;s install script. The problem is that by default, Mongo points to that <code>/data/db</code> folder, and it either forgets to create or set ownership of it on installation.</p>
<p>Thankfully, the solution is quite simple. First, we&#39;ll make sure that the folder in question exists. Run the following command from your Terminal:</p>
<pre><code class="language-shell">sudo mkdir -p /data/db/
</code></pre>
<p>And then, we&#39;ll set the ownership of the folder to the user that&#39;s going to start the mongod service. Since I only use if for local development in my computer, I set myself as the owner:</p>
<pre><code class="language-shell">sudo chown `id -u` /data/db
</code></pre>
<p>Now, just running <code>mongod</code> should do the job.</p>
<p>Thanks for reading!</p>

          ]]></content:encoded>
          <media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://rsinfo.vercel.app/images/posts/mongodb-error-datadb-on-linux/cover.jpg"/>
          <media:content xmlns:media="http://search.yahoo.com/mrss/" medium="image" url="https://rsinfo.vercel.app/images/posts/mongodb-error-datadb-on-linux/cover.jpg"/>          
        </item>
      
        <item>
          <guid>https://rsinfo.vercel.app/net-core-project-restored-different-version</guid>
          <title>.NET Core - Project version mismatch</title>
          <description>Solving this cryptic error might take you many hours. Hopefully this will help you out.</description>
          <link>https://rsinfo.vercel.app/net-core-project-restored-different-version</link>
          <pubDate>Mon, 03 Jun 2019 00:00:00 +0000</pubDate>
          
          <content:encoded><![CDATA[
            <div style="margin: 50px 0; font-style: italic;">
              If anything looks wrong, 
              <strong>
                <a href="https://rsinfo.vercel.app/net-core-project-restored-different-version">
                  read on the site!
                </a>
              </strong>
            </div>

            <p>This problem usually happens when you&#39;re working on a solution with multiple projects that were created using different versions of the .NET SDK.</p>
<blockquote>
<p>[!error]
The project was restored using Microsoft.NETCore.App version x.x.x, but with current settings, version y.y.y would be used instead</p>
</blockquote>
<p>You may encounter this error when running <code>dotnet build</code> or maybe only on <code>dotnet publish</code>. In any case, the best way to get rid of this problem for good is the following:</p>
<ol>
<li>On the folder where your <code>.sln</code> file resides, create a new file named <code>Directory.Build.props</code>. If you&#39;re not working with a solution (not using Visual Studio), you can use create it on the root directory of your repository (usually where <code>.gitignore</code> is;</li>
<li>With a text editor, add the following content to it:</li>
</ol>
<pre><code class="language-xml">~filename Directory.Build.props
&lt;Project&gt;
  &lt;PropertyGroup&gt;
    &lt;TargetLatestRuntimePatch&gt;true&lt;/TargetLatestRuntimePatch&gt;
    &lt;GenerateFullPaths&gt;true&lt;/GenerateFullPaths&gt;
    &lt;LangVersion&gt;latest&lt;/LangVersion&gt;
  &lt;/PropertyGroup&gt;
&lt;/Project&gt;
</code></pre>
<p>What these properties do is make your projects always restore and compile using the latest version available.</p>
<p>Try running the command again. If all went right, it should be compiling successfully now!</p>
<blockquote>
<p>[!info]
In case it doesn&#39;t work for you, you can add these lines manually on each of the <code>.csproj</code> files.</p>
</blockquote>
<p>Thanks for reading!</p>

          ]]></content:encoded>
          <media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://rsinfo.vercel.app/images/posts/net-core-project-restored-different-version/cover.jpg"/>
          <media:content xmlns:media="http://search.yahoo.com/mrss/" medium="image" url="https://rsinfo.vercel.app/images/posts/net-core-project-restored-different-version/cover.jpg"/>          
        </item>
      
        <item>
          <guid>https://rsinfo.vercel.app/open-source-x-free-software</guid>
          <title>Open Source x Free Software: What's the difference?</title>
          <description>Learn the difference between these two terms that often get mixed up.</description>
          <link>https://rsinfo.vercel.app/open-source-x-free-software</link>
          <pubDate>Sat, 23 Mar 2019 00:00:00 +0000</pubDate>
          
          <content:encoded><![CDATA[
            <div style="margin: 50px 0; font-style: italic;">
              If anything looks wrong, 
              <strong>
                <a href="https://rsinfo.vercel.app/open-source-x-free-software">
                  read on the site!
                </a>
              </strong>
            </div>

            <p>Free software is a concept that&#39;s been around for a long time, and so is open source. At first glance, they may seem like the same thing with different names. However, they are very different in their philosophy. In this article, I&#39;ll explain what each one is and how they are different.</p>
<h2 id="free-software">Free Software</h2>
<p>According to the <a href="https://www.fsf.org/">Free Software Foundation (FSF)</a>, free software is the software that respects the user&#39;s freedom and sense of community. This means that the user has the freedom to run, copy, distribute, study, change and improve it.</p>
<p>A common phrase you may read somewhere is &quot;Free as in freedom, not as in beer&quot;. This means that the name doesn&#39;t indicate that the software is free of charge, only that the user has the freedom to do whatever they want with it.</p>
<p>The FSF lists four essential freedoms that every free software must follow:</p>
<ul>
<li>The freedom to run the program as you wish, for any purpose (freedom 0);</li>
<li>The freedom to study how the program works, and change it so it does your computing as you wish (freedom 1). Access to the source code is a precondition for this;</li>
<li>The freedom to redistribute copies so you can help others (freedom 2);</li>
<li>The freedom to distribute copies of your modified versions to others (freedom 3). By doing this you can give the whole community a chance to benefit from your changes. Access to the source code is a precondition for this.</li>
</ul>
<p>You can read more about Free Software at gnu.org, <a href="https://www.gnu.org/philosophy/free-sw.en.html">here</a>.</p>
<h2 id="open-source">Open Source</h2>
<p>The <a href="https://opensource.org/">Open Source Initiative</a> defines 10 criteria for software to be considered open source. You can read them fully <a href="https://opensource.org/docs/definition.php">here</a>. I&#39;ll summarize them below:</p>
<ul>
<li>Any person must be able to distribute or sell the software without restrictions;</li>
<li>The source code must be distributed along with the software, or at least link to it clearly;</li>
<li>A copy of the license must be distributed with the software;</li>
<li>People must be able to modify your software and redistribute it with the same license;</li>
<li>Modifications must only be redistributed with a different name or version than the original code;</li>
</ul>
<h2 id="the-difference">The Difference</h2>
<p>By reading each concept&#39;s principles above, you can get the idea that Open Source is a more neutral concept when compared to Free Software. It does not deal with the user&#39;s freedom, only with the technical aspects of the software. Richard Stallman, the founder on FSF, summarized really well the differences between the two concepts:</p>
<blockquote>
<p>The terms “free software” and “open source” stand for almost the same range of programs. However, they say deeply different things about those programs, based on different values. The free software movement campaigns for freedom for the users of computing; it is a movement for freedom and justice. By contrast, the open source idea values mainly practical advantage and does not campaign for principles. - Richard Stallman</p>
</blockquote>
<p>You can read more about it <a href="https://www.gnu.org/philosophy/open-source-misses-the-point.en.html">here</a>.</p>
<h2 id="tldr">TL;DR</h2>
<p>Open Source is a technical, practical concept. Free Software is a philosophical, broader concept. Since Free Software already considers the technical aspects of Open Source, we can say that <strong>Every Free Software is Open Source, but not every Open Source is Free Software</strong>.</p>
<h3 id="how-to-know-if-an-open-source-software-is-free-software">How to know if an Open Source software is Free Software?</h3>
<p>The easiest way is to check their license. <a href="https://www.gnu.org/licenses/license-list.html#SoftwareLicenses">The FSF lists all Free Software licenses here</a>, but usually most of them are under the GPL or MIT licenses.</p>
<p>Thanks for reading!</p>

          ]]></content:encoded>
          <media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://rsinfo.vercel.app/images/posts/open-source-x-free-software/cover.jpg"/>
          <media:content xmlns:media="http://search.yahoo.com/mrss/" medium="image" url="https://rsinfo.vercel.app/images/posts/open-source-x-free-software/cover.jpg"/>          
        </item>
      
        <item>
          <guid>https://rsinfo.vercel.app/microfrontends</guid>
          <title>Micro Frontends: Solving the Legacy JavaScript Problem</title>
          <description>Finally a way to modernize that legacy project you keep complaining about!</description>
          <link>https://rsinfo.vercel.app/microfrontends</link>
          <pubDate>Sun, 17 Mar 2019 00:00:00 +0000</pubDate>
          
          <content:encoded><![CDATA[
            <div style="margin: 50px 0; font-style: italic;">
              If anything looks wrong, 
              <strong>
                <a href="https://rsinfo.vercel.app/microfrontends">
                  read on the site!
                </a>
              </strong>
            </div>

            <p>It&#39;s a running joke in the development community that if a JS programmer goes into a coma for 6 months, he will need to learn everything again by the time he wakes up. This is a consequence of JavaScript&#39;s open, decentralized nature. It&#39;s both a blessing and a curse.</p>
<p>All the time there are new frameworks and libraries meant to make it easier to develop in JS, at least for a specific use. Sometimes they are effectively better, sometimes they just bring a new workflow, and as a developer it can be quite fun to learn them and explore new paradigms.</p>
<p>However, in the &quot;enterprise world&quot;, reality is different. We build big, complex applications that usually rely on a framework&#39;s properties to work the way they do. Recent frameworks like React, Vue and Angular offer an easy way to break an application in smaller, more independent chunks that can be maintained separately, but they still rely on the main framework&#39;s version.</p>
<p>Front-end development is becoming more and more like back-end development, with more complex architectures. Naturally, the concept of microservices was brought over and is being called Micro Frontends.</p>
<h2 id="what-do-micro-frontends-consist-of">What do Micro Frontends consist of?</h2>
<p>First, we must define what monolithic frontends are. You probably work on one of them, since they are basically every web app that is made with a specific framework and version, and only works by itself without resorting to redirects and iframes. Hence the monolith-derived name.</p>
<p>Micro Frontends, however, can be made of several pieces of different technologies - all in a &quot;central&quot; app that puts the puzzle pieces together.</p>
<p>Since frameworks like React and Angular are already very popular, the concept of componentizing our apps is well known, and it&#39;s basically what Micro Frontends consist of. It uses the Custom Elements API, a web standard that is being implemented by all major browsers (with polyfills for older ones!), to provide a common ground between different components written in Angular, React, Vue, or even good old pure JS!</p>
<p>To do that, they work in a similar way modern frameworks do, with an Input/Output pattern and a very simple way to import them into the parent&#39;s HTML. We&#39;ll see more about this later.</p>
<h2 id="how-does-that-solve-the-legacy-problem">How does that solve the legacy problem?</h2>
<p>You&#39;ve probably already worked on a big app that was made years ago, and used &quot;ancient&quot; technology. If you haven&#39;t, lucky you! But in many enterprise environments, working with JQuery, KnockoutJS, AngularJS (v1.x) or even older JS technologies is the norm. While usually there is willingness to update the tech stack in order to gain more productivity and performance, it is usually not feasible to update an entire behemoth all at once. Add the fact that companies and their products must move fast with features and changes, and the chance to update is close to zero.</p>
<p>One alternative is to create a second app with a new technology and make the change in multiple steps, with routes handling which app is to be shown. This however, has many issues:</p>
<ul>
<li>You have to duplicate many things, like fixed menus, authentication handling, and all the base architecture. Even worse than duplicating is <strong>maintaining</strong> both of them afterwards;</li>
<li>The user experience will be severely harmed when your app redirects to a different one frequently;</li>
<li>When the new technology you use becomes obsolete, you&#39;ll have to deal with the problem all over again.</li>
</ul>
<p>Other alternative is to use iframes, which brings a lot of problems since communication between both pages is not very straightforward and the experience feels clunky. Not very good.</p>
<p>However, when using Micro Frontends, you are able to:</p>
<ul>
<li>Migrate technologies in small steps:</li>
<li>Communication between both technologies is easy;</li>
<li>The user does not notice the use of two different stacks - they all merge seamlessly in the same experience;</li>
<li>There is no need to maintain more than one version of a component;</li>
<li>Encourages good use of components and code reuse.</li>
</ul>
<p>At my job, we had our main application written in AngularJS, and since it was a pretty huge application, migrating to a newer stack was just not feasible. We then had a project that included a complete overhaul of the design of the application, we felt it was a good time to use newer technologies.</p>
<p>Since we had a side project written in Angular 6 and most of us had knowledge of this framework, we decided to write new components for our main app in Angular 7. While the plan was to update the entire app, rewriting it entirely and publishing all at once would bring a lot of problems.</p>
<p>We then decided to use the Micro Frontends approach, rewriting our pages/components one by one and releasing it in &quot;packages&quot;. We did that by creating Custom Elements in Angular 7 and integrating them with the older AngularJS app. Since we would be modernizing entire pages at once, there wouldn&#39;t be many changes on the older app. The tried-and-tested older app was still responsible for managing routes and authentication, and would just display our newer components as they were built. <em>This proved to be a successful approach that allowed us to both modernize our tech stack, minimize user impact, we kept delivering value to our customers and, since the project was broken in smaller pieces, we had flexibility to tackle other projects in between.</em></p>
<h2 id="how-do-they-work-in-practice">How do they work in practice?</h2>
<p>For this article, I am going to create a custom element with Angular 7 and use it in a simple html file. I&#39;ve created a sample app on GitHub. <a href="https://github.com/matfantinel/custom-elements-sample">You can check the full code here.</a></p>
<h3 id="creating-the-custom-element">Creating the Custom Element</h3>
<p>First, we create a new Angular 7 app:</p>
<pre><code class="language-shell">ng new angular-elements-sample --prefix custom
</code></pre>
<p>The CLI will ask you for some settings, you can choose whatever you like. Since we&#39;re just using Custom Components in this example, I chose not to apply Angular routing.</p>
<p>Then, we need to add the Angular package that brings Custom Elements support:</p>
<pre><code class="language-shell">ng add @angular/elements
</code></pre>
<p>Now, on tsconfig.json file, change target to &quot;es2015&quot;.</p>
<pre><code class="language-json">{
  &quot;compileOnSave&quot;: false,
  &quot;compilerOptions&quot;: {
    ...
    &quot;target&quot;: &quot;es2015&quot;,
    ...
  }
}
</code></pre>
<p>Then, create a new component in your app:</p>
<pre><code class="language-shell">ng g component button
</code></pre>
<p>On this component, we should set its encapsulation to ShadowDom. This means that its styles will be limited to itself, and styles from the parent application won&#39;t apply to the child component, or vice-versa. Also, we&#39;ll be declaring an Input() property, that the element will receive from the parent, and a CustomEvent, a way to communicate events with other applications/components in the same page.</p>
<p>Below is the full component Typescript code:</p>
<pre><code class="language-typescript">~filename button.component.ts
import { Component, OnInit, ViewEncapsulation, Input, ElementRef } from &#39;@angular/core&#39;;

@Component({
    selector: &#39;custom-button&#39;,
    templateUrl: &#39;./button.component.html&#39;,
    styleUrls: [&#39;./button.component.scss&#39;],
    encapsulation: ViewEncapsulation.ShadowDom
})
export class ButtonComponent implements OnInit {
    @Input() label = &#39;Default Label&#39;;
    private clicksCount: number = 0;

    htmlElement: HTMLElement;

    constructor(public hostElement: ElementRef) {
        this.htmlElement = this.hostElement.nativeElement as HTMLElement;
    }

    ngOnInit() {}

    handleClick = () =&gt; {
        this.clicksCount++;
        let action = new CustomEvent(&#39;action&#39;, {
            detail: {
                clicksCount: this.clicksCount
            }
        });
        this.htmlElement.dispatchEvent(action);
    };
}
</code></pre>
<p>The HTML template is very simple:</p>
<pre><code class="language-html">&lt;button (click)=&quot;handleClick()&quot;&gt;{{ label }}&lt;/button&gt;
</code></pre>
<p>Then, we must declare our Custom Element in our app.module.ts file:</p>
<pre><code class="language-typescript">~filename app.module.ts
@NgModule({
    declarations: [...ButtonComponent],
    entryComponents: [ButtonComponent],
    providers: [],
    bootstrap: []
})
export class AppModule {
    constructor(private injector: Injector) {}

    ngDoBootstrap() {
        //Declares our component&#39;s Custom Element
        //Then defines it in the DOM so it can be used in other projects
        const buttonElement = createCustomElement(ButtonComponent, { injector: this.injector });
        customElements.define(&#39;custom-button&#39;, buttonElement);
    }
}
</code></pre>
<p>To make it easier to use our component in another app, we can use some script magic to concat all the .js files produced by <code>ng build --prod</code> into a single properly-named file. To do that, I created the following script in package.json&#39;s script session:</p>
<pre><code class="language-json">~filename package.json
&quot;package&quot;: &quot;ng build --prod &amp;&amp; cat ./dist/runtime.js ./dist/polyfills.js ./dist/scripts.js ./dist/main.js &gt; CustomElementsSample.js&quot;
</code></pre>
<p>If you&#39;re on a Windows system, you won&#39;t have access to cat. In that case install <code>jscat</code> from npm and change the cat command to jscat.</p>
<p>For that to work though, we need to disable output hashing on the angular.json file. This makes sure that the generated file names are always the same. Just change <code>&quot;outputHashing&quot;: &quot;all&quot;</code> to <code>&quot;outputHashing&quot;: &quot;none&quot;</code>.</p>
<p>Now we have a single js file that contains our custom element, and we can use it in our sample legacy app!</p>
<h3 id="using-the-custom-element">Using the Custom Element</h3>
<p>Check this sample html file:</p>
<pre><code class="language-html">&lt;html&gt;
    &lt;head&gt;
        &lt;meta charset=&quot;UTF-8&quot; /&gt;
        &lt;title&gt;This is a legacy app that uses Angular 7 custom elements&lt;/title&gt;
        &lt;script src=&quot;../angular-elements-sample/CustomElementsSample.js&quot;&gt;&lt;/script&gt;

        &lt;style&gt;
            button {
                background-color: red;
                color: white;
            }
        &lt;/style&gt;
    &lt;/head&gt;
    &lt;body&gt;
        &lt;custom-button label=&quot;Legacy app label&quot;&gt;&lt;/custom-button&gt;
        &lt;span id=&quot;counter&quot;&gt;&lt;/span&gt;&lt;span&gt; clicks!&lt;/span&gt;

        &lt;script&gt;
            const button = document.querySelector(&#39;custom-button&#39;);
            button.addEventListener(&#39;action&#39;, (event) =&gt; {
                document.getElementById(&#39;counter&#39;).innerHTML = event.detail.clicksCount;
            });
        &lt;/script&gt;
    &lt;/body&gt;
&lt;/html&gt;
</code></pre>
<p>You can see that we are successfully being able to listen for events, pass the label parameter, and that the button style from the html does not apply to the component. Success!</p>
<h2 id="caveats">Caveats</h2>
<p>As with all things, there are some disadvantages in this approach:</p>
<h3 id="browser-support">Browser Support</h3>
<p>![Screenshot of Can I Use website, showing that Custom Elements work on current versions of Chrome and Firefox, but not IE and Edge, and is only partially supported on Safari.](/images/posts/microfrontends/Browser-Support.jpg &#39;You can check this information on the <a href='https://caniuse.com/custom-elementsv1' target='_blank'>Can I Use</a> website.&#39;)</p>
<p>As of March 2019, only Firefox, Chrome and Chromium-based browsers fully support custom elements, while Safari implements them only partially. However, <a href="https://github.com/webcomponents/custom-elements">there&#39;s a polyfill available</a> to bring support to older browsers.</p>
<h3 id="js-bundle-size">JS Bundle size</h3>
<p>Since you&#39;re running components using other frameworks, you&#39;ll still have to load them on the user&#39;s side. If your app uses AngularJS, Angular, JQuery and React in different components, you&#39;ll have to load all their runtimes before the app is fully functional. In this case, your better option is to minimize the bundle as much as possible, and use <a href="https://rsinfo.vercel.app/what-are-pwas-and-why-should-i-care-about-them">Service Workers and PWA capabilities</a> to improve caching on your app.</p>
<h3 id="communication-between-components-is-not-as-good-as-within-the-same-framework">Communication between components is not as good as within the same framework</h3>
<p>This should not be much of an issue unless you break a page into too many components with different technologies. Even then, communication with other components is very doable, just not as good as it would be between Angular-Angular or React-React components.</p>
<h2 id="wrapping-up">Wrapping up</h2>
<p>Micro Frontends are a consequence of the complexicity that front-end has developed in the last few years. It is very good to see technology move forward, and we may get lost amidst so much change, so it is good to know that we don&#39;t have to be afraid to not migrate our apps to the latest and greatest. They bring us the advantages of newer frameworks while minimizing the disadvantages.</p>
<p>Thanks for reading!</p>

          ]]></content:encoded>
          <media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://rsinfo.vercel.app/images/posts/microfrontends/cover.jpg"/>
          <media:content xmlns:media="http://search.yahoo.com/mrss/" medium="image" url="https://rsinfo.vercel.app/images/posts/microfrontends/cover.jpg"/>          
        </item>
      
        <item>
          <guid>https://rsinfo.vercel.app/dotnet-core-405-error</guid>
          <title>.NET Core - Method not allowed on PUT and DELETE requests</title>
          <description>See how to solve this annoying error after deploying your .NET Core API.</description>
          <link>https://rsinfo.vercel.app/dotnet-core-405-error</link>
          <pubDate>Thu, 14 Mar 2019 00:00:00 +0000</pubDate>
          
          <content:encoded><![CDATA[
            <div style="margin: 50px 0; font-style: italic;">
              If anything looks wrong, 
              <strong>
                <a href="https://rsinfo.vercel.app/dotnet-core-405-error">
                  read on the site!
                </a>
              </strong>
            </div>

            <p>Recently, I&#39;ve been working on an Angular app, powered with a .NET Core API. Everything was working well and smoothly when running both on my local machine.</p>
<p>After pushing code to the beta server, most of it was working fine. The front-end was being able to call GET, POST and OPTIONS requests normally. When trying to DELETE or PUT entries, however, the following error would show up on the browser&#39;s console:</p>
<p><img src="https://rsinfo.vercel.app/images/posts/dotnet-core-405-error/post1.jpg" alt="405 (Method Not Allowed) | Access to XMLHttpRequest at &#39;...&#39; from origin &#39;...&#39; has been blocked by CORS policy: No &#39;Access-Control-Allow-Origin&#39; header is present on the requested resource."></p>
<p><em>Method not allowed? CORS error? What?</em></p>
<p>Initially, I was misled by the CORS error. Having had problems with this in the past, I thoroughly checked my API code for any possible problem in the configuration that could lead to this error only after deployed. I found none.</p>
<p>Then, it dawned on me that the CORS error could be not because my API wasn&#39;t sending the &#39;Access-Control-Allow-Origin&#39; on its response, but because it wasn&#39;t being sent on the HTTP 405 error seen above.</p>
<h2 id="solution">Solution</h2>
<p>I ended up finding <a href="https://www.ryadel.com/en/error-405-methods-not-allowed-asp-net-core-put-delete-requests/">this article</a>. What happens is that, when published, .NET Core enables the <em>WebDAVModule</em>, which <em>disables PUT and DELETE requests</em> by default.</p>
<p>So, to solve the issue, I ended up disabling WebDAV in the whole application, by adding these lines to the auto-generated web.config:</p>
<pre><code class="language-xml">~filename web.config
&lt;system.webServer&gt;
  &lt;modules runAllManagedModulesForAllRequests=&quot;false&quot;&gt;
    &lt;remove name=&quot;WebDAVModule&quot; /&gt;
  &lt;/modules&gt;
&lt;/system.webServer&gt;
</code></pre>
<p>After restarting the API in IIS, <span>TA-DA!</span> Everything (or at least your PUT and DELETE requests) should be working normally.</p>
<p>This issue seems to only occur when hosting .NET Core on Windows, which is why I could not simulate the issue by running my application in production mode on my Linux machine.</p>
<p>I hope this will be helpful to someone like it was for me!</p>

          ]]></content:encoded>
          <media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://rsinfo.vercel.app/images/posts/dotnet-core-405-error/cover.jpg"/>
          <media:content xmlns:media="http://search.yahoo.com/mrss/" medium="image" url="https://rsinfo.vercel.app/images/posts/dotnet-core-405-error/cover.jpg"/>          
        </item>
      
        <item>
          <guid>https://rsinfo.vercel.app/what-are-pwas-and-why-should-i-care-about-them</guid>
          <title>What are PWAs and why should I care about them?</title>
          <description>We see a lot of talk about PWAs, but the concept is not that easy to understand.</description>
          <link>https://rsinfo.vercel.app/what-are-pwas-and-why-should-i-care-about-them</link>
          <pubDate>Tue, 12 Mar 2019 00:00:00 +0000</pubDate>
          
          <content:encoded><![CDATA[
            <div style="margin: 50px 0; font-style: italic;">
              If anything looks wrong, 
              <strong>
                <a href="https://rsinfo.vercel.app/what-are-pwas-and-why-should-i-care-about-them">
                  read on the site!
                </a>
              </strong>
            </div>

            <p>Progressive Web Apps are not new, but they are becoming more and more popular everyday. Big companies like Facebook, Twitter and Google have been using them for a while, and while they&#39;re often designed for mobile, recent pushes from Microsoft and Chrome are making them a good option even for desktop.</p>
<p><a href="https://rsinfo.vercel.app/angular-pwa-how-to">I&#39;ve covered how you can turn your Angular 6+ app into a PWA here</a>. Now, let&#39;s see why you should do that.</p>
<h2 id="what-is-a-pwa">What is a PWA?</h2>
<p>Native apps, the ones that are designed to work specifically on Mobile/Desktop OSs, usually have some useful features, like access to the device&#39;s functionalities like camera, GPS, sending notifications, working offline, and so on. They also are able to utilize the device&#39;s full screen (on mobile), show up on the home screen, and are usually pretty fast to load.Web apps though, need to be accessed by a browser. This takes away some screen real estate, since the browser&#39;s UI is also shown. They cannot work offline, can only show up on the home screen as a shortcut to the browser, and usually take longer to load, since its assets need to be loaded from the web.</p>
<p>PWAs, or Progressive Web Apps, are basically websites that have the ability to deliver a native app-like experience, by sending notifications, offering a snappier and more responsive experience, working offline, etc. This is achieved with the use of modern Web APIs, and a little thing called <strong>Service Worker</strong>.</p>
<p><em>Please keep in mind that hybrid apps developed with Ionic, Cordova, or similar frameworks <strong>are not PWAs</strong>, since they are installed like a real app and have full access to the device.</em></p>
<h3 id="service-worker">Service Worker?</h3>
<p>A Service Worker is like a client-side proxy, written in Javascript, that powers offline functionality, push notifications, caching, updating, and more.</p>
<p>They can, for instance, listen for any http requests and handle them nicely, like retrieving cached data if there&#39;s no internet connection. To avoid problems with updates, since it caches content more aggressively, it can be configured to update itself everytime it sees there is a new version online. This avoids problems with users using older versions of our web apps (and therefore gets rid of native apps&#39; biggest nuisance).</p>
<p>This all may sound complicated, which is why there are many &quot;recipes&quot; of Service Workers around the web. They are still JavaScript files, so it&#39;s not hard to adapt and improve them at your own pace.</p>
<p>You probably have already found some of them in the wild. In Chrome for Android, opening a certain website might trigger this panel at the bottom of the screen:</p>
<p><img src="https://rsinfo.vercel.app/images/posts/what-are-pwas-and-why-should-i-care-about-them/install-prompt-android.jpg" alt="PWA Install Prompt on Android" title="Add Notepad to the home screen"></p>
<p>And on Desktop, this option shows up in the URL bar:</p>
<p><img src="https://rsinfo.vercel.app/images/posts/what-are-pwas-and-why-should-i-care-about-them/install-prompt.jpg" alt="Chrome prompts you to install PWA"></p>
<p>With this, your app is able to be displayed on your phone or PC&#39;s app list just like any other app. Cool!</p>
<p><em>Keep in mind that for now only a few Chromium-based browsers offer this functionality on Android. Firefox, sadly, is not allowed by Google to create WebAPKs (how these are called). Thanks, free market!</em> 🙄</p>
<h2 id="thats-nice-and-all-but-how-would-my-app-benefit-from-it">That&#39;s nice and all... But how would my app benefit from it?</h2>
<p>Let&#39;s get one thing out of the way first - <strong>PWAs are not a replacement for native apps</strong>. They have more limitations, and overall offer worse performance than a native app written in Java/Swift. Their purpose is to offer a better user experience for web apps that are used often by users. If you have a complex web app, and do not have the time/resources or simply don&#39;t think it&#39;s worth it to create a native counterpart, PWAs are for you. I will compare PWAs to hybrid apps, like the ones built on Ionic.</p>
<p>The first main advantage is that the entry barrier is lower. Research shows that <a href="https://techcrunch.com/2017/08/25/majority-of-u-s-consumers-still-download-zero-apps-per-month-says-comscore/">the majority of mobile users in the US download an average of 0 apps monthly</a>. That&#39;s zero. None. That may be because searching for an app in the app store may be a bit counterintuitive depending on the situation. Let&#39;s imagine that you have an hybrid app on the app store. Your new user probably found out about your app/service on its website, so they&#39;re already in the browser:</p>
<ol>
<li>Logs in to your app on the browser;</li>
<li>You detect that they&#39;re using a mobile phone, so you can show them a banner to download your app on the store;</li>
<li>They open the app store;</li>
<li>They try to download your app. Or, they might give up because they&#39;re on their limited data plan, and avoids downloading apps on it.</li>
<li>They can either return to the web app on the browser, with all the disavantadges mentioned before, or use your hybrid app.</li>
</ol>
<p>If the user has installed your app, cool! However, you must still keep one thing in mind: your app updates independently from your web app, and the updates will take longer. Some users might even disable autoupdates altogether. Depending on how your app works, you might suffer from users using outdated versions of the code, which might result in issues for them and for you.</p>
<p>Now let&#39;s imagine the same flow, but with a PWA:</p>
<ol>
<li>Logs in to your app on the browser;</li>
<li>A panel shows up on the bottom of their screen: &quot;Hey, add this to your home screen!&quot;;</li>
<li>The app is installed into the user&#39;s phone and can now be accessed from the app list, with better screen estate, better performance (because of caching), and easier to open;</li>
<li>Your app is always on-par with the web version.</li>
</ol>
<p>Another worthy thing to mention is that you don&#39;t have to go through the hassle of publishing an app on the app store!</p>
<h2 id="there-are-advantages-even-if-the-user-doesnt-install-your-web-app">There are advantages even if the user doesn&#39;t install your web app</h2>
<p>So far I&#39;ve covered how your app would benefit from users being able to install the app directly from the browser. But still, a lot of the PWA benefits still apply even if they don&#39;t.</p>
<p>Even when opened in a browser, a PWA can still offer:</p>
<ul>
<li>Better speed after first load, due to the more aggressive cacheing of the static content;</li>
<li>Less jankiness and more responsiveness overall, since the content will be loaded from the user&#39;s device instead of downloaded dynamically;</li>
<li>Won&#39;t be affected by variations in the user&#39;s connection.</li>
</ul>
<h2 id="how-can-i-convince-my-boss-to-let-me-work-on-this">How can I convince my boss to let me work on this?</h2>
<p>Well, every boss is different. But <a href="http://https//developers.google.com/web/progressive-web-apps/">Google provides some neat statistics that may help you in your endeavor</a>:</p>
<ul>
<li>Push notifications increase user engagement by up to 4 times;</li>
<li>Some use cases report that the increase in conversions after transitioning to a PWA was of 104%!</li>
</ul>
<h2 id="as-with-all-things-dont-overdo-it">As with all things, don&#39;t overdo it</h2>
<p>This article covered the concept and advantages of PWAs, but keep in mind that they are not for every use case. <strong>Use it for web apps that users will find themselves coming back to frequently</strong>. There&#39;s no point in doing it for your company&#39;s website or static websites. It&#39;s also worth remembering that <strong>PWAs do not replace native apps, they are just a lower-effort alternative for web apps without native counterparts</strong>.</p>
<p>It&#39;s also worth mentioning that the advantages cited in this article are, as of March 2019, <strong>fully supported only by Google Chrome/Chromium</strong>. Google&#39;s been pushing PWAs hardly lately and other companies still have some catching up to do. iOS 11.3 saw the addition of basic PWA capabilities on Safari, but some features still do not work. Firefox for Android also supports some PWA capabilities, but does not prompt the user the same way Chrome does (because Google won&#39;t allow it, may I add).</p>
<p>Thanks for reading!</p>

          ]]></content:encoded>
          <media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://rsinfo.vercel.app/images/posts/what-are-pwas-and-why-should-i-care-about-them/cover.jpg"/>
          <media:content xmlns:media="http://search.yahoo.com/mrss/" medium="image" url="https://rsinfo.vercel.app/images/posts/what-are-pwas-and-why-should-i-care-about-them/cover.jpg"/>          
        </item>
      
        <item>
          <guid>https://rsinfo.vercel.app/angular-pwa-how-to</guid>
          <title>How to transform your Angular 6+ app into a PWA</title>
          <description>Make your Angular app work like a native app on phones and desktop.</description>
          <link>https://rsinfo.vercel.app/angular-pwa-how-to</link>
          <pubDate>Sun, 10 Mar 2019 00:00:00 +0000</pubDate>
          
          <content:encoded><![CDATA[
            <div style="margin: 50px 0; font-style: italic;">
              If anything looks wrong, 
              <strong>
                <a href="https://rsinfo.vercel.app/angular-pwa-how-to">
                  read on the site!
                </a>
              </strong>
            </div>

            <p>Recently, I&#39;ve converted my Angular 6 app into a PWA, allowing it to work offline and work like a native app on phones and desktop.</p>
<p>Although there are many tutorials out there about turning Angular apps into PWAs, I&#39;ve decided to write one simply because I faced some issues that were a bit hard to solve, so if you end up having them you don&#39;t lose as much time as I did!</p>
<blockquote>
<p>[!info]
This tutorial assumes you are using Angular CLI. Possible issues are listed at the end of the tutorial.</p>
</blockquote>
<h2 id="step-1-installing-the-angular-pwa-dependencies">Step 1. Installing the Angular PWA dependencies</h2>
<p>This is the easiest part. Run <code>ng add @angular/pwa</code> in the root of your project (the folder where <code>package.json</code> is. The CLI will automagically add <code>@angular/pwa</code> and <code>@angular/service-worker</code> as dependencies in your package.json file, and add some placeholder icons in your <code>assets</code> folder.</p>
<p>Besides that, it will create a file named <code>ngsw-config.json</code> in your root folder, as well as a <code>manifest.json</code> in your /src folder, and reference both in <code>index.html</code> and <code>app.module.ts</code>. These files are important as you&#39;ll be using them to configure your PWA later.</p>
<h2 id="step-2-setting-up-your-manifestjson">Step 2. Setting up your manifest.json</h2>
<p>The <code>manifest.json</code> file is the one that tells the browser/OS about your app. You can set the full and short names, theme color, icons, and more. <a href="https://developers.google.com/web/fundamentals/web-app-manifest/">You can find more about its settings here.</a></p>
<p>Don&#39;t forget to update the auto-generated icons on <code>/assets/icons</code> folder! These are necessary so that your app icon shows up for devices of all DPI settings.</p>
<h2 id="step-3-setting-up-ngsw-configjson">Step 3. Setting up ngsw-config.json</h2>
<p>This file is the one that can configure how your PWA works. You can set up different installation behaviors, as well as handle cache updates. <a href="https://angular.io/guide/service-worker-config">The Angular documentation has got all options covered here.</a></p>
<h2 id="step-4-test-it-out">Step 4. Test it out!</h2>
<p>If you want to test out your app&#39;s new PWA capabilities locally, <code>ng serve</code> won&#39;t help you. Instead, you can run a web server in your machine easily by installing the <code>http-server</code> package from npm:</p>
<pre><code class="language-shell">npm i http-server -g
</code></pre>
<p>Then, compile your app in production mode:</p>
<pre><code class="language-shell">ng build --prod
</code></pre>
<p>And finally, start the web server:</p>
<pre><code class="language-shell">http-server -p 8080 -c-1 dist/&lt;project-name&gt;
</code></pre>
<p>Your app should be up and running on <code>http://localhost:8080/</code> (or whichever port you chose). How do you know it&#39;s a PWA? There are a few ways:</p>
<h3 id="check-if-the-service-worker-is-being-registered">Check if the service worker is being registered</h3>
<p><img src="https://rsinfo.vercel.app/images/posts/angular-pwa-how-to/Service-Workers.jpg" alt="Screenshot of Chromium&#39;s Service Workers UI" title="On dev console &gt; Application &gt; Service Workers, there should be a registered service worker for your app."></p>
<h3 id="use-chromes-audits-feature-to-validate-it-as-a-pwa">Use Chrome&#39;s Audits feature to validate it as a PWA</h3>
<p><img src="https://rsinfo.vercel.app/images/posts/angular-pwa-how-to/Audits.jpg" alt="Screenshot of Chromium&#39;s Audits tab, displaying options on how to test your page as different devices and for different metrics. The options &quot;mobile&quot; and &quot;Progressive Web App&quot; are selected." title="On dev console &gt; Audits, test it for Progressive Web Apps."></p>
<p><img src="https://rsinfo.vercel.app/images/posts/angular-pwa-how-to/Passed-Audits.jpg" alt="Screenshot of a list of passed audits, with two highlighted: &quot;User can be prompted to install the Web App&quot; and &quot;Registers a service worker&quot;" title="If everything went well, you should see the highlighted results on the &#39;Passed audits&#39; section."></p>
<p>You may see some errors regarding the app not running over HTTPS. Don&#39;t worry, that&#39;s only because it&#39;s running locally.</p>
<h2 id="step-5-install-it">Step 5. Install it!</h2>
<p>On Chrome/Edge, you may also see the option to install the app appear in the URL bar:</p>
<p><img src="https://rsinfo.vercel.app/images/posts/angular-pwa-how-to/install-prompt.jpg" alt="Screenshot of a browser window, showing an &quot;Install app?&quot; prompt on the navigation bar."></p>
<p>After this, the app should already open on a separate window, and show up on your OS&#39;s installed apps list!</p>
<p><img src="https://rsinfo.vercel.app/images/posts/angular-pwa-how-to/dock-icon.jpg" alt="Screenshot of the dock of the operating system, showing the PWA icon besides other apps&#39;, as if it were a &quot;real&quot; app."></p>
<h2 id="issues-encountered">Issues Encountered</h2>
<p>Even though the proccess is quite straight-forward, I still faced some issues when running it in my app. They were because of Angular tools versions, and I probably had these issues because I&#39;m still running an Angular 6 app (and Angular 7 is out as of now).</p>
<h3 id="the-ng-add-angularpwa-command-doesnt-create-relevant-files">The <code>ng add @angular/pwa</code> command doesn&#39;t create relevant files</h3>
<p>This was a <a href="https://github.com/angular/angular-cli/issues/11914">reported bug</a> on the CLI. I had a bugged version (6.0.8) installed on my app. I updated it by running:</p>
<pre><code class="language-shell">npm uninstall @angular/cli --save
npm install @angular/cli@latest --save
</code></pre>
<p>It updated itself to version 7.1.4 and worked flawlessly.</p>
<p><em>Notice: this is related to the local cli version, the one displayed on your <code>package.json</code> file, not the global one installed in your machine.</em></p>
<h3 id="failed-to-register-a-serviceworker-a-bad-http-response-code-404-was-received-when-fetching-the-script">Failed to register a ServiceWorker: A bad HTTP response code (404) was received when fetching the script.</h3>
<p>This error shows up on the browser console after opening the app running on http-server. It happens because, when running <code>ng build --prod</code>, Angular isn&#39;t sending the service worker&#39;s files along with the ones from the app. You can confirm this by searching for the <code>ngsw-worker.js</code> file on the <code>/dist</code> folder of your app. If it&#39;s not there, then you have this issue.</p>
<p>This one took me the longest to find out. Another bug related to outdated versions of Angular tools. Simply changing <code>@angular-devkit/build-angular</code> version in devDependencies to <code>~0.10.0</code> solved it.</p>
<h2 id="wrapping-up">Wrapping Up</h2>
<p>I hope you had success on setting up your PWA! Remember that, when published, it will only work if you serve your app through HTTPS.</p>
<p>Thanks for reading!</p>

          ]]></content:encoded>
          <media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://rsinfo.vercel.app/images/posts/angular-pwa-how-to/cover.jpg"/>
          <media:content xmlns:media="http://search.yahoo.com/mrss/" medium="image" url="https://rsinfo.vercel.app/images/posts/angular-pwa-how-to/cover.jpg"/>          
        </item>
      
        <item>
          <guid>https://rsinfo.vercel.app/purpose-of-this-blog</guid>
          <title>The purpose of this blog</title>
          <description>Why does it exist?</description>
          <link>https://rsinfo.vercel.app/purpose-of-this-blog</link>
          <pubDate>Fri, 08 Mar 2019 00:00:00 +0000</pubDate>
          
          <content:encoded><![CDATA[
            <div style="margin: 50px 0; font-style: italic;">
              If anything looks wrong, 
              <strong>
                <a href="https://rsinfo.vercel.app/purpose-of-this-blog">
                  read on the site!
                </a>
              </strong>
            </div>

            <p>There are many developer blogs out there, probably because developers like to ramble about the tech they enjoy. I&#39;m guilty of that too! This blog was created mainly for that - sharing about development stuff that I like or that I&#39;m learning.</p>
<p>The purpose is to help myself learn about the subjects better, since there&#39;s no better way to learn than trying to reach someone. Of course, it won&#39;t be made of tutorials only - I intend to write about some theoretical concepts, and maybe tech stuff not related to development.</p>
<p>I consider myself a tech enthusiast. Which means I like to talk about software and gadgets in a way that most other people would find me annoying. This can be a great place to be able to share this with people that may care, hopefully you!</p>
<p>I hope to see you here in future posts, and I hope you enjoy reading what I have to say!</p>

          ]]></content:encoded>
          <media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://rsinfo.vercel.app/images/posts/purpose-of-this-blog/cover.jpg"/>
          <media:content xmlns:media="http://search.yahoo.com/mrss/" medium="image" url="https://rsinfo.vercel.app/images/posts/purpose-of-this-blog/cover.jpg"/>          
        </item>
      
  </channel>
</rss>