<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Untitled Publication]]></title><description><![CDATA[Untitled Publication]]></description><link>https://blog.phreakyphoenix.tech</link><generator>RSS for Node</generator><lastBuildDate>Tue, 07 Apr 2026 10:28:32 GMT</lastBuildDate><atom:link href="https://blog.phreakyphoenix.tech/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Fixing Guake Window Alignment in Multi-Monitor Setups]]></title><description><![CDATA[If you’ve ever used Guake (the drop-down terminal for GNOME) with a multi-monitor setup, you may have noticed that on the primary monitor the Guake window sometimes overflows beyond the visible screen area — usually extending past the top or right ed...]]></description><link>https://blog.phreakyphoenix.tech/fixing-guake-window-alignment-in-multi-monitor-setups</link><guid isPermaLink="true">https://blog.phreakyphoenix.tech/fixing-guake-window-alignment-in-multi-monitor-setups</guid><category><![CDATA[guake ]]></category><category><![CDATA[Ubuntu]]></category><category><![CDATA[window management]]></category><category><![CDATA[development]]></category><category><![CDATA[technology]]></category><dc:creator><![CDATA[Aditya Jyoti Paul]]></dc:creator><pubDate>Fri, 05 Sep 2025 10:23:08 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1757067526915/38dceb0c-c5e7-4f8c-b663-9c566ba86b54.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>If you’ve ever used <a target="_blank" href="https://github.com/Guake/guake">Guake</a> (the drop-down terminal for GNOME) with a <strong>multi-monitor setup</strong>, you may have noticed that on the <strong>primary monitor</strong> the Guake window sometimes overflows beyond the visible screen area — usually extending past the <strong>top</strong> or <strong>right</strong> edges.</p>
<p>This makes Guake slightly annoying to use on the main monitor when you have more than one display connected.</p>
<hr />
<h2 id="heading-the-problem">The Problem</h2>
<p>On single-monitor setups, Guake aligns perfectly.<br />But with multiple monitors only the <strong>left alignment is fine</strong>, with overflows on the top and right out of the visible area.</p>
<p>On the <strong>primary monitor</strong> (<code>monitor == 0</code>), the window width and vertical alignment can push Guake partially off-screen.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1757066807859/7f9ee5a6-7ae9-491b-a12e-f45337817a0d.jpeg" alt class="image--center mx-auto" /></p>
<hr />
<h2 id="heading-the-solution">The Solution</h2>
<p>After digging through the source code, I found the logic that calculates Guake’s window rectangle in <a target="_blank" href="https://github.com/Guake/guake/blob/master/guake/utils.py"><code>utils.py</code></a> inside the <code>RectCalculator.set_final_window_rect</code> method.</p>
<p>By default, Guake calculates width and height as a percentage of the monitor’s geometry, then applies horizontal and vertical alignment. But there’s <strong>no special handling for the primary monitor in multi-monitor setups</strong>.</p>
<p>The fix is a simple adjustment right before resizing/moving the window in <code>/usr/lib/python3/dist-packages/guake/utils.py</code>.</p>
<pre><code class="lang-python"><span class="hljs-comment"># check for multi monitor setups</span>
<span class="hljs-comment"># if multiple monitors are detected and the primary monitor is used,</span>
<span class="hljs-comment"># we need to adjust the window width and position</span>

<span class="hljs-comment"># log.debug("Number of monitors detected: %s", screen.get_n_monitors())</span>
<span class="hljs-comment"># log.debug("Current monitor: %s", monitor)</span>
<span class="hljs-comment"># log.debug("Primary monitor: %s", screen.get_primary_monitor())</span>

<span class="hljs-keyword">if</span> screen.get_n_monitors() &gt; <span class="hljs-number">1</span> <span class="hljs-keyword">and</span> monitor == <span class="hljs-number">0</span>:
    log.debug(<span class="hljs-string">"Adjustment for Primary monitor in multi-monitor env applied"</span>)
    window_rect.width -= <span class="hljs-number">70</span>          <span class="hljs-comment"># reduce width</span>
    window_rect.y += <span class="hljs-number">34</span>              <span class="hljs-comment"># increase top gap</span>
</code></pre>
<p>That’s it. With this patch:</p>
<ul>
<li><p>Guake stays within visible bounds on the primary monitor.</p>
</li>
<li><p>Multi-monitor setups behave correctly without affecting single-monitor mode.</p>
</li>
</ul>
<p>Otherwise the top part is hidden by the activities pane and the right side goes beyond visible area (not sure why, the px calculations seem right but visually it’s not)</p>
<p>The commented log debug lines are meant to provide a jumpstart for more advanced tweaks, for eg if your primary monitor is not 0, you might want to find that or use the variable if it keeps changing etc.</p>
<p>While tesing the fix, the simplest way is to run guake from another terminal and restart it with <code>pkill guake &amp;&amp; guake -v</code>, no need to delete <code>__pycache__</code>.</p>
<p>Here’s how it looks with the fix.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1757066862559/82f65624-2be5-43ef-8236-89c4527a1e3a.jpeg" alt class="image--center mx-auto" /></p>
<hr />
<h2 id="heading-making-it-permanent">Making It Permanent !?</h2>
<p>If you edit <code>/usr/lib/python3/dist-packages</code>, your changes will be <strong>overwritten</strong> when Guake updates via your package manager.</p>
<p>Safer approaches:</p>
<ol>
<li><p><strong>Run from source</strong> – clone the Guake repo, apply the patch, and launch it directly.</p>
</li>
<li><p><strong>Use a Python venv</strong> – install Guake in a virtual environment and patch it there.</p>
</li>
</ol>
<p>I don’t recommend either, changing 4 lines in a python file if the issue reappears seems like the simplest solution to me while using your package manager.</p>
<hr />
<h2 id="heading-final-thoughts">Final Thoughts</h2>
<p>Sometimes the best fixes are small. Just a couple of lines in <code>utils.py</code> completely solved the misalignment issue for me in a multi-monitor setup. If you’re facing the same problem, give this tweak a try.</p>
]]></content:encoded></item><item><title><![CDATA[Mastering Monorepos Part 3: Points to consider choosing between Nx and Turborepo]]></title><description><![CDATA[📚 Use Cases

Nx excels in scenarios where a comprehensive, integrated workspace is preferred, offering simplicity and shared configurations.

Turborepo shines when modularity and parallel development are paramount, catering to projects with diverse,...]]></description><link>https://blog.phreakyphoenix.tech/mastering-monorepos-part-3-points-to-consider-choosing-between-nx-and-turborepo</link><guid isPermaLink="true">https://blog.phreakyphoenix.tech/mastering-monorepos-part-3-points-to-consider-choosing-between-nx-and-turborepo</guid><category><![CDATA[monorepo]]></category><category><![CDATA[software development]]></category><category><![CDATA[Software Engineering]]></category><category><![CDATA[consulting]]></category><category><![CDATA[software architecture]]></category><category><![CDATA[System Architecture]]></category><category><![CDATA[System Design]]></category><dc:creator><![CDATA[Aditya Jyoti Paul]]></dc:creator><pubDate>Tue, 30 Jan 2024 15:49:37 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1706629146427/1c55add5-e1d6-4dbd-8f68-20f1b285d65e.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h3 id="heading-use-cases">📚 Use Cases</h3>
<ol>
<li><p>Nx excels in scenarios where a comprehensive, integrated workspace is preferred, offering simplicity and shared configurations.</p>
</li>
<li><p>Turborepo shines when modularity and parallel development are paramount, catering to projects with diverse, independent packages.</p>
</li>
</ol>
<h3 id="heading-which-monorepo-to-choose">🤔 Which monorepo to Choose</h3>
<ol>
<li><p>If you want to use the integrated approach and prefer using generators for almost everything to control the build-test-deploy-pipeline at a granular level, you need to choose Nx.</p>
</li>
<li><p>Turborepo is easier to get up and running and is good enough for smaller prjects without a lot of shared code and dependencies.</p>
</li>
<li><p>Learning curve for Nx is considerably steeper than Turborepo. Anecdotally, it took me 15 mins to setup my first Turborepo, and 2.5 hrs with Nx integrated approach.</p>
</li>
</ol>
<h3 id="heading-some-other-observations">💡 Some other observations</h3>
<ol>
<li><p>Free tier for both is good enough, but Nx pricing is more transparent.</p>
</li>
<li><p>Nx Cloud as well as Turborepo support remote and local caching, speeding up local dev immensely.</p>
</li>
<li><p>Currently all Phoenix HQ products like PhoenixTrack, GraFin use Nx integrated and all our blogs use Turborepo package based, CI/CD on products took 40% lesser on average with monorepos than without.</p>
</li>
<li><p>Learning to use Nx generators efficiently is no piece of cake, it'd take a few days to get used to, but the improvements even for a small dev team are worth it.</p>
</li>
</ol>
<p>I put in a lot of love and effort into this monorepos series, please like and share so it reaches more people.</p>
<p>I'd love you sharing your experiences with monorepos in the comments.</p>
<p>Keep building!</p>
]]></content:encoded></item><item><title><![CDATA[Mastering Monorepos Part 2: Nx vs. Turborepo- A Deeper Dive into Package Management! 🚀]]></title><description><![CDATA[In the vibrant realm of monorepos, Nx and Turborepo stand out for their distinctive approaches to package management. I'll share my experience unravelling the intricacies of integrated and package-based styles in both platforms.
NX supports both inte...]]></description><link>https://blog.phreakyphoenix.tech/mastering-monorepos-part-2-nx-vs-turborepo-a-deeper-dive-into-package-management</link><guid isPermaLink="true">https://blog.phreakyphoenix.tech/mastering-monorepos-part-2-nx-vs-turborepo-a-deeper-dive-into-package-management</guid><category><![CDATA[monorepo]]></category><category><![CDATA[software development]]></category><category><![CDATA[Software Engineering]]></category><category><![CDATA[consulting]]></category><category><![CDATA[software architecture]]></category><category><![CDATA[System Architecture]]></category><category><![CDATA[System Design]]></category><dc:creator><![CDATA[Aditya Jyoti Paul]]></dc:creator><pubDate>Tue, 30 Jan 2024 15:47:08 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1706629495887/e085c184-f73e-40da-ae9c-95ed6d1fb43c.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In the vibrant realm of monorepos, Nx and Turborepo stand out for their distinctive approaches to package management. I'll share my experience unravelling the intricacies of integrated and package-based styles in both platforms.</p>
<p>NX supports both integrated and package-based styles. The former integrates projects within a unified workspace, fostering collaboration and shared configurations. TurboRepo adopts a package-based style, emphasizing modularity and independent versioning for optimized parallel development.</p>
<h3 id="heading-integrated-vs-package-based">🔄 Integrated vs Package-based</h3>
<h4 id="heading-nx-the-integrated-approach-also-supports-the-package-based-approach">🔗 NX: The Integrated Approach (also supports the package-based approach)</h4>
<ol>
<li><p><strong>Collaboration made easy</strong>: NX fosters collaboration by consolidating related projects into a unified workspace.</p>
</li>
<li><p><strong>Shared configurations</strong>: Developers benefit from shared configurations, ensuring consistency in tooling, testing, and linting across projects.</p>
</li>
<li><p><strong>Flexibility with granular commands</strong>: NX commands seamlessly operate across the entire workspace or specific projects, offering developers flexibility and control.</p>
</li>
<li><p><strong>Holistic NX workspaces</strong>: In NX, projects are organized within an "Nx Workspace," encouraging a holistic view of the entire codebase.</p>
</li>
<li><p><strong>Reusable Components</strong> with Nx Libraries: Nx Libraries facilitate code sharing, empowering developers to create reusable components, services, and utilities.</p>
</li>
</ol>
<h4 id="heading-turborepo-the-package-based-approach">📦 Turborepo: The Package-based Approach</h4>
<ol>
<li><p><strong>Modular</strong>: TurboRepo centers around a package-based style, emphasizing modularity to enhance scalability and performance.</p>
</li>
<li><p><strong>Independent Versioning</strong>: TurboRepo allows independent versioning for packages, providing granular control over dependencies.</p>
</li>
<li><p><strong>Parallel Development Capabilities</strong>: Developers can concurrently work on different packages in TurboRepo, enabling parallel development without unnecessary coupling.</p>
</li>
<li><p><strong>Dynamic workspaces</strong>: TurboRepo introduces dynamic workspaces, allowing developers to focus on a specific set of packages without the need for an all-encompassing workspace.</p>
</li>
<li><p><strong>Efficient Build System</strong>: TurboRepo optimizes builds by selectively rebuilding affected packages, contributing to faster development cycles.</p>
</li>
</ol>
<p>Also check out the comparison from Nx <a target="_blank" href="https://nx.dev/concepts/integrated-vs-package-based">here</a>.</p>
<blockquote>
<p>The integrated style is more convenient for projects which benefit from dependencies being managed centrally from the package.json in the root, whereas other projects which require different versions of the same package would be more suitable for the package-based approach.</p>
</blockquote>
<p>It's very easy to switch from the integrated style to the package-based style but significantly harder vice versa.</p>
<p>In the next article of this series, I'll share some use-cases and how I decide on the appropriate solution.<br />Comment and let me know which monorepo solution you prefer and why.<br />Please like and share so it reaches more people.</p>
<p>Useful links:</p>
<ol>
<li><p>Learn more about monorepos on <a target="_blank" href="https://monorepo.tools/">monorepo.tools</a>.</p>
</li>
<li><p>Check out <a target="_blank" href="https://nx.dev/">nx.dev</a> and <a target="_blank" href="https://turbo.build/">turbo.build</a>.</p>
</li>
</ol>
]]></content:encoded></item><item><title><![CDATA[Mastering Monorepos Part 1: Pros, Cons, Top Solutions]]></title><description><![CDATA[Monorepos have become a hot topic in the software development community, revolutionizing the way teams manage their codebases. Let's dive into the pros and cons and explore some popular solutions!
Pros

Code Sharing: Monorepos enable seamless code sh...]]></description><link>https://blog.phreakyphoenix.tech/mastering-monorepos-decide-between-nx-turborepo</link><guid isPermaLink="true">https://blog.phreakyphoenix.tech/mastering-monorepos-decide-between-nx-turborepo</guid><category><![CDATA[monorepo]]></category><category><![CDATA[software development]]></category><category><![CDATA[Software Engineering]]></category><category><![CDATA[consulting]]></category><category><![CDATA[software architecture]]></category><category><![CDATA[System Architecture]]></category><category><![CDATA[System Design]]></category><dc:creator><![CDATA[Aditya Jyoti Paul]]></dc:creator><pubDate>Tue, 30 Jan 2024 15:05:56 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1706626926177/ef959e60-d622-47f3-a20d-4fd3392df319.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Monorepos have become a hot topic in the software development community, revolutionizing the way teams manage their codebases. Let's dive into the pros and cons and explore some popular solutions!</p>
<h3 id="heading-pros"><strong>Pros</strong></h3>
<ol>
<li><p><strong>Code Sharing</strong>: Monorepos enable seamless code sharing across projects.</p>
</li>
<li><p><strong>Consistent Builds</strong>: Centralized configuration ensures consistent builds.</p>
</li>
<li><p><strong>Easier Refactoring</strong>: Changes across projects are easier to manage.</p>
</li>
<li><p><strong>Atomic Commits</strong>: Facilitates atomic commits, enhancing version control.</p>
</li>
<li><p><strong>Streamlined CI/CD</strong>: Unified pipelines simplify continuous integration and deployment.</p>
</li>
<li><p><strong>Unified Builds</strong>: Don't build the same thing more than once.</p>
</li>
</ol>
<h3 id="heading-cons"><strong>Cons</strong></h3>
<ol>
<li><p><strong>Learning Curve</strong>: Adopting monorepos may require a learning curve.</p>
</li>
<li><p><strong>Increased Repository Size</strong>: Larger repositories may impact cloning and storage.</p>
</li>
<li><p><strong>Tooling Complexity</strong>: Managing monorepos often involves sophisticated tooling.</p>
</li>
<li><p><strong>Dependency Management</strong>: Dependencies can be challenging to handle.</p>
</li>
<li><p><strong>Risk of Coupling</strong>: Close relationships between projects may lead to tight coupling.</p>
</li>
</ol>
<h3 id="heading-monorepo-solutions"><strong>Monorepo Solutions</strong></h3>
<ol>
<li><p><strong>Bazel</strong>: Focuses on build and test automation for large, multi-language projects from Google.</p>
</li>
<li><p><strong>Lage</strong>: A modern and extensible monorepo build system for TypeScript projects.</p>
</li>
<li><p><strong>Moon</strong>: Designed for simplicity and scalability, making monorepo management a breeze.</p>
</li>
<li><p><strong>NX</strong>: Ideal for teams working with Angular, React, and Node.js. NX provides powerful tooling, extensibility, and integration with popular frameworks.</p>
</li>
<li><p><strong>Pants</strong>: A scalable and flexible build system for monorepos, supporting multiple languages.</p>
</li>
<li><p><strong>Rush</strong>: Developed by Microsoft, designed for TypeScript projects.</p>
</li>
<li><p><strong>TurboRepo</strong>: Known for its efficient handling of codebases, TurboRepo offers optimization benefits in large-scale projects.</p>
</li>
</ol>
<h3 id="heading-highlighting-nx-and-turborepo"><strong>Highlighting NX and TurboRepo</strong></h3>
<p>🚀 <strong>NX</strong>: Ideal for teams working with Angular, React, and Node.js. NX provides powerful tooling, extensibility, and integration with popular frameworks. Its focus on developer experience and comprehensive toolset makes it a solid choice for managing monorepos of various sizes.</p>
<p>🔍 <strong>TurboRepo</strong>: Recognized for its efficient management of codebases, TurboRepo offers optimization features for handling large projects effectively. TurboRepo stands out for its simplicity and ease, especially if you're in the Vercel ecosystem. 💻</p>
<p>We at <a target="_blank" href="https://phoenixhq.space">Phoenix HQ</a> chose Nx as our monorepo solution (in the integrated style), along with eslint/tsconfig setup w/ NextJS, and it has proved to be gamechanging. I've continue to use Turborepo in some personal projects, they only support the package-based approach afaik, and it is super convenient to set up and use.</p>
<p>In a part 2 of this series, I'd compare Nx and Turborepo, going into more detail on how the package-based and integrated styles differ, how it impacts development.</p>
<p>Useful links:</p>
<ol>
<li><p>Learn more about monorepos on <a target="_blank" href="https://monorepo.tools/">monorepo.tools</a>.</p>
</li>
<li><p>Check out <a target="_blank" href="https://nx.dev/">nx.dev</a> and <a target="_blank" href="https://turbo.build/">turbo.build</a>.</p>
</li>
</ol>
]]></content:encoded></item><item><title><![CDATA[AmzTrack: Track Amazon Prices with Python]]></title><description><![CDATA[Hello there, fellow savvy shoppers and Pythonistas! If you've ever wanted to keep an eye on the price of a product on Amazon without manually refreshing the page every five minutes, this blog post is for you. Today, I'll share with you a simple Pytho...]]></description><link>https://blog.phreakyphoenix.tech/amztrack-track-amazon-prices-with-python</link><guid isPermaLink="true">https://blog.phreakyphoenix.tech/amztrack-track-amazon-prices-with-python</guid><category><![CDATA[Amazon]]></category><category><![CDATA[shopping]]></category><category><![CDATA[tracking]]></category><category><![CDATA[telegram]]></category><category><![CDATA[pricetrends]]></category><dc:creator><![CDATA[Aditya Jyoti Paul]]></dc:creator><pubDate>Sat, 29 Jul 2023 11:59:39 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1690630067308/4cf29499-0077-4e37-8918-602fe0cf5e5e.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Hello there, fellow savvy shoppers and Pythonistas! If you've ever wanted to keep an eye on the price of a product on Amazon without manually refreshing the page every five minutes, this blog post is for you. Today, I'll share with you a simple Python script that I created, which will allow you to track Amazon prices right from your laptop or server, regardless of the operating system you use.</p>
<p><em>And the best part? It's free and easy to use.</em></p>
<p>So, let's get started!</p>
<h3 id="heading-part-1-meet-your-new-friend-botfatherhttpstmebotfather"><strong>Part 1: Meet your new friend,</strong> @<a target="_blank" href="https://t.me/botfather">BotFather</a></h3>
<p>Before we dive into the code, you'll need a Telegram Bot token if you want to get constant price updates in Telegram. Don't worry; getting one is simple. Go to your Telegram app and search for a bot named @<a target="_blank" href="https://t.me/botfather">BotFather</a>. It will generate a new bot and provide you with a token. Keep this token safe; you will need it to interact with your bot. Replace <code>&lt;TELEGRAM BOT TOKEN&gt;</code> in the script with your token.</p>
<h3 id="heading-part-2-the-price-tracking-alternatives"><strong>Part 2: The Price Tracking Alternatives</strong></h3>
<p>There are a few websites out there like <a target="_blank" href="http://pricehistoryapp.com">pricehistoryapp.com</a> and <a target="_blank" href="http://pricebefore.com">pricebefore.com</a> that track prices. However, these services aren't always reliable. They might not update in real time, they may only work with certain products, or they could stop functioning if the website changes its layout.</p>
<p>Web scraping services like <a target="_blank" href="http://webscraping.ai">webscraping.ai</a> can provide more precise and customizable results, but they also come with a cost. If all you need is a simple tracker, it might not be worth paying for these services.</p>
<h3 id="heading-part-3-the-art-of-web-scraping"><strong>Part 3: The Art of Web Scraping</strong></h3>
<p>Here's where things get interesting. To fetch the prices, our script uses a method called "web scraping", which is a way to extract data from websites. Amazon does not like this and uses techniques such as IP blocking and CAPTCHA challenges to prevent it. Using a residential IP address can help bypass some of these obstacles, but be aware that excessive or inappropriate scraping can still lead to your IP getting blocked.</p>
<p>So, remember, with great power comes great responsibility. Use your scraping powers wisely!</p>
<h3 id="heading-part-4-see-the-magic"><strong>Part 4: See the Magic</strong></h3>
<ol>
<li><p><strong>Install Python and the necessary libraries</strong>: First, you need to have Python installed on your computer. If you don't have it, download it from <a target="_blank" href="https://www.python.org/downloads/"><strong>here</strong></a>. Once Python is installed, open your terminal or command prompt and type the following commands to install the necessary Python libraries: <code>pip install requests beautifulsoup4 urllib3==2.0.4</code>.</p>
<p> You'd also want <code>pip install fastapi uvicorn</code> if you want to run it as a server.</p>
</li>
<li><p><strong>Get your Telegram Bot Token and Chat ID</strong>: Follow the steps described in the blog post. Once you have these, keep them handy as you will need to put them into your Python script.</p>
</li>
<li><p><strong>Get the Product URL</strong>: Go to the Amazon product page you want to track and copy its URL.</p>
</li>
<li><p><strong>Get Telegram chat_id and optionally Amazon browser cookies:</strong></p>
<p> For chat_id, start by sending your bot a message in Telegram. Then, run the provided script with your bot token. This will return your chat_id in the response.</p>
<pre><code class="lang-python"> <span class="hljs-keyword">import</span> requests
 TOKEN = &lt;YOUR TELEGRAM TOKEN HERE&gt;
 url = <span class="hljs-string">f"https://api.telegram.org/bot<span class="hljs-subst">{TOKEN}</span>/getUpdates"</span>
 print(requests.get(url).json())
</code></pre>
<p> For cookies, it's optional even if you're using the server implementation. You can obtain them by opening the product page in your local Chrome browser for example, copying the cookies, and formatting them into a Python dictionary. Replace the cookie dictionary in the script with your own.<br /> Tip: I selected all the cookies and asked GPT to format it into a Python dict. 😉</p>
</li>
<li><p><strong>Edit the Python script</strong>: Now you need to replace some placeholders in the script with the values you just collected:</p>
<ul>
<li><p>Replace <code>&lt;TELEGRAM BOT TOKEN&gt;</code> with your Telegram Bot Token.</p>
</li>
<li><p>Replace <code>&lt;CHAT_ID&gt;</code> with your chat_id.</p>
</li>
<li><p>Replace <code>&lt;Your Product URL&gt;</code> with the product URL.</p>
</li>
<li><p>Replace <code>&lt;Your Cookie&gt;</code> with the cookies dictionary you have collected (optional)</p>
</li>
<li><p>Set the <code>TARGET</code> variable to the price point at which you want to be alerted.</p>
</li>
</ul>
</li>
<li><p><strong>Run the script</strong>: Save the script as a <code>.py</code> file (for example, <code>base.py</code>). Now, go to your terminal or command prompt, navigate to the directory where you saved the script and type: <code>python base.py</code> and hit Enter. The script should now run and send you updates on Telegram every 2 minutes!</p>
</li>
</ol>
<p>Remember, this script will stop running if you close the terminal or shut down your computer. If you want the script to run continuously, you will have to set up your computer to prevent it from sleeping, or run the script on a server.</p>
<p>If you're on a Mac, use these commands to disable sleep mode and run the script as a continuous process:</p>
<pre><code class="lang-plaintext">sudo pmset -b sleep 0; sudo pmset -b disablesleep 1
nohup caffeinate python base.py &amp;
</code></pre>
<p>When you're finished, re-enable sleep mode with:</p>
<pre><code class="lang-plaintext">sudo pmset -b sleep 5; sudo pmset -b disablesleep 0
</code></pre>
<p>You can do this similarly on Linux and disable sleep and network sleep from Power Management in Windows.</p>
<p>And there you have it! You're now set to never miss a price drop on your favorite Amazon product again. Happy shopping and happy coding!</p>
<h3 id="heading-part-5-complete-code-with-brief-explanation"><strong>Part 5: Complete Code with Brief Explanation</strong></h3>
<p>I've created two Python scripts for you. One is a base script that you can run from any device on your home network. The other is a FastAPI script if you want to run it as a server process. Here's what they do:</p>
<h4 id="heading-base-script-you-probably-only-need-this">Base Script <em>(You Probably only need this)</em></h4>
<p>First, the script uses a <code>requests.get</code> call to fetch the HTML content of the Amazon product page. We send along headers that mimic a browser to prevent getting blocked by Amazon. It then uses BeautifulSoup to parse the HTML and extract the prices from specific tags.</p>
<p>The script checks two prices for verification. If the prices match, it sends a message to a specified Telegram chat with the current price. If the prices do not match, it sends an alert. If the price drops below a certain target, it sends a different alert.</p>
<pre><code class="lang-python"><span class="hljs-comment">## Base script</span>

<span class="hljs-keyword">import</span> requests
<span class="hljs-keyword">from</span> bs4 <span class="hljs-keyword">import</span> BeautifulSoup
<span class="hljs-keyword">from</span> time <span class="hljs-keyword">import</span> sleep

TOKEN = &lt;TELEGRAM BOT TOKEN&gt;
CHAT_ID = &lt;YOUR CHAT ID&gt;
TELEGRAM_API_URL = <span class="hljs-string">f"https://api.telegram.org/bot<span class="hljs-subst">{TOKEN}</span>/sendMessage"</span>
PRODUCT_URL = <span class="hljs-string">"https://www.amazon.in/POCO-Pro-Yellow-128GB-Storage/dp/B0B6GDLMQK/ref=sr_1_1?crid=3EB9ZPVILWI2J&amp;keywords=poco+x4+pro+5g&amp;qid=1690330911&amp;sprefix=poco+x4+pro%2Caps%2C243&amp;sr=8-1"</span>
TARGET = <span class="hljs-number">17000</span>  <span class="hljs-comment">#INSERT YOUR TARGET PRICE HERE</span>

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">get_prices</span>(<span class="hljs-params">url=PRODUCT_URL</span>):</span>
    headers = {<span class="hljs-string">"User-Agent"</span>: <span class="hljs-string">"Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:91.0) Gecko/20100101 Firefox/91.0"</span>}
    response = requests.get(url, headers=headers)
    soup = BeautifulSoup(response.content, <span class="hljs-string">"html.parser"</span>)

    input_tag = soup.find(<span class="hljs-string">'input'</span>, {<span class="hljs-string">'id'</span>: <span class="hljs-string">'attach-base-product-price'</span>})
    price_primary = float(input_tag[<span class="hljs-string">'value'</span>])

    price_tag = soup.find(<span class="hljs-string">'span'</span>, {<span class="hljs-string">'class'</span>: <span class="hljs-string">'a-price-whole'</span>})
    price_whole =float(price_tag.text.replace(<span class="hljs-string">','</span>,<span class="hljs-string">''</span>))
    <span class="hljs-keyword">return</span> price_primary, price_whole

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">send_telegram_message</span>(<span class="hljs-params">message, chat_id = CHAT_ID</span>):</span>
    <span class="hljs-string">"""Sends a message to a specified chat in Telegram."""</span>
    data = {
        <span class="hljs-string">'chat_id'</span>: chat_id,
        <span class="hljs-string">'text'</span>: message
    }
    response = requests.post(TELEGRAM_API_URL, data=data)
    <span class="hljs-keyword">return</span> response.json()

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">main</span>(<span class="hljs-params">args=None</span>):</span>
    <span class="hljs-string">"""The main routine."""</span>
    price_primary, price_whole = get_prices()
    <span class="hljs-keyword">if</span> price_primary == price_whole:
        message = <span class="hljs-string">f'Price of product is <span class="hljs-subst">{price_primary}</span>'</span>
        <span class="hljs-keyword">if</span> price_primary &lt;= TARGET:
            message = <span class="hljs-string">f'ALERT PRICE DROP Price of product is <span class="hljs-subst">{price_primary}</span>'</span>
    <span class="hljs-keyword">else</span>:
        message = <span class="hljs-string">f'Price mismatch for product between <span class="hljs-subst">{price_primary}</span> and <span class="hljs-subst">{price_whole}</span>'</span>
        <span class="hljs-keyword">if</span> price_primary &lt;= TARGET <span class="hljs-keyword">or</span> price_whole &lt;= TARGET:
            message = <span class="hljs-string">f'ALERT PRICE DROP WITH MISMATCH Price of product is <span class="hljs-subst">{min(price_primary,price_whole)}</span>'</span>
    send_telegram_message(message)

<span class="hljs-keyword">if</span> __name__ == <span class="hljs-string">"__main__"</span>:
    <span class="hljs-keyword">while</span> <span class="hljs-literal">True</span>:
        main()
        sleep(<span class="hljs-number">60</span>*<span class="hljs-number">5</span>)
</code></pre>
<h4 id="heading-server-script">Server Script</h4>
<p>The server script does the same thing, but it's designed to run as a FastAPI process. This script uses cookies to maintain a session, which you will need to replace them with your own. The check will happen each time the check_price function runs which happens when the / route is hit.</p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> fastapi <span class="hljs-keyword">import</span> FastAPI
<span class="hljs-keyword">import</span> requests
<span class="hljs-keyword">from</span> bs4 <span class="hljs-keyword">import</span> BeautifulSoup

app = FastAPI()

TOKEN = &lt;TELEGRAM BOT TOKEN&gt;
CHAT_ID = &lt;YOUR CHAT ID&gt;
TELEGRAM_API_URL = <span class="hljs-string">f"https://api.telegram.org/bot<span class="hljs-subst">{TOKEN}</span>/sendMessage"</span>
PRODUCT_URL = <span class="hljs-string">"https://www.amazon.in/POCO-Pro-Yellow-128GB-Storage/dp/B0B6GDLMQK/ref=sr_1_1?crid=3EB9ZPVILWI2J&amp;keywords=poco+x4+pro+5g&amp;qid=1690330911&amp;sprefix=poco+x4+pro%2Caps%2C243&amp;sr=8-1"</span>
TARGET = <span class="hljs-number">17000</span>  <span class="hljs-comment">#INSERT YOUR TARGET PRICE HERE</span>

headers = {
        <span class="hljs-string">"User-Agent"</span>: <span class="hljs-string">"Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:91.0) \
        Gecko/20100101 Firefox/91.0"</span>
    }

cookies = {
    <span class="hljs-string">"csm-hit"</span>: <span class="hljs-string">"tb:s-CXXNPATX9J2QGP81Q|1690349188202&amp;t:169034999&amp;adb:adblk_no"</span>,
    <span class="hljs-string">"session-token"</span>: <span class="hljs-string">"W842UvQcRIpJHNyfBrqtjds14fUwP7OoBTeIDrLCLpKks+uFGi6hZrn7H8DGUC8IJTdsfQsq6jgGzhGXho0oiA0TbhE9BHUAs8ZlJ2YsuUA4CMLLb6csSo/xAUwULgrLE6fVdZf/fwhHbBMt+XpuKnBoSSRHYe+VnWgrCxeN8cx7VXBD5gNf1+DbPnpcvF53DFaOBg+Zj0QN6KJsvZCsVdR/4pXJHllCvr0Y="</span>,
    <span class="hljs-string">"ubid-acbin"</span>: <span class="hljs-string">"247-6048695-6105069"</span>,
    <span class="hljs-string">"i18n-prefs"</span>: <span class="hljs-string">"INR"</span>,
    <span class="hljs-string">"lc-acbin"</span>: <span class="hljs-string">"en_IN"</span>,
    <span class="hljs-string">"session-id-time"</span>: <span class="hljs-string">"2083786201l"</span>,
    <span class="hljs-string">"session-id"</span>: <span class="hljs-string">"253-7064393-874941"</span>,
}

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">get_prices</span>(<span class="hljs-params">url=PRODUCT_URL</span>):</span>

    sess = requests.Session()
    sess.headers.update(headers)
    sess.cookies.update(cookies)
    response = sess.get(url)
    soup = BeautifulSoup(response.content, <span class="hljs-string">"html.parser"</span>)

    input_tag = soup.find(<span class="hljs-string">"input"</span>, {<span class="hljs-string">"id"</span>: <span class="hljs-string">"attach-base-product-price"</span>})
    price_primary = float(input_tag[<span class="hljs-string">"value"</span>])

    price_tag = soup.find(<span class="hljs-string">"span"</span>, {<span class="hljs-string">"class"</span>: <span class="hljs-string">"a-price-whole"</span>})
    price_whole = float(price_tag.text.replace(<span class="hljs-string">","</span>, <span class="hljs-string">""</span>))
    <span class="hljs-keyword">return</span> price_primary, price_whole

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">send_telegram_message</span>(<span class="hljs-params">message, chat_id=CHAT_ID</span>):</span>
    <span class="hljs-string">"""Sends a message to a specified chat in Telegram."""</span>
    data = {<span class="hljs-string">"chat_id"</span>: chat_id, <span class="hljs-string">"text"</span>: message}
    response = requests.post(TELEGRAM_API_URL, data=data, timeout=<span class="hljs-number">20</span>)
    <span class="hljs-keyword">return</span> response.json()

<span class="hljs-meta">@app.get("/")</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">check_price</span>():</span>
    message = <span class="hljs-string">''</span>
    <span class="hljs-keyword">try</span>:
        price_primary, price_whole = get_prices()
        <span class="hljs-keyword">if</span> price_primary == price_whole:
            message = <span class="hljs-string">f"Price of product is <span class="hljs-subst">{price_primary}</span>"</span>
            <span class="hljs-keyword">if</span> price_primary &lt;= TARGET:
                message = <span class="hljs-string">f"ALERT PRICE DROP Price of product is <span class="hljs-subst">{price_primary}</span>"</span>
        <span class="hljs-keyword">else</span>:
            message = (
                <span class="hljs-string">f"Price mismatch for product between <span class="hljs-subst">{price_primary}</span> and <span class="hljs-subst">{price_whole}</span>"</span>
            )
            <span class="hljs-keyword">if</span> price_primary &lt;= TARGET <span class="hljs-keyword">or</span> price_whole &lt;= TARGET:
                message = <span class="hljs-string">f"ALERT PRICE DROP WITH MISMATCH Price of product is <span class="hljs-subst">{min(price_primary,price_whole)}</span>"</span>
    <span class="hljs-keyword">except</span> Exception <span class="hljs-keyword">as</span> e:
        message = <span class="hljs-string">f"Error: <span class="hljs-subst">{str(e)}</span>"</span>
    <span class="hljs-keyword">finally</span>:
        send_telegram_message(message)
        <span class="hljs-keyword">return</span> {<span class="hljs-string">"message"</span>: message}
</code></pre>
<h3 id="heading-part-6-detailed-code-walkthrough">Part 6: Detailed Code Walkthrough</h3>
<p>Here we walk through the code line by line, feel free to skip this if you're not looking to add features to the tool. But if you're looking to customize this even further, the sky is the limit, let's delve into it.</p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> requests
<span class="hljs-keyword">from</span> bs4 <span class="hljs-keyword">import</span> BeautifulSoup
<span class="hljs-keyword">from</span> time <span class="hljs-keyword">import</span> sleep
</code></pre>
<p>Here, we're importing necessary Python libraries. <code>requests</code> allows us to send HTTP requests, <code>BeautifulSoup</code> is used for pulling data out of HTML and XML files, and <code>sleep</code> from <code>time</code> will help us to pause the execution of the script for a specified amount of time.</p>
<pre><code class="lang-python">TOKEN = &lt;TELEGRAM BOT TOKEN&gt;
CHAT_ID = &lt;YOUR CHAT ID&gt;
TELEGRAM_API_URL = <span class="hljs-string">f"https://api.telegram.org/bot<span class="hljs-subst">{TOKEN}</span>/sendMessage"</span>
PRODUCT_URL = <span class="hljs-string">"https://www.amazon.in/POCO-Pro-Yellow-128GB-Storage/dp/B0B6GDLMQK/ref=sr_1_1?crid=3EB9ZPVILWI2J&amp;keywords=poco+x4+pro+5g&amp;qid=1690330911&amp;sprefix=poco+x4+pro%2Caps%2C243&amp;sr=8-1"</span>
TARGET = <span class="hljs-number">17000</span>  <span class="hljs-comment">#INSERT YOUR TARGET PRICE HERE</span>
</code></pre>
<p>In these lines, we're setting up our variables. <code>TOKEN</code> is your Telegram Bot Token, <code>TELEGRAM_API_URL</code> is the URL for the Telegram API for sending messages, <code>PRODUCT_URL</code> is the URL for the Amazon product you want to track, and <code>TARGET</code> is the price point at which you want to be alerted.</p>
<pre><code class="lang-python"><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">get_prices</span>(<span class="hljs-params">url=PRODUCT_URL</span>):</span>
    headers = {<span class="hljs-string">"User-Agent"</span>: <span class="hljs-string">"Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:91.0) Gecko/20100101 Firefox/91.0"</span>}
    response = requests.get(url, headers=headers)
    soup = BeautifulSoup(response.content, <span class="hljs-string">"html.parser"</span>)
</code></pre>
<p>This is the start of the <code>get_prices</code> function. We define a headers dictionary with a <code>User-Agent</code> to mimic a real browser. We then send a GET request to the product URL and parse the HTML content with BeautifulSoup.</p>
<pre><code class="lang-python">input_tag = soup.find(<span class="hljs-string">'input'</span>, {<span class="hljs-string">'id'</span>: <span class="hljs-string">'attach-base-product-price'</span>})
price_primary = float(input_tag[<span class="hljs-string">'value'</span>])
</code></pre>
<p>Here, we're looking for an HTML 'input' tag with the ID 'attach-base-product-price'. This is where Amazon stores the base product price. We retrieve it and convert it to a float.</p>
<pre><code class="lang-python">price_tag = soup.find(<span class="hljs-string">'span'</span>, {<span class="hljs-string">'class'</span>: <span class="hljs-string">'a-price-whole'</span>})
price_whole =float(price_tag.text.replace(<span class="hljs-string">','</span>,<span class="hljs-string">''</span>))
<span class="hljs-keyword">return</span> price_primary, price_whole
</code></pre>
<p>Next, we're finding the span tag with the class 'a-price-whole' which contains the displayed price on the product page. We're extracting the text, removing any commas, converting it to a float and returning both prices.</p>
<pre><code class="lang-python"><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">send_telegram_message</span>(<span class="hljs-params">message, chat_id = CHAT_ID</span>):</span>
    <span class="hljs-string">"""Sends a message to a specified chat in Telegram."""</span>
    data = {
        <span class="hljs-string">'chat_id'</span>: chat_id,
        <span class="hljs-string">'text'</span>: message
    }
    response = requests.post(TELEGRAM_API_URL, data=data)
    <span class="hljs-keyword">return</span> response.json()
</code></pre>
<p>This is the <code>send_telegram_message</code> function. It takes a message and a chat_id as inputs, creates a dictionary with these values, and sends a POST request to the Telegram API to send the message. We send the messages by calling <code>send_telegram_message(message)</code></p>
<pre><code class="lang-python"><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">main</span>(<span class="hljs-params">args=None</span>):</span>
    <span class="hljs-string">"""The main routine."""</span>
    price_primary, price_whole = get_prices()
    <span class="hljs-keyword">if</span> price_primary == price_whole:
        message = <span class="hljs-string">f'Price of product is <span class="hljs-subst">{price_primary}</span>'</span>
        <span class="hljs-keyword">if</span> price_primary &lt;= TARGET:
            message = <span class="hljs-string">f'ALERT PRICE DROP Price of product is <span class="hljs-subst">{price_primary}</span>'</span>
    <span class="hljs-keyword">else</span>:
        message = <span class="hljs-string">f'Price mismatch for product between <span class="hljs-subst">{price_primary}</span> and <span class="hljs-subst">{price_whole}</span>'</span>
        <span class="hljs-keyword">if</span> price_primary &lt;= TARGET <span class="hljs-keyword">or</span> price_whole &lt;= TARGET:
            message = <span class="hljs-string">f'ALERT PRICE DROP WITH MISMATCH Price of product is <span class="hljs-subst">{min(price_primary,price_whole)}</span>'</span>
</code></pre>
<p>In the <code>main</code> function, we call the <code>get_prices</code> function to get the two price values.</p>
<p>We're checking if the base product price and displayed price are the same. If they are, we're creating a message with the price, and if it is less than or equal to the target, we're creating an alert message. If the prices are not the same, we're creating a message to notify about the mismatch and creating an alert message if either price is less than or equal to the target. You can customize the messages in the if-else block as you wish.</p>
<pre><code class="lang-python"><span class="hljs-keyword">if</span> __name__ == <span class="hljs-string">"__main__"</span>:
    <span class="hljs-keyword">while</span> <span class="hljs-literal">True</span>:
        main()
        sleep(<span class="hljs-number">60</span>*<span class="hljs-number">5</span>)
</code></pre>
<p>Finally, if this script is being run directly (and not being imported as a module), we're calling the <code>main</code> function in an infinite loop, with a pause of 5 minutes (60*5) between each call. This will keep checking the prices and sending updates to Telegram. You can also remove the infinite loop and just call the main function, handling the scheduling in a Cron Job, if you'd prefer, that'd also save a bit of OS resources.</p>
<h3 id="heading-conclusion">Conclusion</h3>
<p>And voila! You've just created your very own Python-based Amazon price tracker. With the power of Python and a little bit of your time, you've built a tool that can save you both time and money. No longer do you need to manually keep track of fluctuating prices or pay for pricey tracking services. Now, you can have updates delivered right to you via Telegram.</p>
<p>Whether you're a bargain hunter or just love tinkering with Python, this script gives you a new tool in your arsenal. Plus, you've learned valuable skills in web scraping, working with APIs, and scripting with Python. The best part? You can customize this script to fit your specific needs, whether it's tracking prices on different websites or setting different price thresholds.</p>
<p>I was able to help my girlfriend buy a mobile with this. See how the price jumps up at the end, that happened right after we made the purchase. We had set an alert at 17k, and got a deal within 2 days of running AmzTrack.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1690606439534/1de493ff-7ae7-4824-b0f2-f3f3ef54e86b.jpeg" alt class="image--center mx-auto" /></p>
<p>Remember, this script is a starting point, and the sky is the limit when it comes to customizing it. Want to track multiple items at once or receive alerts via different messaging platforms or on-call? Go ahead and modify it to your heart's content. After all, that's the beauty of coding.</p>
<p>So, start saving money today with AmzTrack. It's a game-changer for online shopping. As always, happy coding and happy shopping!</p>
]]></content:encoded></item><item><title><![CDATA[What to expect in a management interview?]]></title><description><![CDATA[When it comes to a management interview, the expectations are high, and the interview process can be very thorough. The employer will be looking for the right combination of skills, experience, and personality traits to ensure that the candidate can ...]]></description><link>https://blog.phreakyphoenix.tech/what-to-expect-in-a-management-interview</link><guid isPermaLink="true">https://blog.phreakyphoenix.tech/what-to-expect-in-a-management-interview</guid><category><![CDATA[management]]></category><category><![CDATA[agile]]></category><category><![CDATA[interview]]></category><category><![CDATA[interview questions]]></category><category><![CDATA[teamwork]]></category><dc:creator><![CDATA[Aditya Jyoti Paul]]></dc:creator><pubDate>Fri, 24 Mar 2023 15:22:43 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1679667587200/192ca2c5-d7d8-4448-95c7-b7e21ebb131f.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>When it comes to a management interview, the expectations are high, and the interview process can be very thorough. The employer will be looking for the right combination of skills, experience, and personality traits to ensure that the candidate can effectively lead and manage a team.</p>
<p>In this article, I'll cover some general things to expect in an interview, key areas of preparation and some sample questions and answers. Since every management interview is different, the article will be generally applicable to most individuals but for more personalized guidance and support, you can book some time with me <a target="_blank" href="https://topmate.io/phreakyphoenix/201077">here</a>.</p>
<p>Here are some things to expect in a management interview.</p>
<ol>
<li><p><strong>Discussion of Management Style</strong>: One of the primary things that an interviewer will want to know is your management style. The interviewer may ask questions about how you have managed teams in the past, how you would handle different situations, and what your strengths and weaknesses are as a manager. The interviewer will also want to know if your management style aligns with the company culture.</p>
</li>
<li><p><strong>Questions about Leadership</strong>: Leadership is a crucial aspect of management, and the interviewer will want to know if you have the necessary skills to lead a team effectively. The interviewer may ask questions about your experience in leading teams, how you motivate your team, and how you handle conflicts within the team. They may also ask about your approach to delegation and decision-making.</p>
</li>
<li><p><strong>Experience and Education</strong>: The interviewer will want to know about your experience and education. They may ask questions about your previous roles, the size of the teams you have managed, and the type of projects you have overseen. The interviewer may also ask about any management-related education or training that you have completed.</p>
</li>
<li><p><strong>Problem-Solving Skills</strong>: Managers are often required to solve complex problems, and the interviewer will want to know if you have the necessary problem-solving skills. The interviewer may ask hypothetical questions that require you to come up with creative solutions to challenging problems.</p>
</li>
<li><p><strong>Communication Skills</strong>: Effective communication is a critical aspect of management, and the interviewer will want to know if you have the necessary communication skills. The interviewer may ask questions about your approach to communication, how you handle difficult conversations, and how you communicate with team members of different backgrounds and skill levels.</p>
</li>
<li><p><strong>Personal Attributes</strong>: In addition to technical skills and experience, the interviewer will also be interested in your personal attributes. They may ask questions about your ability to work under pressure, your ability to adapt to changing situations, and your ability to handle feedback.</p>
</li>
</ol>
<p>Here are some general tips for preparing for a management interview:</p>
<ol>
<li><p><strong>Research the company</strong>: Study the company’s history, mission, values, products or services, and culture. Familiarize yourself with its recent news and developments.</p>
</li>
<li><p><strong>Review the job description</strong>: Read the job description carefully and make a list of the skills, qualifications, and responsibilities required for the position. Think about how your experience and skills align with those listed.</p>
</li>
<li><p><strong>Prepare your examples</strong>: Prepare specific examples from your past experiences that demonstrate your skills and qualifications. Think about examples that show how you solved a problem, motivated a team, or achieved a goal.</p>
</li>
<li><p><strong>Practice answering common interview questions</strong>: Prepare to answer questions about your leadership style, conflict resolution skills, problem-solving abilities, and experience managing teams.</p>
</li>
<li><p><strong>Be confident and personable</strong>: During the interview, be confident and personable. Remember to listen carefully to the interviewer and provide thoughtful responses.</p>
</li>
</ol>
<p>Here are some specific questions you might encounter in a management interview:</p>
<ol>
<li><p>How do you manage conflicts within your team?</p>
</li>
<li><p>Can you tell me about a time when you had to make a difficult decision?</p>
</li>
<li><p>How do you motivate your team to achieve their goals?</p>
</li>
<li><p>How do you prioritize and manage your workload as a manager?</p>
</li>
<li><p>Can you describe your leadership style and how it has helped you achieve success?</p>
</li>
<li><p>How do you handle underperforming team members?</p>
</li>
<li><p>How do you stay up to date on industry trends and best practices?</p>
</li>
<li><p>Can you provide an example of a project you managed and how you achieved success?</p>
</li>
<li><p>Can you describe a time when you had to work with a difficult stakeholder or client?</p>
</li>
<li><p>How do you foster a positive and inclusive work culture within your team?</p>
</li>
</ol>
<p>Take some time to ponder on these questions, <strong>there's no right answer to these questions as they're open-ended but there absolutely are wrong answers that you need to steer clear of</strong>.</p>
<p><em>Below I've shared some sample answers to showcase the style in which you can answer these questions but make sure you</em> <strong><em>personalize the answers</em></strong> <em>and are truthful to your own management style since the goal of these questions is to know the real you.</em></p>
<ol>
<li><p><strong>How do you manage conflicts within your team?</strong> When conflicts arise within my team, I first ensure that all parties are heard and their concerns are addressed. I encourage open communication and respect for one another's perspectives. Then, I work collaboratively with my team to find a solution that satisfies all parties involved and aligns with the company's goals.</p>
</li>
<li><p><strong>Can you tell me about a time when you had to make a difficult decision?</strong> When faced with a difficult decision, I gather all relevant information and perspectives, evaluate the pros and cons, and consider the potential impact on the team and the company. I weigh all factors carefully and make the decision that aligns best with the company's values and goals.</p>
</li>
<li><p><strong>How do you motivate your team to achieve their goals?</strong> I believe in leading by example and setting clear goals and expectations for my team. I encourage them to take ownership of their work and provide regular feedback and recognition for their achievements. I also create opportunities for growth and development, and empower them to make decisions and take risks.</p>
</li>
<li><p><strong>How do you prioritize and manage your workload as a manager?</strong> I prioritize my workload by setting clear goals and deadlines, and by identifying tasks that are urgent or important. I delegate tasks to team members when appropriate and ensure that each task aligns with the company's goals and priorities. I also regularly review and adjust my workload as needed.</p>
</li>
<li><p><strong>Can you describe your leadership style and how it has helped you achieve success?</strong> My leadership style is collaborative, supportive, and empowering. I believe in building strong relationships with my team members and creating a positive and inclusive work culture. I encourage open communication and respect for one another's perspectives. This approach has helped me achieve success by fostering a productive and motivated team that is aligned with the company's goals.</p>
</li>
<li><p><strong>How do you handle underperforming team members?</strong> When a team member is underperforming, I first assess the reasons for their poor performance and provide them with clear feedback and guidance on how to improve. I create a plan with them to address the issue and regularly check in on their progress. If the issue persists, I escalate the matter to senior management.</p>
</li>
<li><p><strong>How do you stay up to date on industry trends and best practices?</strong> I stay up to date on industry trends and best practices by attending industry events, reading industry publications, and networking with other professionals in the field. I also encourage my team members to do the same and share their findings with the rest of the team.</p>
</li>
<li><p><strong>Can you provide an example of a project you managed and how you achieved success?</strong> One project I managed involved developing a new product line for our company. I first identified the market opportunity and worked with my team to conduct market research and develop the product concept. We then worked collaboratively with other departments to design and produce the product, and successfully launched it to the market, exceeding our sales targets.</p>
</li>
<li><p><strong>Can you describe a time when you had to work with a difficult stakeholder or client?</strong> I once had to work with a stakeholder who had conflicting priorities and expectations. To address the issue, I first listened to their concerns and made sure to clearly communicate our goals and limitations. I then worked collaboratively with them to find a solution that satisfied both parties and aligned with the company's goals.</p>
</li>
<li><p><strong>How do you foster a positive and inclusive work culture within your team?</strong> I foster a positive and inclusive work culture by setting clear expectations and goals for my team, providing regular feedback and recognition, and encouraging open communication and respect for one another's perspectives. I also create opportunities for team building and personal growth, and ensure that diversity and inclusion are prioritized in all aspects of our work. I believe that a positive and inclusive work culture leads to a more engaged and motivated team that is better able to achieve its goals and contribute to the success of the company.</p>
</li>
</ol>
<p>Hope you found this article very helpful.</p>
<p>If you want more personalized guidance on how to chart your journey to successful management roles, in a 1:1 with me, I'll teach you how to</p>
<ol>
<li><p>answer questions effectively and impress the interviewer,</p>
</li>
<li><p>improve your style and content delivery to get your point across lucidly, and</p>
</li>
<li><p>supercharge your preparation for your dream management roles.</p>
<p> If you'd find that valuable, you can book time with me for a <a target="_blank" href="https://topmate.io/phreakyphoenix/201077">Mock Management Interview</a> with personalized guidance and actionable insights. All the best!</p>
</li>
</ol>
]]></content:encoded></item><item><title><![CDATA[Performance Comparison of Polars vs Pandas]]></title><description><![CDATA[If you haven't read it already, do check out my article Introducing Polars, which goes over what is Polars, who it is for and the differences from Pandas in detail. This article only briefly touches upon them and focuses on the performance comparison...]]></description><link>https://blog.phreakyphoenix.tech/performance-comparison-of-polars-vs-pandas</link><guid isPermaLink="true">https://blog.phreakyphoenix.tech/performance-comparison-of-polars-vs-pandas</guid><category><![CDATA[Data Science]]></category><category><![CDATA[performance]]></category><category><![CDATA[Machine Learning]]></category><category><![CDATA[data]]></category><category><![CDATA[big data]]></category><dc:creator><![CDATA[Aditya Jyoti Paul]]></dc:creator><pubDate>Wed, 22 Mar 2023 13:01:49 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1679489986637/06f7a917-a62d-4199-b408-98389c192abe.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>If you haven't read it already, do check out my article <a target="_blank" href="https://phreakyphoenix.tech/blog/introducing-polars">Introducing Polars</a>, which goes over what is Polars, who it is for and the differences from Pandas in detail. This article only briefly touches upon them and focuses on the performance comparison,</p>
<h2 id="heading-introduction-to-polars">🐻‍❄️ Introduction to Polars</h2>
<p>Polars is an open-source data manipulation library that offers faster processing speeds and efficient memory usage compared to Pandas. It is built in Rust, a programming language known for its speed and safety, and offers a DataFrame API that is similar to Pandas.</p>
<p>When working with large datasets, choosing the right data manipulation library can significantly affect performance. In this blog, we will compare the performance of two popular data manipulation libraries: Pandas and Polars, using benchmarking.</p>
<h2 id="heading-differences-between-pandas-and-polars">🐼 Differences between Pandas and Polars</h2>
<p>Pandas is a widely used data manipulation library that offers a comprehensive set of tools for data analysis. However, its performance is limited by its reliance on the Python programming language, which is known to be slower than languages like Rust. In contrast, Polars is built in Rust, which enables it to deliver significantly faster performance.</p>
<p>One of the key differences between Pandas and Polars is their memory usage. Pandas stores data in memory as a NumPy array, which can be memory-intensive for large datasets. On the other hand, Polars uses memory mapping, which enables it to read and write data to disk without loading it into memory. This results in more efficient memory usage, especially for large datasets.</p>
<p>Another significant difference between Pandas and Polars is their processing speed. Polars is designed to leverage the power of modern CPUs, making use of multi-threading and SIMD (Single Instruction Multiple Data) instructions. This enables it to perform operations like aggregations, joins, and filters much faster than Pandas, especially on large datasets.</p>
<h2 id="heading-set-up">🏄 Set Up</h2>
<p>The setup is simple, we need to install <code>pyarrow</code> and <code>polars</code>. Without pyarrow, polars complains about it not being present. The experiments are run on an M1 Mac with 16GB ram and 256 GB SSD.</p>
<p>We will create a virtualenv for the experiment and run</p>
<pre><code class="lang-bash">pip install polars pandas pyarrow
</code></pre>
<p>To begin with, we create a data frame with 1 million rows and 10 columns, using NumPy's random function. We will use this data frame for our benchmarking.</p>
<pre><code class="lang-python"><span class="hljs-comment"># Create a datafram with 1 million rows and 10 columns</span>
df = pd.DataFrame(np.random.rand(<span class="hljs-number">10000000</span>, <span class="hljs-number">10</span>), columns=[<span class="hljs-string">'col_'</span>+str(i) <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> range(<span class="hljs-number">10</span>)])
pl_df = pl.DataFrame(df)
</code></pre>
<h3 id="heading-brief-aside-on-timeit">🔔 <strong>Brief aside on %timeit</strong></h3>
<p>The <code>%timeit</code> <a target="_blank" href="https://stackoverflow.com/questions/29280470/what-is-timeit-in-python">magic command</a> is used in Jupyter notebooks to measure the time taken by a piece of code to execute. The command runs the code multiple times to get an average execution time, which helps in eliminating any variations in the time taken by the code to execute due to system performance or other factors.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1679484396138/da2b19c2-cf37-4007-b1e2-bc409777fe0c.png" alt class="image--center mx-auto" /></p>
<p>In the code snippets provided below, <code>%timeit</code> is used to compare the performance of Pandas and Polars libraries for various operations. The <code>-r7</code> parameter, for example, indicates that the command should run the code 7 times, and <code>-n 1000</code> specifies that the command should run the code 1000 times for each run. This ensures that the results obtained are statistically significant and reliable.</p>
<p>By using <code>%timeit</code> in this way, we can compare the performance of Pandas and Polars for various operations and determine which library is faster and more efficient for each command.</p>
<p>Now let's get into the operations we're going to benchmark.</p>
<h2 id="heading-benchmarking">📊 Benchmarking</h2>
<h3 id="heading-selecting-columns">📈 Selecting Columns</h3>
<p>We start our benchmarking by selecting a column. We select columns 'col_0' and 'col_1' from our data frame using Pandas and Polars.</p>
<pre><code class="lang-python"><span class="hljs-comment"># Selecting columns</span>
<span class="hljs-comment">#Pandas</span>
%timeit -r7 -n <span class="hljs-number">1000</span> df[[<span class="hljs-string">'col_0'</span>,<span class="hljs-string">'col_1'</span>]]

<span class="hljs-comment">#Polars</span>
%timeit -r7 -n <span class="hljs-number">1000</span> pl_df[[<span class="hljs-string">'col_0'</span>,<span class="hljs-string">'col_1'</span>]]
%timeit -r7 -n <span class="hljs-number">1000</span> pl_df.select(pl.col([<span class="hljs-string">'col_0'</span>,<span class="hljs-string">'col_1'</span>]))
</code></pre>
<p>The above code measures the execution time for each of the three operations (Pandas, Polars - using square brackets, and Polars - using select method) for 7 rounds with 1000 executions each.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1679484003463/21216552-3013-4732-a495-dd4d7129fd0b.png" alt class="image--center mx-auto" /></p>
<p>Pandas took 34.6ms, whereas Polars took 1.48μs with indexing and 37.7μs for the select method.</p>
<p>The results show that Polars outperforms Pandas significantly for this operation, and highlight that square bracket indexing performed ~25 times faster than the select API for filter, which is generally the recommended mode. This exception is also called out in the polars docs, <a target="_blank" href="https://pola-rs.github.io/polars-book/user-guide/howcani/selecting_data/selecting_data_indexing.html#selecting-with-indexing">selecting with indexing section</a>.</p>
<blockquote>
<p>Polars select API (37.7μs) is ~1000 times faster than Pandas (34.6ms).<br />Polars square bracket indexing (1.48μs) is about 23,000 times faster than Pandas (34.6ms).</p>
</blockquote>
<h3 id="heading-filtering-rows">📈 Filtering Rows</h3>
<p>Next, we filter rows based on a condition. We select rows where 'col_0' is greater than 0.5 using Pandas and Polars.</p>
<pre><code class="lang-python"><span class="hljs-comment">#Filtering rows </span>
<span class="hljs-comment">#Pandas</span>
%timeit -r7 -n <span class="hljs-number">1000</span> df.query (<span class="hljs-string">'col_0&gt;0.5'</span>)           
<span class="hljs-comment">#Polars        </span>
%timeit -r7 -n <span class="hljs-number">1000</span> pl_df.filter(pl.col(<span class="hljs-string">'col_0'</span>)&gt;<span class="hljs-number">0.5</span>)
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1679485310996/5de45060-7754-40fe-af9a-2142cf344173.png" alt class="image--center mx-auto" /></p>
<p>The results show that Polars is faster than Pandas for this operation as well, but the magnitude is far lesser.</p>
<blockquote>
<p>Pandas (108ms) takes about 2.8 times as long as Polars (38.3ms) in filtering rows.</p>
</blockquote>
<h3 id="heading-groupby">📉 Groupby</h3>
<p>In the next operation, we group by 'col_0' and calculate the mean of 'col_1'. We use both Pandas and Polars for this operation.</p>
<pre><code class="lang-python"><span class="hljs-comment">#Grouping by col_0 and calculating the mean of col_1</span>
%timeit -r7 -n <span class="hljs-number">1000</span> df.groupby(<span class="hljs-string">'col_0'</span>)[<span class="hljs-string">'col_1'</span>].mean()              
%timeit -r7 -n <span class="hljs-number">1000</span> df.groupby(<span class="hljs-string">'col_0'</span>)[<span class="hljs-string">'col_1'</span>].agg(<span class="hljs-string">'mean'</span>)         

<span class="hljs-comment">#polars</span>
%timeit -r7 -n <span class="hljs-number">1000</span> pl_df.groupby(<span class="hljs-string">'col_0'</span>).agg([pl.col(<span class="hljs-string">'col_1'</span>).mean()]) <span class="hljs-comment">#select method</span>
%timeit -r7 -n <span class="hljs-number">1000</span> pl_df.groupby(<span class="hljs-string">'col_0'</span>).agg(pl.mean(<span class="hljs-string">'col_1'</span>))<span class="hljs-comment">#short</span>
</code></pre>
<p>The results show that Polars is slower than Pandas in doing groupby. Polars offers two syntaxes for this operation, and both are faster than Pandas.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1679485806722/eea745f2-16d2-4ff6-9fcb-ee32e33708da.png" alt class="image--center mx-auto" /></p>
<p>In Pandas, .mean() was slightly slower than .agg('mean')</p>
<p>In Polars, using the pl.col function to extract the column and then calling .mean() was slightly faster than calling pl.mean directly within square indexing on the column.</p>
<blockquote>
<p>Overall, Pandas (3.62s) was almost twice as fast as Polars(7s), irrespective of the syntax used.</p>
</blockquote>
<h3 id="heading-conversion-between-wide-and-long-formats">📈 Conversion between wide and long formats</h3>
<p>Lastly, we compare the performance of Pandas and Polars for conversion between wide and long formats using the melt function.</p>
<pre><code class="lang-python"><span class="hljs-comment">#Conversion between wide and long formats</span>
<span class="hljs-comment">#Pandas</span>
%timeit -r7 -n <span class="hljs-number">1000</span> pd.melt(df, id_vars=[<span class="hljs-string">'col_0'</span>], value_vars=[<span class="hljs-string">'col_1'</span>, <span class="hljs-string">'col_2'</span>, <span class="hljs-string">'col_3'</span>, <span class="hljs-string">'col_4'</span>, <span class="hljs-string">'col_5'</span>, <span class="hljs-string">'col_6'</span>, <span class="hljs-string">'col_7'</span>, <span class="hljs-string">'col_8'</span>, <span class="hljs-string">'col_9'</span>])
<span class="hljs-comment">#Polars</span>
%timeit -r7 -n <span class="hljs-number">1000</span> pl_df.melt(id_vars=[<span class="hljs-string">'col_0'</span>], value_vars=[<span class="hljs-string">'col_1'</span>, <span class="hljs-string">'col_2'</span>, <span class="hljs-string">'col_3'</span>, <span class="hljs-string">'col_4'</span>, <span class="hljs-string">'col_5'</span>, <span class="hljs-string">'col_6'</span>, <span class="hljs-string">'col_7'</span>, <span class="hljs-string">'col_8'</span>, <span class="hljs-string">'col_9'</span>])
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1679486496100/9171aa2a-ccfc-4862-b665-6a40f59358c0.png" alt class="image--center mx-auto" /></p>
<blockquote>
<p>Thus Polars (696ms) is about than 5.5 times faster than Pandas (3.88s) for melt.</p>
</blockquote>
<h3 id="heading-wrap-up">🎉 Wrap Up</h3>
<p>In conclusion, Polars offers a compelling alternative to Pandas for data manipulation tasks, particularly when dealing with large datasets that require efficient memory usage and high processing speeds. While Pandas remains a popular and powerful library, Polars' performance advantages make it a valuable addition to any data scientist or data engineer's toolkit.</p>
<p>Here's an image with all the code and runtimes together.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1679488446369/c31afe77-9d72-45f9-96a0-96b17341368e.png" alt class="image--center mx-auto" /></p>
<p>I highly recommend reading the official <a target="_blank" href="https://pola-rs.github.io/polars-book/user-guide/introduction.html">Polars User Guide</a>, if you're loving this series to learn more about the syntax, and query optimization. I'd love to hear on social media, which Polars feature or feature set you want me to cover in the next article.</p>
<p>If you liked this article, please show some love and do share it with your network who would find it valuable. See you in the next article.</p>
]]></content:encoded></item><item><title><![CDATA[Introducing Polars]]></title><description><![CDATA[As data scientists, we are constantly searching for tools that will enable us to manipulate and analyze large datasets efficiently. Pandas is the most widely used tool in the data science community for data manipulation and analysis, and it has been ...]]></description><link>https://blog.phreakyphoenix.tech/introducing-polars</link><guid isPermaLink="true">https://blog.phreakyphoenix.tech/introducing-polars</guid><category><![CDATA[Data Science]]></category><category><![CDATA[big data]]></category><category><![CDATA[Machine Learning]]></category><category><![CDATA[Deep Learning]]></category><category><![CDATA[time-series-database]]></category><dc:creator><![CDATA[Aditya Jyoti Paul]]></dc:creator><pubDate>Mon, 20 Mar 2023 12:53:54 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1678981977657/0f1fac15-d5e4-44a1-a06a-328809a163db.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>As data scientists, we are constantly searching for tools that will enable us to manipulate and analyze large datasets efficiently. Pandas is the most widely used tool in the data science community for data manipulation and analysis, and it has been for a long time. However, as datasets become larger and more complex, pandas can become a bottleneck in the data processing pipeline, especially when dealing with time-series data. In this blog post, we will explore a new data manipulation library, Polars, that aims to provide fast and memory-efficient data manipulation and analysis. We will discuss the key features of Polars and compare it with pandas to see how it stacks up in terms of performance, ease of use, and functionality.</p>
<h3 id="heading-what-is-polars">What is Polars?</h3>
<p>Polars is a new data manipulation library built for Rust, a system programming language that prioritizes safety, speed, and concurrency. Rust is known for its memory safety and speed, making it an excellent choice for building a high-performance data manipulation library like Polars. Polars provides a DataFrame API that is similar to pandas, but with some key differences that make it more efficient and faster for large datasets. Polars can handle large datasets, even if they don't fit into memory, by utilizing lazy evaluation and chunking. It also provides support for time-series data, which can be challenging to handle efficiently in pandas.</p>
<h3 id="heading-key-features-of-polars">Key Features of Polars:</h3>
<ol>
<li><p><strong>Lazy evaluation</strong>: Polars utilizes lazy evaluation to avoid unnecessary computations, which can save a lot of time and memory when working with large datasets. Lazy evaluation is a technique used to delay the computation of an expression until it is needed. This means that Polars will not compute any operation until it is necessary, which reduces the memory footprint of the operation.</p>
</li>
<li><p><strong>Chunking</strong>: Polars can handle datasets that do not fit into memory by chunking the data into smaller pieces. This allows Polars to perform operations on each chunk separately, reducing the memory usage of the operation. The result is that Polars can handle larger datasets than pandas, even if they do not fit into memory.</p>
</li>
<li><p><strong>Time-series support</strong>: Polars provides excellent support for time-series data, which can be challenging to handle efficiently in pandas. Polars provides time-series specific operations, such as rolling and resampling, that are optimized for speed and memory usage.</p>
</li>
<li><p><strong>Parallelism</strong>: Polars is designed to take advantage of modern CPUs with multiple cores. It can use all available CPU cores to perform operations in parallel, making it faster than pandas in many cases.</p>
</li>
<li><p><strong>Rust memory safety</strong>: Rust provides memory safety by preventing memory errors such as buffer overflows and null pointer dereferences. This makes Polars a safe and reliable library to use.</p>
</li>
</ol>
<h3 id="heading-comparing-polars-and-pandas">Comparing Polars and Pandas:</h3>
<ol>
<li><p><strong>Performance</strong>: Polars is faster than pandas for many operations, especially when dealing with large datasets. Polars achieves this performance improvement by utilizing lazy evaluation, chunking, and parallelism. This means that Polars can handle larger datasets and perform operations faster than pandas in many cases.</p>
</li>
<li><p><strong>Memory usage</strong>: Polars uses less memory than pandas, especially when dealing with large datasets. This is because Polars uses lazy evaluation and chunking to reduce the memory footprint of operations.</p>
</li>
<li><p><strong>Ease of use</strong>: Polars has a similar API to pandas, so it is easy to use for those familiar with pandas. However, some operations may require a different approach in Polars, so there may be a learning curve for some users.</p>
</li>
<li><p><strong>Functionality</strong>: Polars has a similar set of functionality as pandas, with some differences due to the design choices made by the developers. However, Polars provides excellent support for time-series data, which can be challenging to handle in pandas.</p>
</li>
</ol>
<p>As a data scientist, you are constantly dealing with large datasets, and performing complex data manipulation tasks. In order to perform these tasks efficiently, you need to use the right tools. Two of the most popular tools for data manipulation are Pandas and Polars. In this blog, we will take a look at Polars and compare it to Pandas, and explore the benefits and drawbacks of using each tool.</p>
<h3 id="heading-introduction-to-polars"><strong>Introduction to Polars</strong></h3>
<p>Polars is a Rust-based data manipulation library that aims to be a faster, safer and more ergonomic alternative to Pandas. It is designed to handle large datasets efficiently, with minimal memory usage, and provides an expressive API for data manipulation. The Polars library is built on top of Apache Arrow, which allows it to efficiently handle large datasets in a distributed environment.</p>
<h3 id="heading-key-differences-between-polars-and-pandas"><strong>Key Differences between Polars and Pandas</strong></h3>
<p>Both Polars and Pandas are powerful tools for data manipulation, but they have some key differences that may make one a better fit for your use case. Here are some of the key differences:</p>
<h4 id="heading-performance">Performance</h4>
<p>One of the key advantages of Polars over Pandas is its performance. Polars is designed to be faster and more memory-efficient than Pandas. This is because it is written in Rust, which is a faster language than Python. Additionally, Polars uses Apache Arrow to store data in a columnar format, which is more memory-efficient than the row-based format used by Pandas. In benchmarks, Polars has been shown to be up to 50 times faster than Pandas for certain operations.</p>
<h4 id="heading-memory-usage">Memory Usage</h4>
<p>Polars uses a columnar format to store data, which can be more memory-efficient than the row-based format used by Pandas. This is because columnar storage allows for better compression and can reduce the amount of memory needed to store data. Additionally, Polars uses lazy evaluation, which means that it only computes operations when they are needed, which can further reduce memory usage.</p>
<h4 id="heading-api">API</h4>
<p>Both Polars and Pandas have powerful APIs for data manipulation. However, the two libraries have some key differences in their APIs. Polars has a more concise API that is designed to be more ergonomic than Pandas. Additionally, Polars supports method chaining, which allows you to chain together multiple operations in a single expression. This can make code more readable and concise.</p>
<h4 id="heading-language">Language</h4>
<p>Polars is written in Rust, which is a faster language than Python. Pandas is written in Python, which is a popular language for data science. While Rust may be faster than Python, it may be harder to learn than Python, especially if you are new to programming.</p>
<h4 id="heading-compatibility">Compatibility</h4>
<p>While Polars has a similar API to pandas, there are some differences in how operations are performed that may require a different approach. However, these differences are minor and should not be a significant barrier to entry for users familiar with pandas. But using proper Polars syntax is the best way to leverage it to it's fullest</p>
<p>In conclusion, Polars is an excellent alternative to pandas for data manipulation and analysis, especially when dealing with large datasets. Its focus on memory efficiency, speed, and support for time-series data make it a valuable addition to any data scientist's toolbox.</p>
<p>Here are some of the differences between Polars and Pandas against the key features:</p>
<div class="hn-table">
<table>
<thead>
<tr>
<td><strong>Feature</strong></td><td><strong>Polars</strong></td><td><strong>Pandas</strong></td></tr>
</thead>
<tbody>
<tr>
<td>Language</td><td>Rust</td><td>Python</td></tr>
<tr>
<td>Memory usage</td><td>Uses less memory, especially when dealing with large datasets.</td><td>Can use a lot of memory, especially when dealing with large datasets.</td></tr>
<tr>
<td>Performance</td><td>Faster than pandas for many operations, especially when dealing with large datasets.</td><td>Slower than Polars for large datasets and some operations.</td></tr>
<tr>
<td>Lazy evaluation</td><td>Utilizes lazy evaluation to avoid unnecessary computations, reducing memory usage.</td><td>Does not utilize lazy evaluation, which can lead to unnecessary computations and increased memory usage.</td></tr>
<tr>
<td>Chunking</td><td>Can handle datasets that do not fit into memory by chunking the data into smaller pieces.</td><td>Cannot handle datasets that do not fit into memory without additional tools like Dask or Vaex.</td></tr>
<tr>
<td>Time-series support</td><td>Provides excellent support for time-series data, including time-series specific operations.</td><td>Supports time-series data, but lacks some of the time-series specific operations provided by Polars.</td></tr>
<tr>
<td>Parallelism</td><td>Designed to take advantage of modern CPUs with multiple cores.</td><td>Does not utilize parallelism by default.</td></tr>
</tbody>
</table>
</div><p>Overall, Polars provides better memory efficiency and performance for large datasets, but requires some additional learning for users familiar with pandas. However, for users working with time-series data or dealing with memory constraints, Polars may be the better choice. If you're not working with over 1M datasets, from my experience, using one vs the other does not have significant differences. Polars does have much faster filtering and reshaping in general. To know more about the performance comparison, stay tuned for the next article.</p>
]]></content:encoded></item><item><title><![CDATA[Deploy your Hashnode blog on a subdirectory serverlessly]]></title><description><![CDATA[🤠 Why read this really long blog :P
Are you a Hashnode blogger looking to host your blog on a subdomain? Are you interested in serverless computing and how it can help you build scalable and cost-effective solutions? Look no further than Cloudflare ...]]></description><link>https://blog.phreakyphoenix.tech/deploy-your-hashnode-blog-on-a-subdirectory-serverlessly</link><guid isPermaLink="true">https://blog.phreakyphoenix.tech/deploy-your-hashnode-blog-on-a-subdirectory-serverlessly</guid><category><![CDATA[Developer]]></category><category><![CDATA[Blogging]]></category><category><![CDATA[Hashnode]]></category><category><![CDATA[cloudflare]]></category><category><![CDATA[serverless]]></category><dc:creator><![CDATA[Aditya Jyoti Paul]]></dc:creator><pubDate>Tue, 14 Mar 2023 13:44:28 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1678799732515/f4025271-4af1-4ded-939c-64f3be941f1d.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-why-read-this-really-long-blog-p">🤠 Why read this really long blog :P</h2>
<p>Are you a Hashnode blogger looking to host your blog on a subdomain? Are you interested in serverless computing and how it can help you build scalable and cost-effective solutions? Look no further than Cloudflare Workers! In this post, we'll walk through how to use Cloudflare Workers to host a Hashnode blog on a subdirectory, while taking advantage of the benefits of serverless computing.</p>
<p>If you haven't read about the advantages of subdirectory hosting for your blog yet, check out <a target="_blank" href="https://blog.phreakyphoenix.tech/subdomains-vs-subdirectories-which-is-right-for-your-blog">my previous post in this series</a>.</p>
<h2 id="heading-what-is-serverless-computing">☁️ What is Serverless Computing?</h2>
<p>Serverless computing is a model in which a cloud provider dynamically manages the allocation and provisioning of servers. This means that developers do not need to worry about managing servers or infrastructure, and can instead focus on writing code. With serverless computing, you only pay for what you use, and you don't need to worry about scaling up or down based on user demand.</p>
<h2 id="heading-what-are-cloudflare-workers">👷 What are Cloudflare Workers?</h2>
<p>Cloudflare Workers are a serverless computing platform that allows developers to write and deploy code that runs on Cloudflare's edge network. This means that the code runs in data centers all around the world, closer to your users, resulting in faster response times and lower latency. Cloudflare Workers are a great option for building serverless applications, as they are highly scalable and cost-effective.</p>
<h2 id="heading-advantages-of-serverless-computing">💪 Advantages of Serverless Computing</h2>
<p>There are many advantages to using serverless computing, including:</p>
<ul>
<li><p><strong>Scalability</strong>: Serverless architectures can automatically scale up or down based on user demand, ensuring that your application can handle sudden spikes in traffic.</p>
</li>
<li><p><strong>Cost-effectiveness</strong>: Serverless computing can help you save money, as you only pay for what you use. This means that you don't need to worry about paying for idle server time.</p>
</li>
<li><p><strong>Reduced complexity</strong>: With serverless computing, you don't need to worry about managing servers or infrastructure, as this is all handled by the cloud provider. This means that you can focus on writing code instead of worrying about server management.</p>
</li>
<li><p><strong>Faster time-to-market</strong>: Because you don't need to worry about infrastructure, serverless computing can help you get your applications to market faster.</p>
</li>
</ul>
<h2 id="heading-so-why-cloudflare">⚡So why Cloudflare?</h2>
<p>Reasons to use Cloudflare for hosting content from a subdomain to a subdirectory:</p>
<ul>
<li><p>Cloudflare Workers provide a serverless platform that allows for running code on their network of servers, reducing the need for traditional hosting infrastructure.</p>
</li>
<li><p>Cloudflare's global network allows for fast delivery of content and can cache content at the edge, further improving performance.</p>
</li>
<li><p>Cloudflare Workers support async requests, which can make it easier to handle multiple requests simultaneously and improve performance.</p>
</li>
<li><p>Using a subdomain allows for separating content and improving security, and Cloudflare Workers make it easy to redirect requests from a subdomain to a subdirectory, giving you the best of both worlds.</p>
</li>
</ul>
<p>Alternatives to using Cloudflare:</p>
<ul>
<li><p>Traditional hosting solutions may require more maintenance and have higher costs than Cloudflare Workers.</p>
</li>
<li><p>Other serverless platforms, such as AWS Lambda, could provide similar functionality but may have a steeper learning curve and require more setup.</p>
</li>
<li><p>Using a reverse proxy server (with Apache or NGINX for example) could also provide similar functionality, but it may require more setup and maintenance than using Cloudflare Workers.</p>
</li>
</ul>
<p>⚠️ This approach is not officially supported by Hashnode and hence can break at any point if the architecture/page structure changes.</p>
<h2 id="heading-im-convinced-show-me-how-to-do-it">🙋 I'm convinced, show me how to do it.</h2>
<p>Awesome, now let's delve into the nitty-gritty of the implementation. Cloudflare workers are really easy to implement. if you're new to this, you can learn more about Workers <a target="_blank" href="https://developers.cloudflare.com/workers/">here</a> and try out the playground <a target="_blank" href="https://cloudflareworkers.com/">here</a>. You can use the Wrangler CLI if you're already comfortable with Worker deployments, else I'd recommend the GUI-based method if you're a beginner, and that's the method I'd follow throughout the rest of this blog.</p>
<h3 id="heading-publish-your-blog-on-your-custom-subdomain">🕸️ Publish your blog on your custom subdomain</h3>
<p>Publishing your blog on a custom subdomain with Hashnode is a pre-requisite to this, but if you haven't done that yet, please follow the detailed steps for the same <a target="_blank" href="https://support.hashnode.com/en/articles/5755362-how-to-map-a-custom-domain">here</a>. I recommend just setting up the CNAME record to <code>hashnode.network</code> on Cloudflare DNS, and keeping the orange cloud on.</p>
<h3 id="heading-verify-your-domain-on-cloudflare">🔑 Verify your domain on Cloudflare</h3>
<ol>
<li><p>Click on Create Site and add your domain name. So if you're blog is currently at blog.example.com, enter example.com.</p>
</li>
<li><p>Select the Plan, Free works for most use cases, including mine, let's start off with that, thanks to Cloudflare for their generous limits.</p>
</li>
<li><p>Review your nameservers, you'd need to point your nameservers to Cloudflare, step-by-step instructions for which are available <a target="_blank" href="https://developers.cloudflare.com/dns/zone-setups/full-setup/setup/">here</a>. This can take up to 24 hrs, but usually takes a few minutes.</p>
</li>
<li><p>Ultimately you should see your domain name with a green tick and the word "Active" like this.</p>
</li>
</ol>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1678736662255/9428caef-33a5-4351-a34b-27fb5e7664ea.png" alt class="image--center mx-auto" /></p>
<h3 id="heading-create-your-worker">👷 Create your Worker</h3>
<p>You can create a worker either from <code>Workers &gt; Overview &gt; Create a service</code> from the left pane on your <a target="_blank" href="https://dash.cloudflare.com/">primary dashboard</a></p>
<p>or</p>
<p>Click on your domain name (example.com) and then go to <code>Workers Routes &gt; Manage Workers&gt; Create a Service.</code></p>
<p>And now you'd be here:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1678736796822/15e17dc6-ef24-496c-9fd0-c07286147fa2.png" alt class="image--center mx-auto" /></p>
<p>Give your worker a recognizable name, here I've named it <code>d2s</code> short for sub<strong>d</strong>omain-<strong>to</strong>-<strong>s</strong>ubdirectory, select HTTP router and click <code>Create Service</code>.</p>
<p>Kudos on creating your first worker service. Now we need to add the code.</p>
<h3 id="heading-define-the-data-flow-and-redirect-paths">🪄 Define the data flow and redirect paths</h3>
<p>Click on the <code>Quick Edit</code> button to access the Worker code.</p>
<p>The entire worker.js file is hosted on <a target="_blank" href="https://github.com/phreakyphoenix/cloudflare-deploy-subdomain-to-subdirectory">GitHub</a>, and you can just copy the worker.js file and change the hostname from blog.example.com to the domain where you wish to host it.</p>
<h3 id="heading-set-the-routes">🧭 Set the Routes</h3>
<p>Browse over to the Workers tab on the left pane and click on Manage Service, and go to the Routes section. Add <code>example.com/*</code> to Route and your domain the Zone. You may disable the pre-defined routes if you wish, here' my setup as a reference, you should see your active active routes, like you see at the bottom of this image.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1678738030371/a031ae05-1ba4-41e6-8380-af9867f31704.png" alt class="image--center mx-auto" /></p>
<h3 id="heading-woohoo">🎉 Woohoo!</h3>
<p>That's it! Your blog is now successfully deployed to example.com/blog and also accessible via blog.example.com. You can verify a new DNS <code>Worker</code> record is created in your DNS settings as well pointing to the worker you just deployed.</p>
<p>Pat yourself on your back, coz you deserve it and here's a cute panda rejoicing with you!</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1678739814094/b36b2210-4fce-4acf-8703-680588d2f44e.png" alt="Happy Panda after deploying to subdirectory auccessfully, credits to Midjourney" class="image--center mx-auto" /></p>
<h2 id="heading-the-secret-sauce-in-workerjs">🧙The Secret Sauce in worker.js</h2>
<p>I wanted to save this part for the last so as not to bog you down with code, but if you're a brave adventurer and want to extend the capabilities of your blog, worry not, as I shall explain how the code works and all the interesting nuggets of how I made this work here.</p>
<p>Some helpful references before we begin:</p>
<ol>
<li><p><a target="_blank" href="https://createtoday.io/posts/how-to-serve-a-subdomain-as-a-subdirectory-using-cloudflare">Create Today Demo on deploying a simple site from subdomain to subdirectory</a>.</p>
</li>
<li><p><a target="_blank" href="https://blog.cloudflare.com/subdomains-vs-subdirectories-improved-seo-part-2/">Cloudflare Blog on SEO best practices and subdirectory implementation</a></p>
</li>
</ol>
<p>These were the only two resources I could find which inspired my work.</p>
<h3 id="heading-defining-the-global-variables">🌎 Defining the global variables</h3>
<p>First we'll define our variables like hostname, blog directory and asset pathnames like this.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// keep track of all our blog endpoints here</span>
<span class="hljs-keyword">const</span> myBlog = {
  <span class="hljs-attr">hostname</span>: <span class="hljs-string">"blog.example.com"</span>,
  <span class="hljs-attr">targetSubdirectory</span>: <span class="hljs-string">"/blog"</span>,
  <span class="hljs-attr">assetsPathnames</span>: [<span class="hljs-string">"/_next/"</span>, <span class="hljs-string">"/js/"</span>, <span class="hljs-string">'/api/'</span>, <span class="hljs-string">'_axiom'</span>, <span class="hljs-string">'/ping/'</span>] 
}
</code></pre>
<h3 id="heading-explanations-of-the-code-segments">📜 Explanations of the code segments</h3>
<p>We create a function named <code>handleRequest</code> that handles the routing logic based on the request method along with 2 helper classes <code>AttributeRewriter</code>, <code>ScriptAdder</code> that do an on-the-fly code rewrite for the blog content hosted on the subdirectory. We also create a helper function <code>gatherResponse</code> to return the response body a s a string. We finally add an Event Listener that listens to fetch requests and responds with the result of <code>handleRequest</code>.</p>
<p>Let's understand them one by one.</p>
<p>1. <code>GatherResponse</code> awaits and returns the response body as a string. If the Content-Type is JSON, then it first converts it to a string else just returns the text of the response.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">gatherResponse</span>(<span class="hljs-params">response</span>) </span>{
  <span class="hljs-keyword">const</span> contentType = response.headers.get(<span class="hljs-string">'content-type'</span>) || <span class="hljs-string">''</span>;
  <span class="hljs-keyword">if</span> (contentType.includes(<span class="hljs-string">'application/json'</span>)) {
    <span class="hljs-keyword">return</span> <span class="hljs-built_in">JSON</span>.stringify(<span class="hljs-keyword">await</span> response.json());
  }
  <span class="hljs-keyword">return</span> response.text();
}
</code></pre>
<p>2. <code>AttributeRewriter</code> class helps rewrite the relative URLs in the HTML content sent by Hashnode to the client so that the subdirectory-hosted site communicates as expected. Without it, requests would be sent to /awesome-blog (since blogs on Hashnode are all on the root directory of the subdomain) instead of /blog/awesome-blog. We want the requests to be sent to the targetSubdirectory /blog instead.</p>
<pre><code class="lang-javascript"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">AttributeRewriter</span> </span>{
  <span class="hljs-keyword">constructor</span>(attributeName) {
    <span class="hljs-built_in">this</span>.attributeName = attributeName;
  }
  element(element) {
    <span class="hljs-keyword">const</span> attribute = element.getAttribute(<span class="hljs-built_in">this</span>.attributeName);
    <span class="hljs-comment">//add check for targetSubdirectory start for nested scenarios</span>
    <span class="hljs-keyword">if</span> (attribute &amp;&amp; !attribute.startsWith(<span class="hljs-string">'https://'</span>)) 
    {
      element.setAttribute(<span class="hljs-built_in">this</span>.attributeName, myBlog.targetSubdirectory+attribute);
    }
  }
}

<span class="hljs-keyword">const</span> htmlrewriter = <span class="hljs-keyword">new</span> HTMLRewriter()
  .on(<span class="hljs-string">'a'</span>, <span class="hljs-keyword">new</span> AttributeRewriter(<span class="hljs-string">'href'</span>))
</code></pre>
<p>3. <code>ScriptAdder</code> adds a custom JS script to prepend targetSubdirectory ie. /blog in the browser URL and history for any blog posts that are opened without the targetSubdirectory present. Without this, relative URL refreshes and back and forward flows would break.</p>
<pre><code class="lang-javascript"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ScriptAdder</span> </span>{
  element(element) {
      element.prepend(<span class="hljs-string">'&lt;script&gt;function o(){location.href!=a&amp;&amp;(location.replace("'</span>+myBlog.targetSubdirectory+<span class="hljs-string">'"+location.pathname),a=location.href)}var a=location.href;setInterval(o,1);&lt;/script&gt;'</span>,{<span class="hljs-attr">html</span>: <span class="hljs-literal">true</span>});
  }
}

<span class="hljs-keyword">const</span> scriptadder = <span class="hljs-keyword">new</span> HTMLRewriter()
  .on(<span class="hljs-string">'head'</span>, <span class="hljs-keyword">new</span> ScriptAdder())
</code></pre>
<ol>
<li><p><code>handleRequest</code> checks if the content is a GET or POST request.</p>
<ol>
<li><p>POST responses are first fetched from the subdomain-hosted site, and then sent over to the request originating from the subdirectory. Additionally, for /api/collect requests for pageviews, the payload content itself must be modified with the correct URL.</p>
</li>
<li><p>GET requests are handled differently based on whether they're for a blog document, or assets (CSS, JS, etc) and passed along if they're unrelated.</p>
</li>
</ol>
</li>
</ol>
<pre><code class="lang-javascript"><span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">handleRequest</span>(<span class="hljs-params">request</span>) </span>{
    <span class="hljs-keyword">const</span> parsedUrl = <span class="hljs-keyword">new</span> URL(request.url)
    <span class="hljs-keyword">const</span> requestMatches = <span class="hljs-function"><span class="hljs-params">match</span> =&gt;</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">RegExp</span>(match).test(parsedUrl.pathname)

    <span class="hljs-comment">// console.log(request.body)</span>
    <span class="hljs-keyword">if</span> (request.method === <span class="hljs-string">'POST'</span>) {
      <span class="hljs-keyword">if</span> (requestMatches(<span class="hljs-string">"/api/collect"</span>)) {
        <span class="hljs-keyword">var</span> post_body = <span class="hljs-keyword">await</span> request.json()
        <span class="hljs-built_in">console</span>.log(post_body)
        <span class="hljs-keyword">var</span> req_url = post_body[<span class="hljs-string">"payload"</span>][<span class="hljs-string">"url"</span>]
        req_url = req_url.split(<span class="hljs-string">"/"</span>)[<span class="hljs-number">2</span>];
        post_body[<span class="hljs-string">"payload"</span>][<span class="hljs-string">"url"</span>] = <span class="hljs-string">'/'</span>+req_url;
        post_body[<span class="hljs-string">"payload"</span>][<span class="hljs-string">"hostname"</span>] = <span class="hljs-string">`<span class="hljs-subst">${myBlog.hostname}</span>`</span>;

        <span class="hljs-keyword">const</span> mod_req = {
        <span class="hljs-attr">payload</span>: post_body[<span class="hljs-string">"payload"</span>],
        <span class="hljs-attr">type</span>: <span class="hljs-string">"pageview"</span>,
        };

        <span class="hljs-built_in">console</span>.log(mod_req)
        <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> fetch(<span class="hljs-string">`https://<span class="hljs-subst">${myBlog.hostname}</span>/<span class="hljs-subst">${parsedUrl.pathname}</span>`</span>, mod_req);
        <span class="hljs-keyword">const</span> results = <span class="hljs-keyword">await</span> gatherResponse(response);
        <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> Response(results, request);
      }
      <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> fetch(<span class="hljs-string">`https://<span class="hljs-subst">${myBlog.hostname}</span>/<span class="hljs-subst">${parsedUrl.pathname}</span>`</span>, request);
      <span class="hljs-keyword">const</span> results = <span class="hljs-keyword">await</span> gatherResponse(response);
      <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> Response(results, request);
    }

    <span class="hljs-comment">// else method is GET</span>

    <span class="hljs-comment">// blog HTML</span>
    <span class="hljs-keyword">if</span> (requestMatches(myBlog.targetSubdirectory)) {
      <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"this is a request for a blog document"</span>, parsedUrl.pathname);

      <span class="hljs-keyword">const</span> pruned = parsedUrl.pathname.split(<span class="hljs-string">"/"</span>).filter(<span class="hljs-function"><span class="hljs-params">part</span> =&gt;</span> part);
      <span class="hljs-keyword">if</span> (parsedUrl.pathname.startsWith(myBlog.targetSubdirectory+<span class="hljs-string">'/newsletter'</span>)){
        <span class="hljs-keyword">return</span> scriptadder.transform (htmlrewriter.transform(<span class="hljs-keyword">await</span>(fetch(<span class="hljs-string">`https://<span class="hljs-subst">${myBlog.hostname}</span>/<span class="hljs-subst">${pruned.slice(<span class="hljs-number">1</span>).join(<span class="hljs-string">"/"</span>)}</span>`</span>))));
      }
      <span class="hljs-keyword">if</span> (pruned.length==<span class="hljs-number">1</span>){
        <span class="hljs-keyword">return</span> scriptadder.transform (htmlrewriter.transform(<span class="hljs-keyword">await</span>(fetch(<span class="hljs-string">`https://<span class="hljs-subst">${myBlog.hostname}</span>`</span>))));
      }
      <span class="hljs-keyword">else</span>{
        <span class="hljs-keyword">return</span> htmlrewriter.transform(<span class="hljs-keyword">await</span>(fetch(<span class="hljs-string">`https://<span class="hljs-subst">${myBlog.hostname}</span>/<span class="hljs-subst">${pruned.slice(<span class="hljs-number">1</span>).join(<span class="hljs-string">"/"</span>)}</span>`</span>)));
      }
    }

    <span class="hljs-comment">// blog assets</span>
    <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (myBlog.assetsPathnames.some(requestMatches)) {
      <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"this is a request for other blog assets"</span>, parsedUrl.pathname)
      <span class="hljs-keyword">const</span> assetUrl = request.url.replace(parsedUrl.hostname, myBlog.hostname);
      <span class="hljs-built_in">console</span>.log(assetUrl)
      <span class="hljs-keyword">return</span> fetch(assetUrl)
    }

    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"this is a request to my root domain"</span>, parsedUrl.host, parsedUrl.pathname);
    <span class="hljs-comment">// unrelated stuff, do nothing</span>
    <span class="hljs-keyword">return</span> fetch(request)
  }
</code></pre>
<h3 id="heading-conclusion">🙌 Conclusion</h3>
<p>If you came this far, I congratulate you on trudging boldly to enlightenment, and welcome any contributions and suggestions for this project on my <a target="_blank" href="https://github.com/phreakyphoenix/cloudflare-deploy-subdomain-to-subdirectory">GitHub repo</a>.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1678747981062/86599f46-cf96-4298-baf9-30ebd1834aa7.webp" alt="meme video congraatulatory" class="image--center mx-auto" /></p>
<p>Thanks for reading, please show some love and share with your followers on social media. See you in the next article 👋</p>
]]></content:encoded></item><item><title><![CDATA[Subdomains vs Subdirectories: Which is right for your blog?]]></title><description><![CDATA[Introduction
When starting a blog, one of the first things to consider is where to host it. Two popular options are to use a subdomain or a subdirectory. While both methods allow you to add a blog to your site, they differ in several key areas, inclu...]]></description><link>https://blog.phreakyphoenix.tech/subdomains-vs-subdirectories-which-is-right-for-your-blog</link><guid isPermaLink="true">https://blog.phreakyphoenix.tech/subdomains-vs-subdirectories-which-is-right-for-your-blog</guid><category><![CDATA[SEO]]></category><category><![CDATA[SEO for Developers]]></category><category><![CDATA[Search Engines]]></category><category><![CDATA[Blogging]]></category><category><![CDATA[#content marketing]]></category><dc:creator><![CDATA[Aditya Jyoti Paul]]></dc:creator><pubDate>Wed, 22 Feb 2023 14:21:58 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1677078257938/6790f590-afab-4ada-bea0-d36b173b7503.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-introduction">Introduction</h2>
<p>When starting a blog, one of the first things to consider is where to host it. Two popular options are to use a subdomain or a subdirectory. While both methods allow you to add a blog to your site, they differ in several key areas, including search engine optimization (SEO) and technical implementation. In this article, we'll compare the pros and cons of each approach to help you decide which one is best for your blog.</p>
<h2 id="heading-subdomains">Subdomains</h2>
<p>A subdomain is a domain that is part of a larger domain, but is technically a separate website. It typically appears as a prefix to the main domain, like <a target="_blank" href="http://blog.example.com">blog.example.com</a>. Here are some of the benefits and drawbacks of using a subdomain for your blog:</p>
<h3 id="heading-pros">Pros</h3>
<ol>
<li><p><strong>Separate identity</strong>: A subdomain can give your blog a separate identity from the main site, which may be useful if you want to differentiate your blog from the rest of your content.</p>
</li>
<li><p><strong>Easy setup</strong>: Setting up a subdomain is relatively easy, and most web hosts allow you to create one with just a few clicks.</p>
</li>
<li><p><strong>Scalability</strong>: If your blog grows in popularity and you need more resources to handle traffic, you can upgrade your subdomain to a dedicated server or cloud hosting. Internationalization: Subdomains can be a useful way to target international audiences. For example, if you have a blog in English and want to offer a version in Spanish, you could create a subdomain like <a target="_blank" href="http://es.example.com">es.example.com</a>.</p>
</li>
</ol>
<h3 id="heading-cons">Cons</h3>
<ol>
<li><p><strong>SEO challenges</strong>: While subdomains are a good way to organize content, search engines may view them as separate websites with less authority than the main site. This means it may be more difficult to rank well in search engine results pages (SERPs).</p>
</li>
<li><p><strong>Backlink dilution</strong>: When you use a subdomain, any backlinks to your blog will not help the main site's SEO. This is because the subdomain is seen as a separate website with its own backlink profile.</p>
</li>
<li><p><strong>Technical complexity</strong>: Setting up a subdomain requires more technical expertise than using a subdirectory. You may need to create a separate hosting account, configure DNS settings, and manage multiple databases.</p>
</li>
</ol>
<h2 id="heading-subdirectories">Subdirectories</h2>
<p>A subdirectory is a folder on your main domain that contains your blog content. It typically appears as a suffix to the main domain, like <a target="_blank" href="http://example.com/blog">example.com/blog</a>. Here are some of the benefits and drawbacks of using a subdirectory for your blog:</p>
<h3 id="heading-pros-1">Pros</h3>
<ol>
<li><p><strong>SEO benefits</strong>: Using a subdirectory can give your blog a boost in search engine rankings. This is because the subdirectory is seen as part of the main site, and any authority the main site has is passed on to the blog.</p>
</li>
<li><p><strong>Easy setup</strong>: Most content management systems (CMS) allow you to set up a blog within a subdirectory with minimal technical knowledge.</p>
</li>
<li><p><strong>Backlink authority</strong>: Any backlinks to your blog will also help the main site's SEO, as they are seen as part of the same domain.</p>
</li>
<li><p><strong>Consistency</strong>: By using a subdirectory, you can keep your blog consistent with the rest of your site's branding and design.</p>
</li>
</ol>
<h3 id="heading-cons-1">Cons</h3>
<ol>
<li><p><strong>Limited scalability</strong>: If your blog grows in popularity, you may need to upgrade your hosting plan to handle the traffic. This can be more difficult than upgrading a subdomain, as it may require a more expensive plan or dedicated server.</p>
</li>
<li><p><strong>Less flexibility</strong>: If you want to create a separate identity for your blog, using a subdirectory may not be the best choice. It can be more difficult to differentiate your blog from the rest of your content with a subdirectory.</p>
</li>
</ol>
<p>In conclusion, the decision to use subdomains or subdirectories for blogs depends on the specific needs and goals of the website. Subdomains may be easier to set up and can be useful for targeting specific markets or branding purposes, but they can also dilute keywords and backlinks, making it harder for the root domain to rank in search results.</p>
<p>On the other hand, subdirectories may require more setup and configuration, but they can help consolidate keyword and backlink authority, which can improve the overall SEO of the website. In addition, subdirectories are already built into basic websites, making them a more straightforward option for many website owners.</p>
<blockquote>
<p>Based on the points discussed in this article, it is clear that <strong>subdirectories are a superior option for blogs, particularly for website owners who want to improve their SEO</strong>. While subdomains may be appealing for branding purposes, they can dilute keyword and backlink authority, which can ultimately hurt the SEO of the root domain.</p>
</blockquote>
<p>Overall, the decision to use subdomains or subdirectories for blogs requires careful consideration of the specific needs and goals of the website, as well as an understanding of the potential trade-offs and benefits of each approach.</p>
<h2 id="heading-some-industry-references">Some Industry References</h2>
<ol>
<li><p>A <a target="_blank" href="https://moz.com/blog/google-organic-click-through-rates-in-2014">study by Moz</a> in 2014 also found that using subdirectories was better for SEO than using subdomains. The study analyzed 90,000 root domains and found that subdirectories were more likely to rank higher in SERPs than subdomains. Check out a video explainer <a target="_blank" href="https://fast.wistia.net/embed/iframe/dyzyhh500a?seo=false&amp;videoFoam=true">here</a>.</p>
</li>
<li><p><a target="_blank" href="https://www.searchenginejournal.com/google-treats-subdomains-subdirectories-john-mueller-says/254687/">Google’s own John Mueller has also stated that subdirectories are generally better than subdomains for SEO, when the content is related to the site</a>. In a <a target="_blank" href="https://www.youtube.com/watch?v=kQIyk-2-wRg">webmaster hangout in 2018</a>, Mueller said that it’s easier for Google to understand the structure and hierarchy of a website that uses subdirectories, as opposed to one that uses subdomains.</p>
</li>
<li><p>Here's a great <a target="_blank" href="https://www.semrush.com/blog/subdomain-vs-subdirectory/">in-depth article</a> from Semrush on this topic.</p>
</li>
</ol>
<h2 id="heading-conclusion">Conclusion</h2>
<p>These studies and statements from industry experts suggest that using subdirectories can have SEO benefits compared to subdomains. However, it’s important to note that there are many factors that can impact a website’s SEO, and using subdirectories alone is not a guaranteed way to improve SEO.</p>
]]></content:encoded></item><item><title><![CDATA[Hacking the Food Sourcing Problem for young Indians]]></title><description><![CDATA[What's this all about?
Jugaad and Dhanda are two words that are ingrained into every Indian's soul. But what is the one thing that we all love and the absence of which keeps us awake at night? Food.

This is article especially suited for students and...]]></description><link>https://blog.phreakyphoenix.tech/hacking-the-food-sourcing-problem-for-young-indians</link><guid isPermaLink="true">https://blog.phreakyphoenix.tech/hacking-the-food-sourcing-problem-for-young-indians</guid><category><![CDATA[technology]]></category><dc:creator><![CDATA[Aditya Jyoti Paul]]></dc:creator><pubDate>Sun, 19 Feb 2023 15:53:09 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1676817324571/f12800ca-edcc-4f2d-bfaf-012e1cbcfd9d.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h3 id="heading-whats-this-all-about">What's this all about?</h3>
<p><em>Jugaad</em> and <em>Dhanda</em> are two words that are ingrained into every Indian's soul. But what is the one thing that we all love and the absence of which keeps us awake at night? Food.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1676484939549/9f29992a-e93d-48d4-bd84-19a99f8cfd5c.png" alt class="image--center mx-auto" /></p>
<p>This is article especially suited for students and bachelors but can be useful for everyone (who eats).</p>
<p>I'll keep updating the article as I find new tips and tricks and interesting insights. The article is broken down into sections so jump to the parts you're curious about.</p>
<h3 id="heading-backstory-and-motivation">Backstory and Motivation</h3>
<p>A lot of my friends, colleagues and past batchmates are surprised how I survived for the last 5-6 years only by ordering online. Most of the first-time reactions are surprise, shock, and amusement and most of the common questions can be grouped into the following points</p>
<ul>
<li><p>How I don't fall sick</p>
</li>
<li><p>How I save money</p>
</li>
<li><p>How do I maintain my schedule</p>
</li>
</ul>
<p>To answer all these questions and to make life a bit easier for others to follow my footsteps, I'm penning my experiences and tons of tips and tricks in this blog.</p>
<h3 id="heading-what-is-this-food-sourcing-problem">What is this Food Sourcing Problem?</h3>
<p>I'm a Computer Science graduate with a penchant for algorithms so of course, when one day I left for college and was running short on cash, I sat down to understand where all the time and money goes and how I can optimize the process to put food in my belly as simply and efficiently as possible</p>
<p>The food sourcing problem is based on reducing the effective spend on food, which is directly related to the cost of purchasing the food and the time spent on the same.</p>
<p>Below is an equation for the mathematically inclined</p>
<p>$$effectiveSpend = cost * timeValue$$</p>
<p>Now when ordering online, we massively mitigate the time component, and usually pay a slight premium compared to getting it at the restaurant. This is to compensate for the time and effort of the delivery agent, the food delivery platform and other middle stakeholders.</p>
<p>But sometimes online ordering it's also much cheaper, many restaurants on these aggregator platforms are actually cloud/ghost kitchens. In this business model, they don't have any seating area for customers and operate solely towards online customers often sharing cooking resources with multiple brands all under one roof.</p>
<p>So what does it all mean? Is ordering online cheaper? Let's break this down in the next section.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1676488648110/0ddefba1-6efe-41bb-b78f-71ea7cf59182.png" alt class="image--center mx-auto" /></p>
<h3 id="heading-analysis">Analysis</h3>
<p>Online Food Ordering is right for you if you're living alone or are students, bachelors, etc. Let's see from an example,</p>
<p>If you're living alone and live in Kolkata, your monthly spend on the food is going to include:</p>
<ol>
<li><p>Cost of Raw Materials (Oil, salt, veggies, rice, atta etc): Rs 3000-3500</p>
</li>
<li><p>Time Spent: 60 hrs/month.</p>
</li>
</ol>
<p>For 2 people, your monthly spend incurred is</p>
<ol>
<li><p>Cost of Raw Materials (Oil, salt, veggies, rice, atta etc): Rs 4500-5000</p>
</li>
<li><p>Time Spent: ~70 hrs/month</p>
</li>
</ol>
<p>Thus if you're cooking you'd certainly be better off if you invest in a refrigerator and share the food and cooking responsibilities with a roommate.</p>
<p>Now let's analyze online ordering, I'll use my numbers in this example</p>
<p>Living alone:</p>
<ol>
<li><p>Cost of food : Rs 4500/month (after discounts, including all charges)</p>
</li>
<li><p>Time: ~5 hrs /month</p>
</li>
</ol>
<p>For 2 people:</p>
<ol>
<li><p>Cost of food : 5000-6000 /month (after discounts, including all charges)</p>
</li>
<li><p>Time: ~6 hrs /month</p>
</li>
</ol>
<p>Below is a tabular illustration of this analysis, effective spend accounts for both the cost of materials and medium of cooking along with the monetary value of the time.</p>
<div class="hn-table">
<table>
<thead>
<tr>
<td></td><td>Cost of Raw Materials and Gas</td><td>Time Spent</td><td>Effective Spend</td></tr>
</thead>
<tbody>
<tr>
<td>Cooking for 1 person</td><td>Rs 3200</td><td>60 hrs/month</td><td>~ Rs 11,000</td></tr>
<tr>
<td>Cooking for 2 people</td><td>Rs 4700</td><td>70 hrs/month</td><td>~ RS 13800</td></tr>
<tr>
<td>Ordering for 1 person</td><td>Rs 4500</td><td>5 hrs/month</td><td>~ Rs 5150</td></tr>
<tr>
<td>Ordering for 2 people</td><td>Rs 5500</td><td>6 hrs/month</td><td>~ Rs 6300</td></tr>
</tbody>
</table>
</div><p>Assumptions: Value of 1 hr time has been assumed to be Rs 130 for this illustration, typical hourly rates in India range from Rs 90 - 220.<br /><em>I encourage you to fill this table with your numbers to see how much you'd save.</em></p>
<p>Now that we've shown we can save over 50% even at this hourly rate, I hope I've got your attention and you'd be amazed by the savings you'd get if your hourly rate goes over Rs 1500. At that point, your monthly food expenses would be worth ~4 hrs of work, so saving the hours will be pivotal and the effective savings will be ~90%.</p>
<h3 id="heading-the-solution">The Solution</h3>
<p>Of course, online deliveries are cheaper, just as ridesharing is cheaper, the unit economics speak for themselves and it's just time until more people accept it and include it in their lives. But being successful in this, and making significant savings, still does come with a learning curve, and I'm here to make this journey simpler.</p>
<p>So here are my super secret tips to be successful in this online ordering world</p>
<ol>
<li><p><strong>Act decisively</strong>: Always have a clear mind on what you want to order, browsing restaurants for hours will make you lose the very hrs you set out so hard to achieve, I spend no more than 10 mins/ day to order of which ~8 mins is spent on browsing restaurants, comparing discounts (sometimes across devices) and making the payment (usually instantaneous), rest is spent in guiding the delivery partner to my place.</p>
</li>
<li><p><strong>Know the aggregator app like the back of your hand</strong>: I can recite the items I usually order, the restaurants I order from, the discount and offer codes, card benefits and when each discount starts and ends every day in my sleep. This becomes a habit like day-traders know the price levels of every major index they trade and other macro factors affecting them. Initially you might want to sit down once to learn about the various offers and features on the aggregator app you choose. I for example, use Swiggy.</p>
</li>
<li><p><strong>Know the card offers:</strong> You can speed up your saving with cashback. Cards like <a target="_blank" href="https://www.sbicard.com/invite/j0Rbm8xCOnL">SBI Cashback Card</a> give 5% cashback on all online transactions including Swiggy, Zomato, Blikit, BigBasket etc (excluding rent, wallet reload etc). There are many awesome offers on these platforms from cards like Axis, OneCard, Slice, AU Bank and Union Bank of India as well.</p>
</li>
<li><p><strong>Find out the best timings to order:</strong> The restaurant discounts are not static, ordering at peak hours is a sure-shot way of not getting a good deal. As you explore the platform keep looking at when the restaurant offers start and end, this will vary fr each restaurant. I for example find amazing breakfast deals around 8am-noon and dinner deals 10pm-2am, YMMV.</p>
</li>
<li><p><strong>Try to increase Avg Order Value</strong>: It's possible to save ~25% more by ordering items with a combined order value over 400, this way if you already have a microwave and a fridge you can save quite a lot more. Another idea discussed above is to find a food partner.</p>
</li>
<li><p><strong>Don't underestimate combining offers:</strong> I often save over 70% for each item, by :</p>
<ol>
<li><p><strong>Buying Swiggy vouchers from Woohoo/Gyftr: ~12%</strong>, the voucher is already discounted by ~8%, on top of which I get back 5% cashback.</p>
</li>
<li><p><strong>Using the Swiggy voucher on restaurants offering ~60% off.</strong><br /> In fact, many times, you'd be able to save even up to 30% compared to having the same item in the restaurant.</p>
<p> You could also directly use a lot of card offers directly on Swiggy for example, Axis Select, My Zone has 40% off offers. if you're an Airtel customer, using the Airtel Axis card which gives you 10% cahback is a decent deal too but I find the cashback card+voucher strategy much better.</p>
</li>
</ol>
</li>
<li><p><strong>Use the subscriptions to the fullest</strong>: If you're using Swiggy or Zomato or similar aggregator service regularly, make sure you sign up for their Subscriptions. It's a steal deal at around 799 for a year, when I had been switched over from the Swiggy Super Binge plan.</p>
<p> Now the prices seem to have gone up drastically to around 2000 Rs. For me the subscription might still be sensible, but now I'd suggest you take the plan only if you're ordering regularly, and preferably ordering for your family, friends etc too.</p>
</li>
</ol>
<blockquote>
<p>The biggest reason I'd choose the subscription is for the <strong>free delivery</strong>.<br />To find if it's right for you, just ask yourself this:</p>
<p><strong>"How many orders would you do in a year and how much on average would you like to pay for each delivery?"</strong></p>
<p>If the product of these two is not lesser than the subscription cost by over 25%, get the subscription, as it'd also have additional benefits in terms of dining out and grocery orders etc.</p>
</blockquote>
<p>In the image, you'd see I've saved over 11k this year, but in reality, the real value addition of Swiggy One would be closer to 7k, you'd have 'saved' ~3k anyway due to restaurant discounts even without the subscription, and many of the 'only for Swiggy One customers' offers are just rebranded regular customer offers.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1676546445166/ba70309e-d770-4bbe-b04d-ef9dedea5b45.jpeg" alt class="image--center mx-auto" /></p>
<h3 id="heading-conclusion">Conclusion</h3>
<p>Thus we discussed how we can save 50-90% per month by ordering online, and I also wanted to touch up on the other two questions I get ie. how I maintain the schedule and stay fit. Personally, I found online ordering to be even better than cooking for my schedule and as long as I'm not ordering super processed food everyday (like KFC), I've noticed no major detriment to health. To be honest I found externally ordered food much healthier than the super oily mess food in my canteen. But again YMMV.</p>
<p>Thanks to the amazing delivery agents making our lives easier every day.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1676494485673/b5bf5772-49d1-4316-8610-2eb12207aaf7.png" alt class="image--center mx-auto" /></p>
<p>💸 <strong>Support my work and earn Rs 500</strong></p>
<p>One of the key strategies to save money by online ordering requires using the SBI Cashback Credit Card, which I'd like to recommend.</p>
<p><strong>You can earn an additional Rs 500</strong> by using my referral code j0Rbm8xCOnL, or by <strong>applying for any SBI card via this link</strong> <a target="_blank" href="https://www.sbicard.com/invite/j0Rbm8xCOnL">sbicard.com/invite/j0Rbm8xCOnL</a>. Once you are onboarded, I too would receive the same incentive which helps support this work.</p>
<p>I've been using this card for almost a year, and had recouped its annual fees of 999+gst in just 2 months of cashback, which is anyway waived off on spending 2 lacs, thus this card is working extremely well for me now.</p>
<p><strong>Parting thoughts</strong></p>
<p>Cheers to your first 500 Rs saved through this. 🥳 Wish you all the best in your journey of simplifying and optimizing food sourcing in your life.</p>
<p>Do you have any other tips and tricks that I missed? Let me know in the comments. ✌️</p>
]]></content:encoded></item><item><title><![CDATA[Paper Review: Understanding Deep Learning Requires Rethinking Generalization]]></title><description><![CDATA[Introduction
The paper “Understanding Deep Learning Requires Rethinking Generalization” [1] caused quite a stir in the Deep Learning and Machine Learning research communities, and was one of the three papers awarded the Best Paper Award in ICLR 2017....]]></description><link>https://blog.phreakyphoenix.tech/paper-review-understanding-deep-learning-requires-rethinking-generalization</link><guid isPermaLink="true">https://blog.phreakyphoenix.tech/paper-review-understanding-deep-learning-requires-rethinking-generalization</guid><category><![CDATA[research]]></category><category><![CDATA[Artificial Intelligence]]></category><category><![CDATA[Machine Learning]]></category><category><![CDATA[Deep Learning]]></category><dc:creator><![CDATA[Aditya Jyoti Paul]]></dc:creator><pubDate>Mon, 20 Apr 2020 00:58:05 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1673918080909/22fb1647-2cc5-41fa-a9b0-a4e84f97c757.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h3 id="heading-introduction">Introduction</h3>
<p>The paper “Understanding Deep Learning Requires Rethinking Generalization” [1] caused quite a stir in the Deep Learning and Machine Learning research communities, and was one of the three papers awarded the Best Paper Award in ICLR 2017. This paper approaches the question:</p>
<p><code>"What is it that distinguishes neural networks that generalize well from those that don’t?"</code></p>
<p>It tries to mitigate some of the existing misconceptions in that regard, through a host of randomization tests and touches upon how generalization error may or may not be related to regularization and loss. It also throws light on some interesting points like the finite-sample expressivity of neural nets and how solving the gram matrix in SGD gives us the minimum l2 norm but is not predictive of minimal generalization error. Let’s look at these findings in a bit more detail.</p>
<h3 id="heading-findings">Findings</h3>
<p>The most intriguing and unique strategy adopted by the researchers is <strong>randomization testing</strong>, wherein they train neural networks with true labels, partially corrupted labels (some labels are random labels from uniform distribution), completely random labels from uniform distribution and shuffled pixels, firstly, all having the same shuffling pattern and then with random pixels shuffling, and even from Gaussian noise samplings from original dataset. It is obvious that any correlation, meaningful to humans, between the image and the label is gradually broken. Despite this, the authors find that even from complete noise the neural network correctly ‘shatters’ the training data, ie. fit to training data with 100% accuracy, with same network structure and hyperparameters!</p>
<p>It is thus proved <strong>deep neural networks can easily fit random labels</strong>. The effective capacity of neural nets is sufficient for memorizing the entire data set, given enough parameters and optimization on random labels remains easy ie. it increases by a reasonably small constant factor, refuting some of the findings from the paper titled “Deep Nets don’t learn via memorization” by Krueger et al from the same conference. It’s not a complete paradox though as the researchers from the two papers have found some similar results but drawn different conclusions, observing them in different lights.</p>
<p>For eg, both research groups observed that with increase in noise, networks take a bit longer to shatter training data. On one hand, Krueger et al. concluded that Neural nets did not memorize the data, and captured patterns only. On the contrary, Zhang et al concluded that since the time taken was more by just a small factor, they might really be memorizing the training data, additionally they note that gaussian noise converged faster than random labels, corroborating their hypothesis. Finally, they note that <strong>generalization error is certainly dependent on the network choice</strong>, as observed, Inception gave the least generalization error against AlexNet and a 512x MLP.</p>
<p><em>The paper discusses the effectiveness of some regularization techniques:</em>.</p>
<ul>
<li><p>Augmenting data shows better generalization performance than weight decay, biggest gains are achieved by changing the model architecture.</p>
</li>
<li><p>Early stopping could improve generalization, but that is not always true. Batch normalization improves generalization.</p>
</li>
</ul>
<p>The authors write, <code>"Explicit regularization may improve generalization but is neither necessary nor by itself sufficient.”</code></p>
<p>Universal Function Approximation Theorem states that a single hidden layer, containing a finite number of neurons, can approximate any continuous function on compact subsets of Euclidean space, but does not comment on the algorithmic learnability of those parameters, ie. how feasibly or quickly this neural net will actually learn these weights. This is extended to their theorem when they say, <code>“Given a particular set of data or fixed population level n in d dimensions, there exists a two-layer neural network with ReLU activations and 2n+d weights that can represent any function.”</code></p>
<h3 id="heading-conclusion">Conclusion</h3>
<p>The main findings of the paper can be concluded as, <code>“Both explicit and implicit regularizers could help to improve the generalization performance. However, it is unlikely that the regularizers are the fundamental reason for generalization.”</code></p>
<p>This paper has a lot of interesting results, though it couldn’t offer effective solutions to some problems. I find it to be as groundbreakingly exciting as say the AlexNet paper in 2012, or the Dropout paper in 2014 <em>(references below)</em>, which enlightened us with profound insights into neural networks.</p>
<h4 id="heading-references">References</h4>
<ol>
<li><p><a target="_blank" href="https://arxiv.org/abs/1611.03530">Zhang, Chiyuan, Samy Bengio, Moritz Hardt, Benjamin Recht, and Oriol Vinyals. "Understanding deep learning requires rethinking generalization." arXiv preprint arXiv:1611.03530 (2016).</a></p>
</li>
<li><p><a target="_blank" href="https://www.youtube.com/watch?v=O42vde4tbG0">Rodney LaLonde's paper reading at UCF CRCV.</a></p>
</li>
<li><p><a target="_blank" href="https://papers.nips.cc/paper/2012/hash/c399862d3b9d6b76c8436e924a68c45b-Abstract.html">Krizhevsky, Alex, Ilya Sutskever, and Geoffrey E. Hinton. "Imagenet classification with deep convolutional neural networks." Advances in Neural Information Processing Systems 25 (2012): 1097-1105.</a></p>
</li>
<li><p><a target="_blank" href="https://jmlr.org/papers/v15/srivastava14a.html">Srivastava, Nitish, Geoffrey Hinton, Alex Krizhevsky, Ilya Sutskever, and Ruslan Salakhutdinov. "Dropout: a simple way to prevent neural networks from overfitting." The journal of machine learning research 15, no. 1 (2014): 1929-1958.</a></p>
</li>
</ol>
]]></content:encoded></item></channel></rss>