<?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[Ones and Zeros, by Niladri Roy]]></title><description><![CDATA[In this publication, we would cover a wide range of CS topics — Web Development, Operating Systems, Machine Learning, Processor Architecture, and much more]]></description><link>https://ones-zeros.royniladri.dev</link><generator>RSS for Node</generator><lastBuildDate>Sun, 06 Sep 2026 12:03:36 GMT</lastBuildDate><atom:link href="https://ones-zeros.royniladri.dev/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Self Hosting 101]]></title><description><![CDATA[Introduction
In an era where AI is reshaping everything from search engines to social media, and data privacy feels more like a myth than a guarantee, I decided to take back control—starting at home. My homelab serves as both a tech playground and a ...]]></description><link>https://ones-zeros.royniladri.dev/self-hosting-101</link><guid isPermaLink="true">https://ones-zeros.royniladri.dev/self-hosting-101</guid><category><![CDATA[Homelab]]></category><category><![CDATA[self-hosted]]></category><category><![CDATA[vpn]]></category><dc:creator><![CDATA[Niladri Roy]]></dc:creator><pubDate>Sat, 13 Sep 2025 07:26:15 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/9wnAhRYdDzc/upload/5fcbdcb848740263259a41af3cd64d2b.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-introduction">Introduction</h2>
<p>In an era where AI is reshaping everything from search engines to social media, and data privacy feels more like a myth than a guarantee, I decided to take back control—starting at home. My homelab serves as both a tech playground and a personal fortress of autonomy. It gives me the freedom to run the services I rely on, store my data securely, and explore new technologies without handing over my digital life to third parties.</p>
<p>This setup isn’t about breaking things or chasing enterprise-grade complexity. It’s about building a space where I can experiment safely, learn continuously, and most importantly—own my data. And here’s the best part: you don’t need deep pockets or racks of expensive gear to get started. With a bit of curiosity and repurposed hardware, anyone can build a homelab that empowers them in this increasingly centralized digital world.</p>
<p>In this post, I’ll walk you through my setup, the tools I use, and how you can start your own journey toward digital independence—without spending a fortune.</p>
<p>[PS: Introduction drafted by AI!]</p>
<h2 id="heading-nothing-fancy-here">Nothing fancy here!</h2>
<p>Before we dive in, i want to emphasize on how basic my home-lab is!</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1757747637796/3258c420-1b41-442e-b8b2-18a9eded1062.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-hardware-components">Hardware Components</h2>
<p>I am starting by using existing hardware.</p>
<h3 id="heading-servers">Servers</h3>
<p>For always on machine, I am using a <code>Raspberry Pi</code>. Things that qualify for this are:</p>
<ul>
<li><p>Pi-hole (DNS &amp; Network wide Add block)</p>
</li>
<li><p>Nginx Proxy Manager (Subdomain Routing &amp; SSL Certs)</p>
</li>
<li><p>Home Assistant (Smart home)</p>
</li>
<li><p>n8n (Automation like Zipier)</p>
</li>
</ul>
<p>For a little more demanding app, I am using an <code>old laptop</code>. Its not in the best shape, but with Core i7 and 16GB RAM, it is quite capable of handling reasonable workloads, with some ML use cases (like face recognition). I have upgraded it to a 1TB SSD instead of its old HDD. This machine is on during the day and suspended during night. It is hosting:</p>
<ul>
<li><p>Immich (Photo organization and sharing app like Google Photos)</p>
</li>
<li><p>NextCloud (Cloud drive storage like One Drive, G Drive)</p>
</li>
</ul>
<p>For more demanding workloads like video transcoding or LLM related tasks, I am using my <code>Main PC</code> (Ryzen 9, 32GB DDR4 RAM, RTX 3070). It has a primary 1TB SSD, with additional 2 4TB HDD. This is turned on only when needed as its highly power hungry, and I cannot afford to reduce its life by having it always on. This hosts (or will host):</p>
<ul>
<li><p>Plex/Jellyfin (Media streaming)</p>
</li>
<li><p>Open Web UI (UI for local LLM chat)</p>
</li>
<li><p>Ollama (Run Open source LLM model locally)</p>
</li>
</ul>
<h3 id="heading-networking-gear">Networking Gear</h3>
<p>For router, I am continuing to use the <strong>ISP provided router</strong> with limited configuration. This is one section I am looking to upgrade in the next phase.</p>
<p>Only the Pi is currently connected via LAN; everything else is on wireless.</p>
<h2 id="heading-connection-diagram">Connection Diagram</h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1757747807836/78b80124-4cef-46c5-bf74-0a02f17b838d.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-network">Network</h2>
<p>Now let us understand why a component is there.</p>
<h3 id="heading-pi-on-lan-with-static-ip">Pi on LAN with static IP</h3>
<p>My router does not have the option to assign static IP to devices. By being on the LAN, and trying to reserve a higher IP value, my PI stays on that same IP. The router has a small power backup, but sadly the pi will die when power goes off. Since it auto starts and all services running on it also auto start, it is not a problem for now. Having a static IP enables me to add that IP in devices like TV where I cannot install a VPN client.</p>
<h3 id="heading-tailscale-vpn-provider-based-on-wireguard">Tailscale (VPN provider based on Wireguard)</h3>
<p>When everything is on my local network, I can get away with not using a VPN, and having every service available locally. But If I want my family to have access to some service, they will not be able to connect when outside my network. Moreover, they will not be able to remember machine names or IPs (which will keep changing randomly), and not to mention that the annoying security warning for missing TLS. Having a mesh VPN like Tailscale, allows me to assign each server machine a static IP that can be accessed only when folks are on the same Tailscale network. This solves 2 problems at once, accessibility with static IP as well as security. Other people I want to share with will need a Tailscale network of their own, and I can share my Pi with them. </p>
<p>I have a custom DNS running on Pi-hole (more on this later), and my Tailnet is set to use the Tailscale IP of my Pi.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1757747840878/42fbe85b-e719-4754-b179-d460a9ff366d.jpeg" alt class="image--center mx-auto" /></p>
<h3 id="heading-cloudflare-dns">Cloudflare DNS</h3>
<p>We need a public facing DNS for issuing TLS certificates for my domains. The Cloudflare DNS is a catch all subdomain entry pointing to my Tailnet IP of Pi.</p>
<p><em>Example domain entry:</em></p>
<p><code>*.</code><a target="_blank" href="http://homelab.example.com"><code>homelab.example.com</code></a> → 100.80.50.60</p>
<h3 id="heading-pi-hole-ad-blocker-dns">Pi-Hole (Ad-blocker + DNS)</h3>
<p>This is the first service that I set up on my homelab. It works by blocking DNS requests to well known ad services. As long as other devices are using this as DNS, it will block out most of the adds. For phones and laptops connected to my Tailnet, it will automatically use this as we had set it up in the <strong>Nameservers.</strong></p>
<p>Another task it performs is a local DNS server. We have a reverse proxy exposing my services at a subdomains under my own domain. It can be set up like shown below. The DNS Domain points back to the server running the reverse proxy (in this case its the same machine). The CNAME records each list out the subdomains and link it to the domain we set on the left.</p>
<p><em>Example entries:</em></p>
<p><strong>DNS</strong></p>
<p><a target="_blank" href="http://homelab.example.com"><code>homelab.example.com</code></a> → 192.168.0.50</p>
<p><strong>CNAME</strong></p>
<ul>
<li><p><a target="_blank" href="http://pihole.homelab.example.com"><code>pihole.homelab.example.com</code></a> → <a target="_blank" href="http://homelab.example.com"><code>homelab.example.com</code></a></p>
</li>
<li><p><a target="_blank" href="http://home-assistant.homelab.example.com"><code>home-assistant.homelab.example.com</code></a> → <a target="_blank" href="http://homelab.example.com"><code>homelab.example.com</code></a></p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1757747858452/f042e641-b9d9-4368-b617-9106ca510d09.png" alt class="image--center mx-auto" /></p>
<h3 id="heading-nginx-proxy-manager-reverse-proxy">Nginx-Proxy-Manager (Reverse Proxy)</h3>
<p>This is a core component that exposes subdomains for each service. It works with <code>LetsEncrypt</code> to get SSL certificates from Cloudflare. Interestingly it seems it auto-renews certificates, something i was not aware of until i got messages from Cloudflare. These subdomains are then needed to be added to Pi-hole CNAME records. Even if the services are not using HTTPS, Nginx takes care of ensuring traffic is encrypted while in transit. Also note, it can expose services running on other machines as well, either though static IP (if available), or Tailscale IP (I am using this as i don't have static IP).</p>
<p>So Pi-hole + NPM together serve as a single entry point to the whole home network, and the only device that needs to be shared with other users to allow access.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>This is a very good starting point for a personal homelab using existing hardware (almost no cost). I am running all services using simple docker compose. I am not concerned with redundancy or high availability as its just me and my wife using it (will expand out to parents), and we can live with downtime. Not all corporate fancy stuff needs to be incorporated in a simple setup.</p>
<p>The part that is currently giving me bad sleep is lack of Backup strategy. If any of the storage devices fail, I'll be at a loss. Have some ideas, but have not got around to trying it out. I have a lot of space on my desktop, but having backup software like <code>BorgBackup</code> over network is turning out to be a pain. Once I fix that, will update that step.</p>
<p>If you are experienced with homelabs, let me know what I can improve, or how you are handling backups across machines!</p>
]]></content:encoded></item><item><title><![CDATA[Introduction to Machine Learning in Production | Course Summary]]></title><description><![CDATA[ML lifecycle - https://www.coursera.org/learn/introduction-to-machine-learning-in-production
This course introduces us to the ML lifecycle and some real life examples (yes, ML is not just used to predict house prices on a Jupyter notebook!). It walks...]]></description><link>https://ones-zeros.royniladri.dev/introduction-to-machine-learning-in-production-course-summary</link><guid isPermaLink="true">https://ones-zeros.royniladri.dev/introduction-to-machine-learning-in-production-course-summary</guid><category><![CDATA[mlops]]></category><category><![CDATA[Machine Learning]]></category><category><![CDATA[course-summary]]></category><dc:creator><![CDATA[Niladri Roy]]></dc:creator><pubDate>Sun, 18 Jun 2023 18:16:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1687111892855/e6a4d6b7-f949-4add-8e94-11192e6325d7.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1687111862666/26a3b5d1-36c5-4a8f-aadd-c8cf9a25e267.png" alt class="image--center mx-auto" /></p>
<p><em>ML lifecycle -</em> <a target="_blank" href="https://www.coursera.org/learn/introduction-to-machine-learning-in-production"><em>https://www.coursera.org/learn/introduction-to-machine-learning-in-production</em></a></p>
<p>This course introduces us to the ML lifecycle and some real life examples (yes, ML is not just used to predict house prices on a Jupyter notebook!). It walks through the different phases.</p>
<ul>
<li><p><em>Scoping</em> - What projects to work on, what values it brings, what metrics to use when measuring performance and some ballpark resource estimates.</p>
</li>
<li><p><em>Data</em> - How much data is needed and where it comes from. Ensure data is labelled consistently and establish baselines.</p>
</li>
<li><p><em>Modelling</em> - Instead of a model centric view (optimizing code &amp; hyper-parameters), optimize data &amp; hyper-parameter.</p>
</li>
<li><p><em>Deployment</em> - Deploy and monitor for performance, data drift, and concept drift. Go back &amp; tweak model &amp; data to stay relevant.</p>
</li>
</ul>
<p>Let's take a deeper look at the steps, in reverse order.</p>
<h3 id="heading-deployment">Deployment</h3>
<p>There are a few deployment patterns:</p>
<ul>
<li><p>Canary deployment - roll out to a very select few, monitor &amp; ramp up gradually. Great for new projects with not well defined baselines.</p>
</li>
<li><p>Shadow mode - Where human are in charge of decision, but a ML system too predicts &amp; its performance it tally-ed with human operators &amp; tweaked till required confidence is achieved.</p>
</li>
<li><p>Blue/Green deployment - That gradually routes traffic to the new system (green), and in case there is any issue, it is rolled back to the previous version (blue). Ideal for upgrade situations.</p>
</li>
</ul>
<p>Once the system is deployed, it needs to be closely monitored.</p>
<ul>
<li><p>Have dashboards and set relevant alerts. Brainstorm metrics to track and alert thresholds, but being an iterative process, can be altered with time.</p>
</li>
<li><p>Often ML systems have pipeline, and changes trickle down. Need to closely tap on to important nodes in the process.</p>
</li>
</ul>
<h3 id="heading-modeling">Modeling</h3>
<p>Some key challenges in modelling are as follows:</p>
<ul>
<li><p>It needs to do well on training set, test set and also fulfill business goal.</p>
</li>
<li><p>Often some segment of data is disporportionately important, example - searches for specific websites vs searches for recipes.</p>
</li>
<li><p>The model should ideally be free from biases &amp; social prejudices.</p>
</li>
<li><p>Perform appropriately for rare classes, like medical screening of a rare disease.</p>
</li>
</ul>
<p>To judge the performance of a model, it is crucial to have a baseline against which it could be held up to and define what is irreducible error (Bayes error). Some ways to estimate that are:</p>
<ul>
<li><p>Human level performance (HLP) - great for unstructured data (image, audio, ...)</p>
</li>
<li><p>Literature search (published papers) or open source implementations. Often decent algorithm with good data will outperform smarter algorithm with worse data (remember GIGO?)</p>
</li>
<li><p>Quick &amp; dirty implementation</p>
</li>
<li><p>Performance of older system (if any)</p>
</li>
</ul>
<p>Once a model is shortlisted, it's performance is evaluated and error analysis is done to find the next step. A good way to start is manually going over ~100 or so examples and tag why they were misclassified. based on the difference between the ML model and HLP on tags, and their expected distribution it is decided how to boost those tags.</p>
<p>For skewed datasets, precision-recall and F1 score are better metric than accuracy.</p>
<p>In case of less data, data augmentation can be used (like adding different noises in image and audio, tweaking brightness/contrast of image or video). But augmentation should be realistic - adding stadium noise to a hospital system might not help.</p>
<p>For big models and clear input to output mapping, more data seldom hurts, but for smaller networks or unclear mappings, augmented data might overfit the system.</p>
<p>As an alternative to adding data, adding features too can help, but generally useful in structured data scenarios.</p>
<p>With a highly iterative step of modelling &amp; evaluation it is essential to keep track of what all was tried and how well it turned out. It can be done using text files, spreadsheets or more complicated experiment tracking sytems (Weights &amp; biases, ML Flow, SageMaker, ...). It should track:</p>
<ul>
<li><p>Algorithm/code version</p>
</li>
<li><p>Dataset used (processing done if any)</p>
</li>
<li><p>Hyper-parameters</p>
</li>
<li><p>Results</p>
</li>
</ul>
<h3 id="heading-data">Data</h3>
<p>In this phase, it is defined what input x is and what output y is desired.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1687111949343/02c57115-f849-4295-81fe-a5e577ab373e.png" alt class="image--center mx-auto" /></p>
<p><em>Types of data problems -</em> <a target="_blank" href="https://www.coursera.org/learn/introduction-to-machine-learning-in-production"><em>https://www.coursera.org/learn/introduction-to-machine-learning-in-production</em></a></p>
<ul>
<li><p>For unstructured data, HLP can generally be evaluated, and augmentation likely to help.</p>
</li>
<li><p>For structured data, HLP &amp; augmentation is difficult.</p>
</li>
<li><p>For small data, clean labels are crucial.</p>
</li>
<li><p>For larger data, data processing pipeline becomes crucial.</p>
</li>
</ul>
<p>When label consistency is required it is often beneficial to discuss among labelers and SME and define and document the output category. It might be needed to have some data have ambiguity and have a new label to denote that.</p>
<p>We should not spend too long to acquire data. Getting into the iterative process as fast as possible is helpful as it illuminates where to focus effort. In case of a well documented domain (like spam filter), when folks know what data works best, it is recommended to spend more time to get good data at the get go. As for data sources, chosing one (or more) depends on monetary cost, timeline and volume of data needed or available.</p>
<p>During the initial (POC) phase, data cleaning and feature extraction can be local scripts of notebooks, but then a proper pipeline needs to be set.</p>
<p>It might be beneficial to keep track of metadata (camera settings, geotag, device type, ...). It is useful for error analysis data provenance.</p>
<p>It is crucial to have same distribution in train, dev and test sets. Use "startified" to get splits.</p>
<h3 id="heading-scoping">Scoping</h3>
<p>What problems to work on, what is the metric of success, what resources are needed?</p>
<ul>
<li><p>Feasibility - Is is feasible technically? What is HLP? Are there features that are indicative of outcome?</p>
</li>
<li><p>Value - Engineers &amp; business metric are generally different, and needs establishing a common ground. Also needs ethical considerations - societal benefit, free from bias, ...</p>
</li>
<li><p>Milestones &amp; Resourcing - Ballpark estimations (ML metrics, Software metric, business metric, resource, timeline).</p>
</li>
</ul>
<hr />
<p>With this knowledge under my belt, I am happy to share my 1st certificate in this specialization.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1687111995295/b55a0780-0dc0-4449-901d-dfaff88f77ff.png" alt class="image--center mx-auto" /></p>
<p><em>Course Completion Certificate -</em> <a target="_blank" href="https://coursera.org/share/85a7ccaba778f72a53147f1d0bcb84de"><em>https://coursera.org/share/85a7ccaba778f72a53147f1d0bcb84de</em></a></p>
]]></content:encoded></item><item><title><![CDATA[(Free)Mac Utilities for Day-to-Day Usage]]></title><description><![CDATA[The gigantic track pad is great, and a lot of familiar multi-finger gestures work seamlessly or can be configured to one's preference. As buttery smooth the Mac Book Pro keyboard is, I fail to understand why they have messed around with the keyboard ...]]></description><link>https://ones-zeros.royniladri.dev/freemac-utilities-for-day-to-day-usage</link><guid isPermaLink="true">https://ones-zeros.royniladri.dev/freemac-utilities-for-day-to-day-usage</guid><category><![CDATA[macOS]]></category><category><![CDATA[Apple]]></category><category><![CDATA[utility]]></category><category><![CDATA[free]]></category><dc:creator><![CDATA[Niladri Roy]]></dc:creator><pubDate>Sun, 19 Mar 2023 07:59:12 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/m_HRfLhgABo/upload/b354075a6b67091516cdf877d748730a.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>The gigantic track pad is great, and a lot of familiar multi-finger gestures work seamlessly or can be configured to one's preference. As buttery smooth the Mac Book Pro keyboard is, I fail to understand why they have messed around with the keyboard layout. While that is something you cannot change, you can add some utilities to get back some of the great features that Windows provide out of the box.</p>
<p><img src="https://www.daskeyboard.com/blog/wp-content/uploads/windows-vs-mac-keyboard.jpg" alt="Kyboard layout difference" class="image--center mx-auto" /></p>
<h3 id="heading-1-maccy-clipboard-managerhttpsmaccyapp">1. <a target="_blank" href="https://maccy.app/">Maccy Clipboard Manager</a></h3>
<p>If you're used to the Windows clipboard, you'll be happy to know that Mac has a clipboard too. But the Mac clipboard only remembers the last item you copied, which can be frustrating. That's where Macy Clipboard Manager comes in. This free software keeps track of everything you copy and paste, making it easy to access your clipboard history.</p>
<p><img src="https://maccy.app/img/maccy/Instructions.png" alt class="image--center mx-auto" /></p>
<p>If you check it on the Apple App Store, it is a paid app, but being an open source software (<a target="_blank" href="https://github.com/p0deje/Maccy">https://github.com/p0deje/Maccy</a>), you can get it for free using <a target="_blank" href="https://brew.sh/">Homebrew</a>.</p>
<pre><code class="lang-bash">brew install --cask maccy
</code></pre>
<p>While it works pretty well out of the box, but to get the same feel as windows you'll need to make a couple of adjustments in the app's preferences.</p>
<ul>
<li><p>Change the hotkey to ⇧⌘V (General Tab)</p>
</li>
<li><p>Ensure "Paste automatically" is checked (General Tab)</p>
</li>
<li><p>Ensure "Popup at" is set to "cursor" (Appearance Tab)</p>
</li>
</ul>
<p>Now enjoy the peace of copying stuff until you are ready to paste!</p>
<p>⚠️ <strong>Please ensure to disable it when copying passwords, or clear it manually after using it for passwords.</strong></p>
<h3 id="heading-2-rectangle-window-tilinghttpsrectangleappcom">2. <a target="_blank" href="https://rectangleapp.com/">Rectangle Window Tiling</a></h3>
<p>If you're used to Windows' snapping feature, you'll love Rectangle window tiling. This free software allows you to easily resize and position windows on your Mac by dragging them to the edge of the screen. You can also use keyboard shortcuts to resize and position windows. There are a lot of good defaults involving 2 ways splits, 3 way splits, 4 way splits and much more.</p>
<p><img src="https://rectangleapp.com/assets/images/shortcutScreenshot.jpg" alt class="image--center mx-auto" /></p>
<p>This app too is open source (<a target="_blank" href="https://github.com/rxhanson/Rectangle">https://github.com/rxhanson/Rectangle</a>), and can be installed using <a target="_blank" href="https://brew.sh/">Homebrew</a>.</p>
<pre><code class="lang-bash">brew install --cask rectangle
</code></pre>
<p>Another great feature I love is the Todo Mode. While it feels a little off in a smaller screen, but great for a wide screen monitor. It can pin a app to the left or right of the screen with a set width, the rest of the screen can then be used for single or multiple apps, and the resizes honors the Todo space.</p>
<h3 id="heading-3-hidden-barhttpsgithubcomdwarvesfhidden">3. <a target="_blank" href="https://github.com/dwarvesf/hidden">Hidden Bar</a></h3>
<p>As we keep adding apps and widgets, the bar grows until it hides behind the notch (yet to find a free utility to fix this). While we can reorganize it, it still creates visual clutter. This app allows to send some of the icons off to an expansion space that open on clicking the chevron. You might need the menu bar icons for Maccy and Rectangle for a few days to get used to the keyboard shortcuts, and then they can be hidden! Similarly other stuff that are not required frequently can be hidden.</p>
<p><img src="https://github.com/dwarvesf/hidden/raw/develop/img/tutorial.gif" alt class="image--center mx-auto" /></p>
<p>This app is available for free at the App Store, and also can be installed using <a target="_blank" href="https://brew.sh/">Homebrew</a>.</p>
<pre><code class="lang-bash">brew install --cask hiddenbar
</code></pre>
<h3 id="heading-4-one-thinghttpsappsapplecomusappone-thingid1604176982">4. <a target="_blank" href="https://apps.apple.com/us/app/one-thing/id1604176982">One Thing</a></h3>
<p>This one is for the minimalist in you. You can pin one important task to the taskbar that will help you stay focused during the day. This is not liked to any other todo or productivity app, and needs to be set and reset manually.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1679208290207/796bc0e8-c442-424a-82e2-772f0d4ebaac.png" alt class="image--center mx-auto" /></p>
<p>This app too is free on the App Store (<a target="_blank" href="https://apps.apple.com/us/app/one-thing/id1604176982">https://apps.apple.com/us/app/one-thing/id1604176982</a>), and sadly is not available on <a target="_blank" href="https://brew.sh/">Homebrew</a>.</p>
<h3 id="heading-5-hand-mirrorhttpshandmirrorapp">5. <a target="_blank" href="https://handmirror.app/">Hand Mirror</a></h3>
<p>Need to check if the room background is tidy enough or there isn't spinach stuck between your teeth before a zoom call, this is a nifty little tool. It shows your camera view in a short popout window.</p>
<p><img src="https://handmirror.app/images/screenshot-1.jpg" alt class="image--center mx-auto" /></p>
<p>Again, this is available for free on the App Store (<a target="_blank" href="https://apps.apple.com/us/app/hand-mirror/id1502839586">https://apps.apple.com/us/app/hand-mirror/id1502839586</a>), and sadly is not available on <a target="_blank" href="https://brew.sh/">Homebrew</a>.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Switching from Windows to Mac can be a daunting task, but with the help of handy software the transition can be a lot smoother. These free Mac software ensure you are at your top productivity. Give them a try and see how they can improve your Mac experience!</p>
]]></content:encoded></item><item><title><![CDATA[Turbocharge your Jekyll Website]]></title><description><![CDATA[Jekyll is a static site generator based on Ruby. It is a popular option for creating simple blogs with more focus on the content.

From https://jekyllrb.com/
There are a lot of simple templates available to jumpstart, and they are compatible with Git...]]></description><link>https://ones-zeros.royniladri.dev/turbocharge-your-jekyll-website</link><guid isPermaLink="true">https://ones-zeros.royniladri.dev/turbocharge-your-jekyll-website</guid><category><![CDATA[Web Development]]></category><category><![CDATA[jekyll]]></category><category><![CDATA[PWA]]></category><category><![CDATA[SEO]]></category><dc:creator><![CDATA[Niladri Roy]]></dc:creator><pubDate>Fri, 09 Jul 2021 18:45:23 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1625855002516/Mz_5BJHIA.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Jekyll is a static site generator based on Ruby. It is a popular option for creating simple blogs with more focus on the content.
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1625845427759/HZhjEL8TK.png" alt="Jekyll" />
<em>From https://jekyllrb.com/</em></p>
<p>There are a lot of simple templates available to jumpstart, and they are compatible with GitHub Pages. You just start writing <code>Markdown</code> files and you can have a site up and running in no time! But oftentimes, it will not be optimized. Here is a list of things that are often not part of a free template:</p>
<ol>
<li>Google Analytics</li>
<li>Sitemaps</li>
<li>RSS/ATOM feed</li>
<li>E-mail Subscription</li>
<li>Comments</li>
<li>Progressive Web App (PWA)</li>
</ol>
<p>All these results in a suboptimal experience for the users. With some simple enhancements, we can boost up the <a target="_blank" href="https://developers.google.com/web/tools/lighthouse/">Lighthouse</a> score of our site a lot.
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1625846125743/hoERq61rW.png" alt="image.png" />
<em>Site Score on Lighthouse</em></p>
<blockquote>
<p>Excellence/Perfection is not a destination; it is a continuous journey that never ends. - Brian Tracy</p>
</blockquote>
<p>TLDR: <a target="_blank" href="https://github.com/royNiladri/omscs-journey">Show me the code</a> <a target="_blank" href="https://omscs.royniladri.dev/">Show me the site</a></p>
<p>⚠ <strong>Prerequisite Alert</strong>: This article will assume you have a basic understanding of how a Jekyll site works. Refer to the <a target="_blank" href="https://jekyllrb.com/docs/structure/">Folder Structure</a> for a quick overview of the project resources.</p>
<h2 id="adding-google-analytics">Adding Google Analytics 📈</h2>
<p>Head over to <a target="_blank" href="http://analytics.google.com/">Google Analytics</a> and click <code>Start Measuring</code>. You can follow the steps to enlist your webpage. If you want a step-by-step guide for the same, check the <a target="_blank" href="https://support.google.com/analytics/answer/9304153#zippy=%2Cweb">official doc</a>. Once that is done, head over to the Jekyll project and add the GA property id in <code>_config.yml</code> as:</p>
<pre><code class="lang-yml"><span class="hljs-attr">google_analytics:</span> <span class="hljs-string">UA-XXXXX</span>
</code></pre>
<p>You would probably want analytics to run on all thee pages, and hence need to add the script at the base layout. For most projects it should be at <code>_layouts/default.html</code>. Add the following in the head section:</p>
<pre><code class="lang-html">{% if site.google_analytics %}
<span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">async</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"https://www.googletagmanager.com/gtag/js?id={{ site.google_analytics }}"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">script</span>&gt;</span><span class="javascript">
    <span class="hljs-built_in">window</span>.dataLayer = <span class="hljs-built_in">window</span>.dataLayer || [];
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">gtag</span>(<span class="hljs-params"></span>) </span>{ dataLayer.push(<span class="hljs-built_in">arguments</span>); }
    gtag(<span class="hljs-string">'js'</span>, <span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>());
    gtag(<span class="hljs-string">'config'</span>, <span class="hljs-string">'{{ site.google_analytics }}'</span>);
</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
{% endif %}
</code></pre>
<p>Now, this you can use in all your future project templates. This will not be rendered when you do not specify the <code>google_analytics</code> key in  <code>_config.yml</code></p>
<h2 id="sitemap">Sitemap 🗺</h2>
<p>Sitemaps are documents (can be .txt, or .XML) that list the locations in the webpage. They help search engine crawlers to crawl all the pages of your site for better search results. This can be easily added using a Jekyll plugin:</p>
<pre><code class="lang-yml"><span class="hljs-attr">plugins:</span>
    <span class="hljs-string">...</span>
    <span class="hljs-bullet">-</span> <span class="hljs-string">Jekyll-sitemap</span>
    <span class="hljs-string">...</span>
</code></pre>
<p>This should generate a page at the root level <code>/sitemap.xml</code>. You can now add this to <a target="_blank" href="https://search.google.com/">Google Search Console</a> and enjoy indexing benefits!</p>
<h2 id="rssatom-feed">RSS/ATOM Feed  🔔</h2>
<p>There is again an easy way out with the <a target="_blank" href="https://github.com/jekyll/jekyll-feed">jekyll-feed</a> plugin. Add the plugin, do a bundle install and the feed should start appearing at <code>/feed.xml</code>.</p>
<pre><code class="lang-yml"><span class="hljs-attr">plugins:</span>
    <span class="hljs-string">...</span>
    <span class="hljs-bullet">-</span> <span class="hljs-string">Jekyll-feed</span>
    <span class="hljs-string">...</span>
</code></pre>
<p>Now your users can subscribe to the feed to get notified when you write a post!</p>
<h2 id="e-mail-subscription">E-mail Subscription 💌</h2>
<p>If you want to give your users a way to be contacted when you want to announce something, you can set up an email subscription. One popular option is to use <a target="_blank" href="https://mailchimp.com/">MailChimp</a>. There is a free tier that should be sufficient for most starting bloggers.
Once you set up an account there, Click on <code>Create</code> &gt; <code>Signup Forms</code> &gt; <code>Embedded form</code>
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1625848713424/XsZIM5Tyq.png" alt="image.png" />
Now you can copy the code given and paste it under _includes. You can modify the HTML and CSS to make it look and feel in tune with your existing theme. Assuming you created a partial called <code>mailchimp.html</code>, you can include it in different <code>layouts</code>.
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1625849109603/1-18syJYK.png" alt="image.png" />
After adding my customizations, it looks like this. Much better right?</p>
<h2 id="comments">Comments 💬</h2>
<p>There are some options in this space. Some have privacy concerns, while other need hosting. So a hacky way is to use GitHub issues as comments. Some wrappers make it easy. One such example is <a target="_blank" href="https://utteranc.es/">Utterances</a>.
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1625849811267/n1Ssti5kP.png" alt="Utterences" />
It is simple and easy to set up. Just add permissions to the repository and add a small script in the layouts that require comments. Ensure to add <code>async</code> to ensure it does not impact load time.</p>
<h2 id="progressive-web-app-pwa">Progressive Web App (PWA) 📱</h2>
<p>Enhancing a web app to a PWA has certain benefits. It will take more than a series to explore the nitty-gritty details of PWA (I'll keep adding articles). For a brief introduction, you can check my post on <a target="_blank" href="https://ones-zeros.royniladri.dev/js-service-workers-an-introduction">JS Service Workers</a>. In this section, we will enable the PWA feature with a basic <code>manifest.json</code> and install a service worker that caches the pages when you visit them so that you can still use the site when offline. For this, I have mostly followed the tutorial from <a target="_blank" href="https://alokprateek.in/articles/jekyll-pwa/">Meteoric Teachings</a> by <em>Alok Prateek</em>. After you are done with the changes, Lighthouse (Chrome inspector tab) nags about a few things. You can read the details about those by checking the reference links in the Lighthouse tab. Let us fix those!</p>
<h3 id="custom-splash-screen">Custom Splash Screen</h3>
<p>Add an icon asset to the manifest.json file that is at least 512x512.</p>
<h3 id="maskable-icon">Maskable icon</h3>
<p>Add a maskable icon in the manifest.json file which is at least 192x192.</p>
<pre><code class="lang-JSON">{
    <span class="hljs-attr">"src"</span>: <span class="hljs-string">"/assets/images/gt-logo-maskable.png"</span>,
    <span class="hljs-attr">"sizes"</span>: <span class="hljs-string">"240x240"</span>,
    <span class="hljs-attr">"type"</span>: <span class="hljs-string">"image/png"</span>,
    <span class="hljs-attr">"purpose"</span>: <span class="hljs-string">"maskable"</span>
}
</code></pre>
<p>You can turn an image to its maskable format using the <a target="_blank" href="https://maskable.app/editor">Maskable.app Editor</a></p>
<h3 id="apple-touch-icon">Apple touch icon</h3>
<p>Add a link tag in the <code>head</code> of the default layout.</p>
<pre><code><span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">"apple-touch-icon"</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"/assets/images/logo.png"</span>&gt;</span>
</code></pre><h2 id="bonus-seo-optimizations">Bonus SEO optimizations 🧪</h2>
<ul>
<li>Add description and title to all the pages/posts</li>
<li>Add thumbnails for social media share<pre><code><span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">property</span>=<span class="hljs-string">"og:image"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"{{site.url}}{{site.baseurl}}/assets/images/page-img.jpg"</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">property</span>=<span class="hljs-string">"twitter:image:src"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"{{site.url}}{{site.baseurl}}/assets/images/page-img.jpg"</span>&gt;</span>
</code></pre></li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Upgrading from HDD to SSD]]></title><description><![CDATA[I have a 3-year-old Dell Inspiron laptop with 16 GB DDR4 RAM, Intel Core i7 7500 processor (7th Gen), 4GB Radeon R7 M445 graphics processor, and 2TB Seagate HDD. I have a  Windows 10/Kubuntu dual boot. And for the past couple of months, it had been p...]]></description><link>https://ones-zeros.royniladri.dev/upgrading-from-hdd-to-ssd</link><guid isPermaLink="true">https://ones-zeros.royniladri.dev/upgrading-from-hdd-to-ssd</guid><category><![CDATA[hardware]]></category><category><![CDATA[2Articles1Week]]></category><category><![CDATA[Tutorial]]></category><dc:creator><![CDATA[Niladri Roy]]></dc:creator><pubDate>Sun, 25 Apr 2021 08:15:51 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1619335515092/Ah_tBT23A.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>I have a 3-year-old Dell Inspiron laptop with 16 GB DDR4 RAM, Intel Core i7 7500 processor (7th Gen), 4GB Radeon R7 M445 graphics processor, and 2TB Seagate HDD. I have a  Windows 10/Kubuntu dual boot. And for the past couple of months, it had been painfully slow to start and often froze when running a bunch of chrome tabs, or a large project on Visual Studio Code. While a simple solution was to go ahead and get a new laptop with a little higher configuration, it was an expensive solution. My system is definitely not archaic and I hoped there should be some simple upgrade I can do.</p>
<h2 id="figuring-out-the-problem">Figuring out the problem</h2>
<p>I started checking my system whenever it froze. I always had the Task Manager running. The RAM was barely a problem. CPU peaked from time to time when I had too much going on in my system. The only anomaly seemed to be the disk, which was almost always 100% utilized. While I do have Macafee running, I left my system open overnight for a manual scan. As expected, there were no threats found. My spouse has a new HP laptop with i7 9th Gen, 16 GB DDR4 RAM, and 1 TB SSD which loads up in under 10s! So maybe changing that would help.</p>
<h2 id="getting-the-supplies">Getting the supplies</h2>
<p>Time to hit Amazon. As I am not very knowledgeable about hardware, I had to depend on the ratings and chose Crucial MX500 1TB SSD (~$130). I checked out the 2TB version, but it was way too expensive, about double the 1TB one. I was using about 1TB of storage on my system, but I moved my camera backups and downloaded movies and series to my external HDD. Next, I needed a SATA to USB3 connector to clone my existing disk, and a precision toolkit to dismantle the laptop. It all took me about INR 10,000 (~$135).</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1619336912765/cF9J5eJFm.png" alt="image.png" /></p>
<h3 id="compatibility">Compatibility</h3>
<p>There are a few types of SSD available with different form factors and connectivity options. Before you head out to purchase, just check for compatibility. You'll most likely need a 2.5" SATA device, but you can ensure that here <a target="_blank" href="https://www.crucial.in/store/advisor">Crucial Advisor</a>. </p>
<h2 id="cloning-the-disk">Cloning the disk</h2>
<p>I used Acronis True Image to clone my disk. I used the SATA to USB3 connector to hook it up with my system. If you have both USB2 and USB3 ports on your system, ensure to plug it in the USB3 port. The good thing about this is it can clone a larger disk into a smaller SSD as long as the data is less than the SSD capacity. You can map partitions proportional to the existing one (600 GB partition on HDD will get mapped to 300 GB partition in my case), or manually adjust the space. It takes quite a while to do it and might restart the system.</p>
<h2 id="swapping-the-disks">Swapping the disks</h2>
<p>Now is the time to awaken the little hunter-gatherer part of you and get the tools! It is a good idea to go through a video that describes how to open your specific model, but I would list down the steps that I followed.</p>
<ol>
<li>Unscrew all the screws on the back of the laptop. Keep a track of which screw goes back where. Not all screws are made equal!</li>
<li>If you have an optical drive, pull it open, and unscrew any screws there.</li>
<li>The trickiest part is to pry open the front panel. If the back lid comes off after unscrewing, you will not need this step.</li>
<li>Ground yourself. This is a very important step.</li>
<li>It is recommended to disconnect the battery. (I did not do it because it would have required some more unscrewing.)</li>
<li>Unscrew the HDD and then remove any other brackets/cradle holding it. </li>
<li>Disconnect the SATA cable. It might be fixed tightly, so pull it by the plastic end. If you tug at the flat cable, it might tear off from the connecter (I almost did that! It was scary)</li>
<li>Now keep the HDD aside, and assemble the SSD with the aforementioned brackets/cradle.</li>
<li>Connect back the SATA cable, and screw it back to the board.</li>
<li>If you had disconnected the battery, connect it back now.</li>
<li>Clip back the front panel (if you had to do step 3)</li>
<li>Put back the optical drive.</li>
<li>Screw all the screws back.</li>
</ol>
<p>On powering on, you should see the familiar Windows welcome screen!</p>
<h2 id="problems-with-dual-boot-setup">Problems with Dual-boot setup</h2>
<p>I first logged into my Ubuntu instance, and everything was working smoothly. But when I tried to get into my Windows, I started getting errors. I did not have a USB installer to fix it. After panicking for a while, I decided to dive into it deeper and opened the console in the UEFI loader (type <code>c</code> when on the loader screen)! I did a <code>ls</code> and found the different partitions with their details. Took a picture of that on my phone. Next, I checked the Kubuntu loader script (type <code>e</code> on the loader screen when that option is highlighted`). It was searching for something by UUID, and I had seen the same when listing partitions. So I made a note of the UUID from Ubuntu and patched the Windows script with the same. Alas, that did not fix it!</p>
<p>Next, I took a look at both the scripts and found that Windows was looking for a FAT32 partition. On referencing the partition list, I found one! I went ahead and put that in, and viola, my Windows was loading. It was a short-lived victory, as when I tried to restart, the change was dropped, and I had to manually change that again. So at this point, I could get into the Windows, but something was still wrong with the loader.</p>
<p>I tried a couple of utilities from the internet, but nothing solved the problem. I tried windows recovery, and that did not work either. I tried to solve the same from Ubuntu, but still the same. Finally, I got a way to get all the list of UEFI loaders and deleted everything apart from the Ubuntu. Weirdly enough, that fixed it!</p>
<h2 id="results">Results</h2>
<p>Due to my dual boot setup, I had to disable "fast startup". My system now loads in ~25 s, and is responsive from the instance I am logged in. Earlier this used to take ~3 min and even after logging in I would have to wait for about 5 min for the system to be responsive. </p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1619335673424/Z8XiJKNDa.png" alt="image.png" /></p>
<h2 id="disclaimer">⚠ Disclaimer</h2>
<p>If you are not well versed with laptop hardware or not comfortable with the terminal, you should avoid doing this yourself without supervision. Always backup your important files before tinkering with the system.</p>
<div class="hn-embed-widget" id="buymecoffee"></div>]]></content:encoded></item><item><title><![CDATA[Why you need a Master's Degree (or not)]]></title><description><![CDATA["An investment in knowledge pays the best interest" - Benjamin Franklin

There is no doubt that higher education is often crucial when you are trying to get into a specific niche in your domain (like Data Science, Machine Learning), or trying to bump...]]></description><link>https://ones-zeros.royniladri.dev/why-you-need-a-masters-degree</link><guid isPermaLink="true">https://ones-zeros.royniladri.dev/why-you-need-a-masters-degree</guid><category><![CDATA[education]]></category><category><![CDATA[Developer]]></category><category><![CDATA[Computer Science]]></category><category><![CDATA[life]]></category><category><![CDATA[2Articles1Week]]></category><dc:creator><![CDATA[Niladri Roy]]></dc:creator><pubDate>Thu, 22 Apr 2021 20:11:38 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1619122230127/u_a4VFXmv.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<blockquote>
<p>"An investment in knowledge pays the best interest" - Benjamin Franklin</p>
</blockquote>
<p>There is no doubt that higher education is often crucial when you are trying to get into a specific niche in your domain (like Data Science, Machine Learning), or trying to bump up your pay grade, but it comes at a cost. Let me start with the warnings.</p>
<h2 id="1-the-finance">1. The finance</h2>
<p>On-campus degree programs are often very expensive, and not all can afford them without scholarships. If you already have a loan from your bachelor's or have a family that is dependant on your current income, financing the education with a loan is a really bad idea. Do not fall for placement guarantees, and assume you would be that guy who bagged the maximum package of the year. Life happens, pandemic happens, geopolitical conflicts happen. While dreaming of a bright future, count the numbers in a pessimistic way. While a lot of online courses are now popping up, at a fractional cost of on-campus courses, they are still expensive.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1619119378430/nrYJuQaRE.png" alt="image.png" />
<em>Student Loan debt, from <a target="_blank" href="https://news.prudential.com/prudential-student-loan-debt-postpones-dreams-threatens-financial-security-say-young-adults.htm">Prudential</a></em></p>
<h2 id="2-the-time">2. The time</h2>
<p>If you have taken some MOOCs along the way and under the impression that a degree program would be a similar experience, you are way off! To get the degree, you have to take a couple of subjects (the most popular is 30 credit hours that translates to 10 courses). Some of them might be a little easier, but most are not. In  <a target="_blank" href="https://omscs.royniladri.dev">OMSCS</a>, I easily spend 10-15 hours per week per semester and will increase as I take harder courses. Being a part-time student with a full-time job is quite stressful, so reevaluate if you are ready to sacrifice most of your social life for the next few years.</p>
<h2 id="3-the-purpose">3. The purpose</h2>
<p>Please do not do it just because people around you are doing it, or your parents want you to do it! For that matter, don't do it even if your company wants you to do it, but is not helping you with the finances (remember the first point). If you don't yearn for the knowledge, you will end up giving it minimum effort and getting through without learning much. If it is just the final piece of paper that you seek, real-life experience and projects will serve your resume much better.</p>
<h2 id="4-time-of-life">4. Time of life</h2>
<p>True everyone has their own timeline, and what works for me, might not work for you. But jumping into a master's right as you get your bachelor's degree might be a rush. A few years of industry experience is often a good eye-opener. The real world works quite a bit differently than the archaic books we study in our syllabus. The wisdom from your own experience will beautifully complement your knowledge from a Master's degree.</p>
<h2 id="5-industry-knowledge">5. Industry knowledge</h2>
<p>While an advanced degree will help you, they are still not at par with how the industry operates. If you seek pure technical knowledge to aid your existing job, a MOOC, or workshops are a better solution. And always RTFM! </p>
<p>Now, if you have the source to fund your education, the time to work on it, and a passion for knowledge, a Master's degree can do wonders.</p>
<h2 id="1-break-your-shell">1. Break your shell</h2>
<p>We often think we know more than we actually do, which is due to the fact that we do not yet know what else is out there. The Dunning-Kruger effect demonstrates this in a simple way. So go out there and overcome that valley of despair!</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1619111680411/GExVL0cIc.png" alt="image.png" />
<em>Dunning-Kruger curve, from <a target="_blank" href="https://slidemodel.com/dunning-kruger-effect/">slidemodel</a></em></p>
<h2 id="2-make-more-neural-connections">2. Make more neural connections</h2>
<p>As we often work in a domain, we start specializing in that domain, and our knowledge of other domains starts phasing out. Getting an advanced degree gives you another chance to go back to the basics and dive deeper. This will give you an opportunity to dig at a problem from another perspective. It often will help you squeeze the last bit of performance for some optimization.</p>
<h2 id="3-make-new-social-connection">3. Make new social connection</h2>
<p>This one is a lot easier and helps in the form of study groups when on-campus. For online courses as well there are discussion forums where you can meet amazing people. When doing group projects, or participating in a Piazza discussion, you learn so much. Also, the diversity (gender, geographical, academic) in an online degree program open our eyes to the biases we inherently possess.</p>
<h2 id="4-time-management">4. Time management</h2>
<p>Forget those hours of scrolling through reddit/instagram. Forget Netfix. Forget clocking in extra hours at work indefinitely. If you want to survive a rigorous degree program, you need to stick to a schedule. If you are a morning person, allocate a few hours in the morning to study; if you are a night owl, do it at night. Spend the weekends on projects/extra readings. And slowly you can ease back in an episode every few days, or a Friday night outing (pre Covid conditions). Check out my post on <a target="_blank" href="https://ones-zeros.royniladri.dev/productivity-tools-for-developers">Time Management </a> to learn more.</p>
<h2 id="5-get-new-opportunities">5. Get new opportunities</h2>
<p>If you are looking for a pay raise or want to try out say Artificial Intelligence, a masters degree will often get you to the door. Keep in mind that it only leads you to the door, and you'll need experience and core knowledge to get yourself through. Do not expect a company to offer you a 50% rise just because you hold a degree. In case of on-campus programs, you are also exposed to research opportunities.</p>
<h2 id="conclusion">Conclusion</h2>
<p>Now that we have a balanced pros and cons list, its your job to evaluate if the pros outweigh the cons in your specific case. Remeber that there will always be exceptions, but if everyone was an exception, there would have been none.</p>
<div class="hn-embed-widget" id="buymecoffee"></div>]]></content:encoded></item><item><title><![CDATA[Migrating Coveralls Report from Travis-CI to GitHub Actions]]></title><description><![CDATA[Disclaimer: This is a very specific problem. It is relevant only if you had a travis ci pipeline setup for your GitHub repository and using nyc and coveralls, and thinking of migrating to GitHub actions.

The Past
I followed this setup guide: Integra...]]></description><link>https://ones-zeros.royniladri.dev/migrating-coveralls-report-from-travis-ci-to-github-actions</link><guid isPermaLink="true">https://ones-zeros.royniladri.dev/migrating-coveralls-report-from-travis-ci-to-github-actions</guid><category><![CDATA[GitHub]]></category><category><![CDATA[Devops]]></category><category><![CDATA[Testing]]></category><dc:creator><![CDATA[Niladri Roy]]></dc:creator><pubDate>Tue, 09 Feb 2021 16:20:28 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1612887610699/QTuqr6MQ2.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<blockquote>
<p><strong>Disclaimer</strong>: This is a very specific problem. It is relevant only if you had a <a target="_blank" href="https://travis-ci.org/">travis ci</a> pipeline setup for your GitHub repository and using <code>nyc</code> and <code>coveralls</code>, and thinking of migrating to GitHub actions.</p>
</blockquote>
<h2 id="the-past">The Past</h2>
<p>I followed this setup guide: <a target="_blank" href="https://github.com/istanbuljs/nyc/blob/master/docs/setup-coveralls.md">Integrating with coveralls.io
</a></p>
<h2 id="the-problem">The Problem</h2>
<p>I thought of migrating the build pipeline to GitHub Actions, but was hindered by this error:</p>
<pre><code>&gt; js-big-<span class="hljs-type">decimal</span>@<span class="hljs-number">1.3</span><span class="hljs-number">.3</span> coverage /home/runner/<span class="hljs-keyword">work</span>/js-big-<span class="hljs-type">decimal</span>/js-big-<span class="hljs-type">decimal</span>
&gt; nyc report <span class="hljs-comment">--reporter=text-lcov | coveralls</span>


/home/runner/<span class="hljs-keyword">work</span>/js-big-<span class="hljs-type">decimal</span>/js-big-<span class="hljs-type">decimal</span>/node_modules/coveralls/bin/coveralls.js:<span class="hljs-number">19</span>
      throw err;
      ^
Bad response: <span class="hljs-number">422</span> {"message":"Couldn't find a repository matching this job.","error":<span class="hljs-keyword">true</span>}
(Use `node <span class="hljs-comment">--trace-uncaught ...` to show where the exception was thrown)</span>
npm ERR! code ELIFECYCLE
</code></pre><p>Now time to reveal the solution:</p>
<h2 id="the-solution">The Solution:</h2>
<ul>
<li>Edit the coverage script in package.json to use the default reporter of <code>lcov</code><pre><code>"coverage": nyc report <span class="hljs-comment">--reporter=lcov</span>
</code></pre></li>
<li><p>Modify the pipeline to use the official Coveralls stage</p>
<pre><code>    <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Test</span>
      <span class="hljs-attr">run:</span> <span class="hljs-string">|
        npm run ci-test
        npm run coverage
</span>
    <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Publish</span> <span class="hljs-string">to</span> <span class="hljs-string">coveralls.io</span>
      <span class="hljs-attr">uses:</span> <span class="hljs-string">coverallsapp/github-action@v1.1.2</span>
      <span class="hljs-attr">with:</span>
        <span class="hljs-attr">github-token:</span> <span class="hljs-string">${{</span> <span class="hljs-string">github.token</span> <span class="hljs-string">}}</span>
</code></pre></li>
</ul>
<p>If you need a working example, check <a target="_blank" href="https://github.com/royNiladri/js-big-decimal">JS Big Decimal</a></p>
]]></content:encoded></item><item><title><![CDATA[Taking Back Privacy in 2021]]></title><description><![CDATA[The Social Dilemma opened our eyes to the way social networks operate. While many can argue they do not have anything to hide, giving machines power to understand and predict you better is something I am not comfortable with. I get irked when I see a...]]></description><link>https://ones-zeros.royniladri.dev/taking-back-privacy-in-2021</link><guid isPermaLink="true">https://ones-zeros.royniladri.dev/taking-back-privacy-in-2021</guid><category><![CDATA[privacy]]></category><category><![CDATA[Developer]]></category><category><![CDATA[lifestyle]]></category><dc:creator><![CDATA[Niladri Roy]]></dc:creator><pubDate>Fri, 15 Jan 2021 07:55:25 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1610696741791/KsVI4epxr.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>The Social Dilemma opened our eyes to the way social networks operate. While many can argue they do not have anything to hide, giving machines power to understand and predict you better is something I am not comfortable with. I get irked when I see advertisements for Marvel T-shirts moments after I discuss getting a T-shirt around my phone. I made a couple of changes to my online life. Next up is the Whatsapp agreement. Yes, WhatsApp still cannot read your chats with friends and family, but they can tap into conversations with business accounts, and share that data with 3rd party. So what do we do now? Here's my list of online changes that I follow and would recommend.</p>
<h2 id="web-browser-and-search-engine">Web browser and search engine</h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1610694514140/jEKkCQs7l.png" alt="image.png" />
<a target="_blank" href="https://duckduckgo.com/">DuckDuckGo</a> is a private search engine and also has a mobile app. It does not track user queries. What this means is that you will stop getting all the customized results you saw on Google, which in turn translates to you spending a few more seconds to find your result. Does it replace Google? No. There are times I have a hard time finding a result, in which case I try Google. But now I give Google maybe 1 in 20 searches.</p>
<h2 id="browser-extension">Browser extension</h2>
<p>I already used to have <a target="_blank" href="https://adblockplus.org/">AdBlockPlus</a>, and it is great at removing advertisements from sites, but it was not enough. I came across <a target="_blank" href="https://privacybadger.org/">Privacy Badger</a>, an extension that disables popular trackers.
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1610694849673/8DDtXyj2y.png" alt="image.png" /></p>
<h2 id="social-media">Social Media</h2>
<p>Well, this one is tricky. You cannot just ditch Facebook/Instagram/LinkedIn/Twitter because you have all your friends and family there. So the next best thing you can do is time-bound those apps. Most smartphones come with a screen time limiter. Set the timer to say 30 minutes for Instagram and Facebook. Increase/decrease the time to your preference. Another thing to consider is getting polarised. You will often come across socially or politically charged posts and depending on how you engage with it, the platform will keep feeding you posts that mirror your belief system. An in-depth analysis is required before you take a drastic stand. Always listen to the other side of the story, check your sources, and do not recirculate "news" without validating authenticity.</p>
<h2 id="messaging">Messaging</h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1610695573586/jumoKHMRB.png" alt="image.png" />
Lastly, addressing the elephant in the room, private chats. I had used <a target="_blank" href="https://telegram.org/">Telegram</a>, and it is quite functional. Due to the lack of group video calling feature, I switched to <a target="_blank" href="https://signal.org/">Signal</a>. and its privacy features are amazing. Of course, it is end to end encrypted. All the messages are saved locally on your device, backup, if enabled is encrypted, photos, or files you send are encrypted and stripped of metadata. The list goes on. It is open-source and runs on donations.</p>
<h2 id="email">eMail</h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1610697253342/cUMfvxbGw.png" alt="image.png" />
I am still in the process of exploration and might add more to this. I encountered <a target="_blank" href="https://protonmail.com">ProtonMail</a> and think it will suit my needs for now. The free plan has 500MB of storage and the monthly plans are a tad expensive. </p>
<h2 id="governments-role">Government's role</h2>
<p>Most companies have a separate set of rules when it comes to European countries. If you are a developer in a company that processes European data, you'll have encountered compliance training dedicated to GDPR (General Data Protection Regulation). The Government has taken stringent measures to ensure data about its people is not misused. More countries should take a stand and make a legal barrier against the monetization of private data.</p>
<h2 id="individuals-role">Individual's role</h2>
<p>Be aware of the applications you use. Glance through the data privacy section of terms and conditions. Know your biases, and take important decisions addressing those. Finally, shout out and contribute to open source projects that value data privacy. You as an individual have an important role in keeping the open-source community thriving.</p>
<h2 id="transition-summary-tldr">Transition Summary (TLDR)</h2>
<ul>
<li>Google -&gt; DuckDuckGo</li>
<li>Chrome (Mobile Browser) -&gt; DuckDuckGo (Mobile Browser)</li>
<li>AdBlockPlus -&gt; AdBlockPlus + Privacy Badger</li>
<li>Social Media -&gt; Limit Time, Research sources</li>
<li>WhatsApp -&gt; Telegram, Signal</li>
<li>Gmail -&gt; ProtonMail</li>
<li>Encourage the Government to take privacy seriously</li>
<li>Contribute to privacy champions</li>
</ul>
<p>[Cover Photo courtesy: Photo by <a target="_blank" href="https://unsplash.com/@tobiastu?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Tobias Tullius</a> on <a target="_blank" href="https://unsplash.com/s/photos/privacy?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Unsplash</a>]</p>
<div class="hn-embed-widget" id="buymecoffee"></div>]]></content:encoded></item><item><title><![CDATA[Time Management and Productivity Tools for Developers]]></title><description><![CDATA[Don't you love the rush of dopamine when you check off a task on a to-do list? It instills in us a sense of accomplishment apart from reaching the goal. Having a well-maintained to-do list also helps us keep on track. Hence, a few years ago, I starte...]]></description><link>https://ones-zeros.royniladri.dev/productivity-tools-for-developers</link><guid isPermaLink="true">https://ones-zeros.royniladri.dev/productivity-tools-for-developers</guid><category><![CDATA[Productivity]]></category><category><![CDATA[webdev]]></category><category><![CDATA[2Articles1Week]]></category><category><![CDATA[project management]]></category><category><![CDATA[General Programming]]></category><dc:creator><![CDATA[Niladri Roy]]></dc:creator><pubDate>Tue, 05 Jan 2021 12:57:35 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1609848311007/dPLreKkYZ.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Don't you love the rush of dopamine when you check off a task on a to-do list? It instills in us a sense of accomplishment apart from reaching the goal. Having a well-maintained to-do list also helps us keep on track. Hence, a few years ago, I started using Todoist.</p>
<h2 id="todoist">Todoist</h2>
<p>It is a great to-do list tracker. The free plan comes with enough organization features. You can group tasks into projects, make sections within a project, and add sub-tasks to a task. It parses natural language to set the deadline and allows recurring tasks. There is a concept of karma points when further gamify task completion. The top features of Todoist are the ease of adding new tasks and the widget for mobile devices for quick access.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1609848485363/CyX3bNoid.png" alt="image.png" /></p>
<p>While this served me well for a few years, it does have some drawbacks.</p>
<ul>
<li>There is no place to add details</li>
<li>It is easy to miss a deadline</li>
<li>With a lot of overdue tasks and upcoming tasks, it can be stressful to manage at times (like after a vacation)</li>
</ul>
<h2 id="ms-planner-trello">MS Planner, Trello</h2>
<p>I tried to use professional project management tools to track my objectives and tasks for a while. While both of these have much richer features than Todoist, they lack simplicity. It takes a couple of clicks to add a task and all the fancy bells and whistles cause distractions. Hence, I moved out of them pretty quickly.</p>
<h2 id="notion">Notion</h2>
<p>This was a golden find. It is a note-taking application that processes markdown and can have structured data like in a database. With some YouTube hunting, I was able to set up a structure, where I have multiple projects, each containing some epics, and the final action items called tasks. I tweaked the fields to my preference and viola, I had my custom task tracking application. Notion also allows the creation of multiple views and add filters. So I can easily set up a view that showed what my upcoming tasks are for the week. Another fun part is everything in Notion is a block and a block can be linked to a page. So each task can be made into its own page where I can jot down my plans and progress.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1609847735539/YJye2CJw1.png" alt="image.png" />
<em>My Notion Dashboard</em></p>
<p>You can also create a page that you can share globally. It can be something like the future roadmap of a product or your upcoming content!</p>
<p>But again, this is not a silver bullet. It's a little slow, and have negligible offline support. (I can add tasks or complete them offline in Todoist) The problem of time management too is not exactly solved.</p>
<h2 id="google-calendar">Google Calendar</h2>
<p>After watching some more productivity videos I have added Calendar to the mix and it feels complete now. I have marked out times for office and self-care. I then add things like my study and blogging in the gaps, and lo and behold, I spend less time scrolling social media and ingesting adds, and more on developing myself. You can use a calendar of your choice.</p>
<h2 id="the-process">The process</h2>
<p>Todoist is still the place where most of it starts. I add a task and a deadline. At some convenient time, I move that over to Notion and add relevant details. Then I check the calendar to ensure I have enough time to deliver it and block some of it. If I find that the deadline is not realistic, I either postpone it or remove its deadline (which implies I'll do it at some point when I get time). I have used this setup since the last quarter of 2020, and honestly, it has paid off. I delivered my tasks at my work, scored an A at college, and started blogging. I still have time to browse Netflix and chat with friends. </p>
<p>Let me tell you, this is not perfect and by the end of this year I'll probably make some more changes, but it's important to start. Once to explore tools and set up a workflow, you will get to know what works and what does not. There are multiple productivity mantras and some of them might be conflicting. You have to experiment to understand which style suits you and gives you the best returns. And, always be open to change...</p>
<h2 id="privacy-note">Privacy note</h2>
<p>None of the tools I listed are end to end encrypted. The traffic is encrypted on the wire due to HTTPS, but not at rest. Your data can be viewed by employees of the respective companies. So do not put your highly personal information or confidential information from your works place in these.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1609849731321/GTr_AWIdU.png" alt="image.png" />
<em>Overview of E2E encryption</em></p>
<h2 id="links-to-mentioned-apps">Links to mentioned apps</h2>
<ul>
<li><a target="_blank" href="https://todoist.com/">Todoist</a></li>
<li><a target="_blank" href="https://www.notion.so/">Notion</a></li>
<li><a target="_blank" href="https://calendar.google.com/calendar/">Google Calendar</a></li>
</ul>
<p>✅ Published content about productivity!</p>
<hr />
<p>Love what you see? Follow me or subscribe to the newsletter to stay updated when I post more cool stuff!</p>
<div class="hn-embed-widget" id="buymecoffee"></div>]]></content:encoded></item><item><title><![CDATA[My 2020 WFH Setup]]></title><description><![CDATA[This has been a crazy year. This is the year I realized that I love being out sometimes, even if I am an introvert! I switched my job and started my new position just a week before India went into complete lockdown. I had also started my Masters at G...]]></description><link>https://ones-zeros.royniladri.dev/my-2020-wfh-setup</link><guid isPermaLink="true">https://ones-zeros.royniladri.dev/my-2020-wfh-setup</guid><category><![CDATA[webdev]]></category><category><![CDATA[setup]]></category><category><![CDATA[2Articles1Week]]></category><dc:creator><![CDATA[Niladri Roy]]></dc:creator><pubDate>Wed, 30 Dec 2020 17:34:19 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1609345929443/9bW7s0JLR.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>This has been a crazy year. This is the year I realized that I love being out sometimes, even if I am an introvert! I switched my job and started my new position just a week before India went into complete lockdown. I had also started my Masters at Georgia Tech, and effectively was spending most of my awake time with my laptop. The place of work was my comfy bed. After a few weeks of insane poses, my back nudged me to do something about it! Thus the journey began.</p>
<h2 id="the-desk-and-chair">The desk and chair</h2>
<p>I needed a place to keep my laptop and distance myself from the bed, hence a table and a chair. I hopped on to Amazon, got my mind blown by the prices, and procrastinated for a week. Then I headed over to a local shop and was pleasantly surprised by the pricing. I got a study desk with multiple drawers and cabinets and a comfy chair all in under INR 15,000 (~$200)! One heck of a bargain.</p>
<h2 id="the-monitor">The monitor</h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1609346076975/ql2ZdJFex.png" alt="image.png" />
<em>Dell P2419H - 24" Full HD LED Monitor</em></p>
<p>It is a piece of beauty and functionality. The display is crystal clear, bot for work and entertainment. It comes with an adjustable stand, that allows changing the height and the tilt. This allows me the flexibility to use either one display on top of the other, or side by side. It has an elegant design and the thin bezels almost disappear into the background.</p>
<h2 id="the-keyboard">The keyboard</h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1609346413906/dziF2qKkh.png" alt="image.png" />
<em>Logitech K375s Multi-Device Keyboard</em></p>
<p>This crazy keyboard connects with both my windows laptops and my iPad. While it is true I have never used it with the iPad, but I just love this possibility. It can switch between 3 devices and supports Windows, Mac, Android, and obviously Linux. The only drawback that I found is the switch off button is at the back of the keyboard and hence hard to access. I love the key press feedback, but if you are expecting something mechanical, then this one is not it.</p>
<h2 id="the-mouse">The mouse</h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1609346880094/0a-uqfAZ8.png" alt="image.png" />
<em>Logitech B170 Wireless Mouse</em></p>
<p>It is a very basic wireless mouse. Gets the job done as long as you are on one system, but does not allow multidevice support. I have to manually plug in the receiver to the laptop I want to use. Looking for an upgrade next year.</p>
<h2 id="the-ipad-pro">The iPad Pro</h2>
<p>That is just for show on the table! I use it for my studies and when I want to be reminded that it takes more than an iPad and an overpriced apple pencil to create digital art. It's a pretty handy entertainment center and reader when on the move.</p>
<h2 id="my-laptops">My laptops</h2>
<p>My personal laptop is a Dell Inspiron, with i7 7th gen, 16GB RAM, 4GB Radeon Graphics, 2TB HDD. My system runs Windows 10 by default, but I have set up Kubuntu dual boot. Having a dedicated Linux setup helps with my college projects. The laptop I got from my office is Lenovo with i7 8th Gen, 32 GB RAM, 512 GB SSD.</p>
<p>Here is me with the imaginary teacup. While the laptops are powered by Intel, I am powered by tea!
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1609347554213/nk5H3_8vp.jpeg" alt="image.jpg" /></p>
<h2 id="upgrades-to-look-forward-to">Upgrades to look forward to</h2>
<ul>
<li>Another display</li>
<li>A gaming/streaming chair (I do neither, but they are comfy)</li>
<li>A mouse that supports multi-device</li>
<li>A cute desk plant</li>
</ul>
<p>If you have any suggestions or recommendations, please do share in the comments below!</p>
<hr />
<p>Wish you all a very Happy New year! Keep hacking, keep learning.</p>
<div class="hn-embed-widget" id="buymecoffee"></div>]]></content:encoded></item><item><title><![CDATA[Deploying Static WebApps - A Step by Step Guide]]></title><description><![CDATA[From index.html to a website on a custom domain
Foreword
This post assumes you know how to build a static website and merely touches over the options. This is intended as a deployment guide.
Building a website
There are a lot of options to host stati...]]></description><link>https://ones-zeros.royniladri.dev/deploying-static-webapps-a-step-by-step-guide</link><guid isPermaLink="true">https://ones-zeros.royniladri.dev/deploying-static-webapps-a-step-by-step-guide</guid><category><![CDATA[GitHub]]></category><category><![CDATA[Devops]]></category><category><![CDATA[2Articles1Week]]></category><category><![CDATA[domain]]></category><category><![CDATA[network]]></category><dc:creator><![CDATA[Niladri Roy]]></dc:creator><pubDate>Sun, 06 Dec 2020 05:07:31 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1607162281251/4qS49sBgM.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h4 id="from-indexhtml-to-a-website-on-a-custom-domain">From index.html to a website on a custom domain</h4>
<h2 id="foreword"><strong><em>Foreword</em></strong></h2>
<p><em>This post assumes you know how to build a static website and merely touches over the options. This is intended as a deployment guide.</em></p>
<h2 id="building-a-website">Building a website</h2>
<p>There are a lot of options to host static content. While most content creators would prefer the comfort of a service like <a target="_blank" href="https://wordpress.com/">WordPress</a>, as a developer, I tend to prefer a little more control. GitHub Pages provides both freedom and version control. The decision tree is just getting started here! You can create a website in GitHub using either of the following two ways.</p>
<h3 id="github-pages-template-using-jekyll">GitHub Pages template using Jekyll</h3>
<p>There are some basic templates provided by GitHub Pages as jumping-off points. You can consider them as some sort of theme, and build based on top of that. The pages can be written in HTML or Markdown, and you can add styles and scripts to enhance functionality and experience. This uses Ruby to build the contents and might need some learning and getting used to before you can properly control it. Find more details about this option at <a target="_blank" href="https://jekyllrb.com/docs/github-pages/">Jekyll</a>. The benefit of using this option is that GitHub handles the building and rendering the site.</p>
<h3 id="using-a-ui-framework-of-your-choice">Using a UI framework of your choice</h3>
<p>You can use any of the prevalent UI frameworks like Angular, React, Vue, and the sorts to generate a static site. You have to build the artifacts and configure GitHub Pages to render the contents of the <em>build</em> or <em>dist</em> folder. More options here:</p>
<ul>
<li>You can build the source code and commit the folder to be served</li>
<li>You can set up a build pipeline (I prefer <a target="_blank" href="https://travis-ci.org/">Travis CI</a>).</li>
</ul>
<p>As Uncle Ben once said, “With great power, comes great responsibility”.</p>
<h2 id="default-hosting">Default Hosting</h2>
<p>On your repository, if you visit the setting sections and scroll down to GitHubPages, you’ll find the option to select a branch and root folder. By default, nothing will be selected. See below a basic setting that will create a page with the root folder, and use the README.md or index.html as the starting point. The hosted URL will be of the form:<code>https://&lt;username&gt;.github.io/&lt;repository-name&gt;</code></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1607161782747/Y2rhd3jUE.png" alt="image.png" /></p>
<p>The site is now hosted on GitHub, using your username as a sub-domain. This is a good place to start and see changes. GitHub Pages is available only for public repositories for free members.</p>
<h2 id="porting-to-a-custom-domain">Porting to a custom domain</h2>
<p>There comes a certain point in life where you want more! So one fine morning, you purchase a domain. There are again a lot of options out there and needs a post of its own. For context, I purchased mine from <a target="_blank" href="https://domains.google/">Google domains</a>, and it will cost me about a thousand Indian Rupees per year. As your hairs start greying, you’ll make more websites, which might be related to the same domain. Instead of purchasing multiple domains for a group of things, we can leverage the same one, thus reducing cost.</p>
<h3 id="the-bad-idea">The bad idea</h3>
<p>Set up different subprojects and make folders inside the <em>build</em> directory. This will work, but the change of themes as the user browses through the same website will baffle them, not to mention that hosting different websites as subfolders will be unprofessional (example, https://mark.com/facebook, https://mark.com/instagram and so on). [Disclaimer: The author just came up with these links and are not meant to be visited. The author, aka me, will not be responsible for any or all losses incurred in an attempt to navigate to the aforementioned links.]</p>
<h3 id="subdomains-to-the-rescue">Subdomains to the rescue</h3>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1607161807136/MApvkDLzw.png" alt="image.png" /></p>
<p>Yes, <em>www</em> is a subdomain. The subdomain is an optional part and can be committed (check Medium URL). Generally, the apex domain (medium.com) and subdomain www (www.medium.com) point to the same resource or are redirected. We can use subdomains to host different sites, all under the same domain name. Continuing the example from above, the two sites now will be https://facebook.mark.com and <a target="_blank" href="https://instagram.mark.com.">https://instagram.mark.com.</a></p>
<p>Let us jump to the configurations now.</p>
<h2 id="configurations">Configurations</h2>
<h3 id="step-1-setting-up-a-record">Step 1: Setting up A record</h3>
<p>You need to configure the A record so that it points to the Github Pages servers. The screenshot below shows the configuration for my domain. The IPs will be the same, but it is better to read some more about this from the <a target="_blank" href="https://docs.github.com/en/free-pro-team@latest/github/working-with-github-pages/managing-a-custom-domain-for-your-github-pages-site">GitHub doc</a>.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1607161842954/oYrefSZQS.png" alt="image.png" />
<em>A record configuration</em></p>
<h3 id="step-2-setting-up-a-subdomain">Step 2: Setting up a subdomain</h3>
<p>This is the easiest step, as shown below- just add a CNAME record to point to your GitHub URL (remember .github.io). Generally, this takes a while to set up.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1607161963206/WIZetrSGX.png" alt="image.png" />
<em>CNAME configuration, by Niladri Roy</em></p>
<h3 id="step-3-configuring-github">Step 3: Configuring GitHub</h3>
<p>Back at the GitHub repository settings page, fill in the box for “custom domain” and hit save. It will need some time to take effect. If your domain uses HTTPS, you can enforce HTTPS. This option will be enabled once the other things are set up by GitHub. A file called CNAME will typically be committed to the root of your repository by default. If this file is missing, please add one with the following details:</p>
<blockquote>
<p>[subdomain.]domain-name.top-level-domain</p>
</blockquote>
<p>In my case, the resulting line is <em>omscs.royniladri.dev</em> (no protocol or slashes). It should contain just this line and nothing else. The subdomain is in square brackets because it is optional — you can host a GitHub Pages website on the apex domain.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1607162013292/SJf9mbYvP.png" alt="image.png" />
<em>GitHub Pages using a custom domain</em></p>
<p>After all the settings are done, check back in an hour to find your newly hosted site. The icing on the cake is the fact that the old URL still works. If you had shared your <em>.github.io</em> URL, all future requests are automatically forwarded to use the custom domain with no additional setup.</p>
<blockquote>
<p>May the domain be with you! — A curious developer</p>
</blockquote>
<p>[P.S. If you are interested in checking out the site, visit <a target="_blank" href="https://omscs.royniladri.dev/">OMSCS Journey</a>.]</p>
<hr />
<p>Love what you see? Follow me or subscribe to the newsletter to stay updated when I post more cool stuff!</p>
<div class="hn-embed-widget" id="buymecoffee"></div>]]></content:encoded></item><item><title><![CDATA[How to Date a Tech Bro]]></title><description><![CDATA[This post was inspired by Anita Ihuman's  How to date a tech sis
In this post, let me walk you over the fundamentals of dating a tech bro!
Keep your bags packed
Tech bros in general are travel enthusiasts. They spend most of the time staring at scree...]]></description><link>https://ones-zeros.royniladri.dev/how-to-date-a-tech-bro</link><guid isPermaLink="true">https://ones-zeros.royniladri.dev/how-to-date-a-tech-bro</guid><category><![CDATA[funny]]></category><category><![CDATA[DevLife]]></category><category><![CDATA[2Articles1Week]]></category><category><![CDATA[life-hack]]></category><dc:creator><![CDATA[Niladri Roy]]></dc:creator><pubDate>Sat, 05 Dec 2020 05:32:09 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1607146256413/qnZidHo9y.webp" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>This post was inspired by Anita Ihuman's  <a target="_blank" href="https://movi.hashnode.dev/how-to-date-a-tech-sis-ckia30auq01b3jts1ep1sat2c">How to date a tech sis</a>
In this post, let me walk you over the fundamentals of dating a tech bro!</p>
<h2 id="keep-your-bags-packed">Keep your bags packed</h2>
<p>Tech bros in general are travel enthusiasts. They spend most of the time staring at screens (from dual monitors to smartphones) and love the occasional escape to a few days of digital detox. </p>
<p><img src="https://static01.nyt.com/images/2015/12/06/books/review/1206-BKS-Travel/1206-BKS-Travel-articleLarge-v2.gif" alt="image.png" /></p>
<h2 id="be-creative-in-your-gifts">Be creative in your gifts</h2>
<p>As a techie, he probably makes enough money. He also loves the thrill of reading through articles and watching hundreds of YouTube reviews before making an informed decision. Do not deprive him of this adrenaline rush! Instead, get to know him and spend some time making something. He loves a personal touch.</p>
<p><img src="https://data.whicdn.com/images/51239891/original.gif" alt="image.png" /></p>
<h2 id="be-prepared-to-watch-nerdy-movies">Be prepared to watch Nerdy movies</h2>
<p>Please know the difference between Star Trek, Star Wars, and Guardian of the Galaxy. Be ready to waste weekends with a rerun of the Batman trilogy, or a Marvel marathon! The good part is, he can pause and explain the intricate details if you blink and miss an important part.
<img src="https://media.giphy.com/media/dQtT4S4BDBhcmjrjRb/giphy.gif" alt="image.png" /></p>
<h2 id="confide-in-him">Confide in him</h2>
<p>He is a keeper of secrets. So go ahead and make some confessions. Feeling insecure about something? Go ahead and talk to him. He makes a living out of turning bugs into features. He will be more than happy to show you the perfect picture of yourself that he sees!</p>
<p><img src="https://i.pinimg.com/originals/52/22/fb/5222fb02155a032a609067e85dd879b9.gif" alt="image.png" /></p>
<h2 id="treat-his-pet-well">Treat his pet well</h2>
<p>A vast majority of techies own pets, and you better be comfortable with his furry friends or that might be a deal-breaker!
<img src="https://media.giphy.com/media/Kx82Lvb7wcYNO/giphy.gif" alt="image.png" /></p>
<h2 id="be-explicit">Be explicit</h2>
<p>No, they don't understand unspoken words. They are worse than men in general when it comes to picking up social cues. Their evolution was hindered by the amount of <code>console.log</code> and <code>System.out.println</code> they frantically typed in! So please speak up and be assured that it will be heard.
<img src="https://media.giphy.com/media/huySh9rd9tsIL4cBGf/giphy.gif" alt="image.png" /></p>
<h2 id="dont-plan-anything-in-the-morning">Don't plan anything in the morning</h2>
<p>These creatures are night owls and show their worst colors when woke up early! So plan events accordingly; he will most likely not join you in your morning yoga! Going for a post-dinner stroll? Count him in.
<img src="https://media.giphy.com/media/2tN5tQXC4CyURVwuwC/giphy.gif" alt="image.png" /></p>
<h2 id="read-and-support-his-blog">Read and support his blog</h2>
<p>Yes please! Blogs are not always tutorials and there are often some gems like these! You don't have to be a techie to show some support. Read them, share them with your friends. Help them get their dose of dopamine.
<img src="https://media.giphy.com/media/RlHVpsV3w8zO9lyE2E/giphy.gif" alt="image.png" /></p>
<h2 id="conclusion">Conclusion</h2>
<p>Go ahead and get that tech bro of yours! While they are relatively low maintenance, be warned they are fragile! So do not drop, knock, or spill coffee (on them or their work). Wish you the best of luck!
<img src="https://media.giphy.com/media/26tn8zNgVmit475RK/giphy.gif" alt="image.png" /></p>
<hr />
<p>If you liked this (highly informative) laughter pill for Saturday, and love staying up to date with technology trends, follow me on my journey! And finally, if you are feeling $3 richer,  help me get my dose of caffeine and L-Theanine.</p>
<div class="hn-embed-widget" id="buymecoffee"></div>]]></content:encoded></item><item><title><![CDATA[TypeWritter Effect - Vanilla JS]]></title><description><![CDATA[https://codepen.io/nilroy/pen/JjXmjmZ
There comes a time when you want to do something cool like a typewriter on a web page. There are multiple ways to accomplish it, but today let me show you the vanilla JS way!
The Algorithm
First, we have to initi...]]></description><link>https://ones-zeros.royniladri.dev/typewritter-effect-vanilla-js</link><guid isPermaLink="true">https://ones-zeros.royniladri.dev/typewritter-effect-vanilla-js</guid><category><![CDATA[JavaScript]]></category><category><![CDATA[animation]]></category><category><![CDATA[Web Development]]></category><category><![CDATA[Frontend Development]]></category><category><![CDATA[2Articles1Week]]></category><dc:creator><![CDATA[Niladri Roy]]></dc:creator><pubDate>Fri, 04 Dec 2020 12:47:08 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1607058646420/5OG1tR1fl.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://codepen.io/nilroy/pen/JjXmjmZ">https://codepen.io/nilroy/pen/JjXmjmZ</a></div>
<p>There comes a time when you want to do something cool like a typewriter on a web page. There are multiple ways to accomplish it, but today let me show you the vanilla JS way!</p>
<h2 id="the-algorithm">The Algorithm</h2>
<p>First, we have to initialize a list of strings that we want to type and erase in a loop. The idea is to start from the first character of the first line. We keep adding characters, till we reach the end. Note that we have added <code>+ 5</code> here to stall for a few more cycles before we start erasing. Then we start removing characters, this time 2 at a time! This creates an effect of slow typing and fast erase. Once we reach the beginning of the string, we reset the direction and move on to the next item in the array. Finally, once we reach the end, we start over from the first item in the array.</p>
<h2 id="performance">Performance</h2>
<p>I switched to the performance tab and recorded the run for about 10 seconds. The scripting time is approximately 0.002%.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1607060865132/v8THZayNw.png" alt="image.png" /></p>
<h2 id="advantage-over-css">Advantage over CSS</h2>
<p>I have seen some CSS based solutions, but they have a dependency on the number of characters and work for only one string. This allows you to work with multiple strings in a loop and independent of the string length. If you want to tinker with the speed, just change the timeout value.</p>
<hr />
<p>Love what you see? Follow me or subscribe to the newsletter to stay updated when I post more cool stuff!</p>
<div class="hn-embed-widget" id="buymecoffee"></div>]]></content:encoded></item><item><title><![CDATA[Norman Doors - To Push or To Pull?]]></title><description><![CDATA[Doors are a portal, it allows us to access to buildings and also allows escape! But how many times have you tried to push a door that is meant to be pulled or vice-versa? Sometimes there is a sticker that says,  "Push", and yet you pull. If you feel ...]]></description><link>https://ones-zeros.royniladri.dev/norman-doors-to-push-or-to-pull</link><guid isPermaLink="true">https://ones-zeros.royniladri.dev/norman-doors-to-push-or-to-pull</guid><category><![CDATA[Design]]></category><category><![CDATA[2Articles1Week]]></category><category><![CDATA[user experience]]></category><dc:creator><![CDATA[Niladri Roy]]></dc:creator><pubDate>Thu, 03 Dec 2020 10:26:29 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1606990884713/IrShg8EeN.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Doors are a portal, it allows us to access to buildings and also allows escape! But how many times have you tried to push a door that is meant to be pulled or vice-versa? Sometimes there is a sticker that says,  "Push", and yet you pull. If you feel embarrassed or stupid, worry not my friend, it is not your fault alone, it is a design flaw.</p>
<blockquote>
<p>Donald Arthur Norman is an American researcher, professor, and author. Norman is the director of The Design Lab at the University of California, San Diego. He is best known for his books on design, especially The Design of Everyday Things.  <a target="_blank" href="https://en.wikipedia.org/wiki/Don_Norman">Wikipedia</a></p>
</blockquote>
<p>Doors can get even more complicated if you throw in revolving doors, clear glass doors, with no touchpoints. A door is said to be a <strong>Norman door</strong> if it is not intuitive or self-explanatory. Let us now see how we can fix it.</p>
<h2 id="the-push-side">The push side</h2>
<p>If one side of the door is smooth without and handles or knobs, there is only one thing you can do with it. So not attaching anything to this side of the door is one option. But what if someone starts pushing close to the hinge? To deal with this, we need to give a visual clue as to which end of the door should be pushed - maybe in the form of a metal plate.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1606988850314/X2K1bDTHR.png" alt="image.png" /></p>
<h2 id="the-pull-side">The pull side</h2>
<p>One of the most common things that we spot on a door is a handle. While it is easy to pull, it still allows pushing. The doors of cars are meant for pulling from the outside, but that design will not fit a big door. So, let us get back to handle. Adding a label will make things better, but not by much. We can design the pull handle in a way that makes push much easier than a pull. One such example is shown below:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1606989955689/_zoAeWs2T.png" alt="image.png" />
Do you have any more ideas to make the pull side better?</p>
<h1 id="emergency-door">Emergency door</h1>
<p>Most emergency doors avoid confusion by not having a handle. There is a bar that affords to push. There are often instructions added, but during times of crisis, time is of the essence, and having a good design is priceless.
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1606990072818/q_HfqkuKw.png" alt="image.png" /></p>
<h2 id="watch-your-steps">Watch your steps</h2>
<p>While you wander around in this wide wild world, beware of such catastrophic designs!</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1606990399682/6QaC0exgw.png" alt="image.png" /></p>
<p>All this to say, good designs matter, not just in the software domain, but in the world out there in general. Next time you are designing something, and focusing on how to make it fancy, bear in mind, it needs to be usable and enjoyable. Design for the intended users!</p>
]]></content:encoded></item><item><title><![CDATA[Corporate CI/CD Setup - Introductions and Installations]]></title><description><![CDATA[Welcome to the series. Today I will introduce you to the stack that we are going to use and set up accounts. We will be installing Jenkins and setting up a small backend project to demonstrate the build pipeline. To mock most corporate environments, ...]]></description><link>https://ones-zeros.royniladri.dev/corporate-cicd-setup-introductions-and-installations</link><guid isPermaLink="true">https://ones-zeros.royniladri.dev/corporate-cicd-setup-introductions-and-installations</guid><category><![CDATA[ci-cd]]></category><category><![CDATA[Jenkins]]></category><category><![CDATA[automation]]></category><category><![CDATA[Devops]]></category><category><![CDATA[2Articles1Week]]></category><dc:creator><![CDATA[Niladri Roy]]></dc:creator><pubDate>Tue, 01 Dec 2020 19:30:58 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1606851011774/LXcF1Ve_V.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Welcome to the series. Today I will introduce you to the stack that we are going to use and set up accounts. We will be installing Jenkins and setting up a small backend project to demonstrate the build pipeline. To mock most corporate environments, I will be using Ubuntu 18.04 (Linux) as the working operating system. You can either have that as a dual boot alongside your windows or use a Virtual Machine.</p>
<h2 id="step-1-install-jenkins">Step 1: Install Jenkins</h2>
<p>The official guide provides detailed instructions on how to set it up on different environments. If you have any other Operating system, check out  <a target="_blank" href="https://www.jenkins.io/doc/book/installing/">this installation guide</a> </p>
<pre><code class="lang-bash">wget -q -O - https://pkg.jenkins.io/debian-stable/jenkins.io.key | sudo apt-key add -
sudo sh -c <span class="hljs-string">'echo deb https://pkg.jenkins.io/debian-stable binary/ &gt; \
    /etc/apt/sources.list.d/jenkins.list'</span>
sudo apt-get update
sudo apt-get install jenkins
</code></pre>
<p>Note that to start Jenkins we need Java 8. If you do not have Java 8 or have a different version, you might see an error like this:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1606799502369/5wO0u4Twc.png" alt="image.png" />
This can be easily rectified by installing the required version as such:</p>
<pre><code class="lang-bash">sudo apt install openjdk-8-jdk
</code></pre>
<p>and then installing Jenkins as before.</p>
<p>If all works fine, you will not see any errors and will be able to open the Jenkins admin screen on <code>http://localhost:8080/</code>. The password can be found in the file <code>/var/lib/jenkins/secrets/initialAdminPassword</code>.</p>
<h2 id="installing-plugins">Installing Plugins</h2>
<p>This is the screen you get when you log in:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1606803638568/ipG3DV1j9.png" alt="image.png" /></p>
<p>Now we have to start customizing Jenkins. We will start with the recommended set of plugins. There are quite a few plugins and this step might take a while to finish.</p>
<p>Once that is done, it will ask for creating an Admin User.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1606810933950/zA-ZgRPno.png" alt="image.png" />
For privacy concerns, I have not added the email field in the screenshot. Finally, you'll be taken to the Jenkins dashboard</p>
<p>Time to land on the dashboard!
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1606811198850/5JKFTXxGh.png" alt="image.png" /></p>
<h2 id="setting-up-bitbucket-and-jira">Setting up BitBucket and Jira</h2>
<p>We will be using  <a target="_blank" href="https://bitbucket.org/">BitBucket</a> as the source code management tool. It uses it as the versioning tool. For Scrum and issue tracking, we will be using  <a target="_blank" href="https://www.atlassian.com/software/jira/free">Jira</a>. Note that both of these have free versions and have enough features for our simple use case.</p>
<p>Once logged in to BitBucket, create a workspace, then a project inside that workspace, and two repositories under the project. My repositories can be found at  <a target="_blank" href="https://bitbucket.org/nilroy/server/src/master/">Server</a> and  <a target="_blank" href="https://bitbucket.org/nilroy/ui-app/src/master/">UI App</a> </p>
<h3 id="linking-jira-project-to-bitbucket-project">Linking Jira project to Bitbucket project</h3>
<p>The first step is to link the workspace. Once done, we can follow along with the onscreen guide to add the relevant repositories.
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1606806618677/7K-RdBQo3.png" alt="image.png" /></p>
<p>Ideally, you should see the list of repositories to choose from in Jira itself. For me, that was not the case. So I went back to BitBucket and selected the repository, and navigated to the Jira tab.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1606807718278/sR-LYUXz9.png" alt="image.png" /></p>
<p>Click on "Manage Linked projects" on the right top corner. </p>
<h2 id="creating-issues-and-view-in-jira">Creating Issues and View in Jira</h2>
<p>We can go to the backlog and create Issues (Stories or bugs). If you make a commit with the issue number, we will be able to see the same on Jira. </p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1606814434011/OD6UL5zDG.png" alt="image.png" /></p>
<h2 id="first-job">First Job</h2>
<p>Time to set up our first Jenkins job. In this step, we just want to get the contents of the repository in the workspace. Since this step interacts with <code>git</code>, it is crucial that you have git preinstalled on the machine.</p>
<pre><code class="lang-bash">sudo apt-get install git
</code></pre>
<p>Let's start by creating a Pipeline job:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1606815503922/jxPTPX1ZH.png" alt="image.png" /></p>
<p>For the time being, we will jump down to the bottom and click on "Try Sample Pipeline" under Pipeline. We will remove all the unnecessary steps (as of now), and click on the Pipeline Syntax link.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1606817394968/eFI2umXac.png" alt="image.png" />
You have to add a credential if one does not exist to access the repository.
From here you can generate the line to copy and add it. The final pipeline should something like this:</p>
<pre><code>pipeline {
        agent <span class="hljs-keyword">any</span>

        stages {
            stage(<span class="hljs-string">'Build'</span>) {
                steps {
                    // <span class="hljs-keyword">Get</span> <span class="hljs-keyword">some</span> code <span class="hljs-keyword">from</span> a GitHub repository
                    git credentialsId: <span class="hljs-string">'xxxx-xxx-xxx-xxxx'</span>, url: <span class="hljs-string">'https://&lt;username&gt;@bitbucket.org/nilroy/server.git'</span>
                }
            }
        }
    }
</code></pre><p>Let us save this and try to build the job by clicking build now. Lo and behold, our job works:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1606817500088/B2tfl4qbl.png" alt="image.png" /></p>
<h2 id="basic-server-code">Basic server code</h2>
<p>As a simple example, I have created a maven project and added a class fine and a test file.</p>
<pre><code class="lang-java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Person</span> </span>{
    <span class="hljs-keyword">private</span> String firstName;
    <span class="hljs-keyword">private</span> String lastName;

    Person(String fn, String ln){
        <span class="hljs-keyword">this</span>.firstName = fn;
        <span class="hljs-keyword">this</span>.lastName = ln;
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> String <span class="hljs-title">getFullName</span><span class="hljs-params">()</span></span>{
        <span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span>.firstName+<span class="hljs-string">" "</span>+<span class="hljs-keyword">this</span>.lastName;
    }
}
</code></pre>
<pre><code class="lang-java"><span class="hljs-keyword">import</span> org.junit.Assert;
<span class="hljs-keyword">import</span> org.junit.Test;

<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">PersonTest</span> </span>{
    <span class="hljs-meta">@Test</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">testFullName</span><span class="hljs-params">()</span></span>{
        Person nilroy = <span class="hljs-keyword">new</span> Person(<span class="hljs-string">"Niladri"</span>, <span class="hljs-string">"Roy"</span>);
        Assert.assertEquals(<span class="hljs-string">"Niladri Roy"</span>, <span class="hljs-string">"Niladri Roy"</span>);
    }
}
</code></pre>
<p>You can check if everything is working as expected by running a clean install and a test using <code>mvn</code>. Again if you do not have maven in your local system (or Virtual machine), you can add it using <code>sudo apt install maven</code>.</p>
<h2 id="build-and-test">Build and Test</h2>
<p>Time to add the last bits of our skeleton pipeline, a stage that builds and a stage that tests. The final pipeline should look like this, with a shell running the maven for us:</p>
<pre><code>pipeline {
        agent <span class="hljs-keyword">any</span>

        stages {
            stage(<span class="hljs-string">'Checkout'</span>) {
                steps {
                    // <span class="hljs-keyword">Get</span> <span class="hljs-keyword">some</span> code <span class="hljs-keyword">from</span> a GitHub repository
                    git credentialsId: <span class="hljs-string">'xxxx-xxxx-xxxxx'</span>, url: <span class="hljs-string">'https://&lt;username&gt;@bitbucket.org/nilroy/server.git'</span>
                }
            }
            stage(<span class="hljs-string">'Build'</span>){
                steps {
                    sh <span class="hljs-string">'mvn -DskipTests clean install'</span>
                }
            }
            stage(<span class="hljs-string">'Test'</span>){
                steps {
                    sh <span class="hljs-string">'mvn test'</span>
                }
            }
        }
    }
</code></pre><p>We can now save it and run the job. If everything goes well, we will see a green field!</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1606849178638/9GTFV5lmv.png" alt="image.png" /></p>
<h2 id="why-i-used-pipeline">Why I used pipeline</h2>
<p>There is an easier way to configure Jenkins had we chosen an empty project. But creating a pipeline has a couple of advantages.</p>
<ol>
<li>The results are much more clear and appealing</li>
<li>The logs are chunked and we can focus on logs only when something fails.</li>
<li>We are developers and prefer to type than click!</li>
<li>You can easily set this up as a project file and version it.</li>
</ol>
<hr />
<p>This is just the tip of an iceberg, and we have a lot to cover ahead. Stay tuned. To keep getting notified when I post, follow me or subscribe to the newsletter!</p>
]]></content:encoded></item><item><title><![CDATA[JS Service Workers — An Introduction]]></title><description><![CDATA[A journey towards taking your web application offline
The Why
You have created an awesome website and ready to host it for everyone to find. You have taken the pain of making it responsive and it looks great on all standard devices. Let us walk throu...]]></description><link>https://ones-zeros.royniladri.dev/js-service-workers-an-introduction</link><guid isPermaLink="true">https://ones-zeros.royniladri.dev/js-service-workers-an-introduction</guid><category><![CDATA[JavaScript]]></category><category><![CDATA[Service Workers]]></category><category><![CDATA[progressive web apps]]></category><category><![CDATA[Web Development]]></category><category><![CDATA[2Articles1Week]]></category><dc:creator><![CDATA[Niladri Roy]]></dc:creator><pubDate>Mon, 30 Nov 2020 19:08:20 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1606737739554/8LTcnz_jH.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h4 id="a-journey-towards-taking-your-web-application-offline">A journey towards taking your web application offline</h4>
<h2 id="the-why">The Why</h2>
<p>You have created an awesome website and ready to host it for everyone to find. You have taken the pain of making it responsive and it looks great on all standard devices. Let us walk through a hypothetical Developer vs Product Manager conversation:</p>
<blockquote>
<p><strong><em>PM:</em></strong> Is this application responsive?</p>
<p><strong><em>Dev:</em></strong> Yes boss!</p>
<p><strong><em>PM:</em></strong> Does it work when he is on a slow internet?</p>
<p><strong><em>Dev:</em></strong> Well, I have minimized the assets, serving them up gzipped, so its optimised, but might take a while to load.</p>
<p><strong><em>PM:</em></strong> What if he goes offline?</p>
<p><strong><em>Dev:</em></strong> (Dumbfounded)Web… Web application? Why would someone use a web application offline? We need to create apps if we want to provide offline capabilities!</p>
</blockquote>
<p>The next part of the conversation might not be very pleasant, so let us skip that. <strong><em>What if I told you your web app can be taken offline? What if I told you that your app can act like a native application in multiple platforms and be pinned to the Start screen for easy access?</em></strong> Welcome to PWA, welcome to the future (not really, it has been around for a while. While <a target="_blank" href="https://youtu.be/MyQ8mtR9WxI">Google introduced PWA</a> in 2015, <a target="_blank" href="https://youtu.be/ZlE7dzoD6GA">Steve Jobs conceptualized it</a> back in 2007!)</p>
<h2 id="what-does-it-take">What does it take?</h2>
<p>One word: <em>JavaScript</em></p>
<p>If you are a front end developer, you are already aware of JS, and its nitty-gritty details. You don’t have to learn Java, you don’t have to download software to develop an android app, and yet another for iOS. You don’t have to take the trouble of publishing it across multiple stores. You simply build upon your already existing awesome webpage.</p>
<h2 id="google-lighthouse">Google Lighthouse</h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1606673088647/8Gdysjj8S.png" alt="image.png" /></p>
<p>Have you seen the <em>lighthouse</em> tab (it would come as an <em>audit</em> on older versions) on Chrome developer tools? Go to any site and run it. You see a couple of metrics — how well does the site perform, does it take into account accessibility, does it follow best practices, and finally <strong>does it have what it takes to be a PWA</strong>? This report then has details on how to improve upon the site and is a great place to start enhancing your application.</p>
<h2 id="what-is-a-service-worker">What is a Service Worker</h2>
<blockquote>
<p>A service worker is a script that your browser runs in the background, separate from a web page, opening the door to features that don’t need a web page or user interaction. — <a target="_blank" href="https://developers.google.com/web/resources/contributors/mattgaunt">Matt Gaunt</a> on <a target="_blank" href="https://developers.google.com/web/fundamentals">Web Fundamentals</a></p>
</blockquote>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1606737952102/sk9mstkLl.png" alt="image.png" />
<em>Service Worker Overview from <a target="_blank" href="https://docs.google.com/presentation/d/1bFVDRa71JK0ilr6lS6y9Twqp9gy8jzV1O8FFbG4A3qk/edit#slide=id.p9">Introduction to Service Workers</a> by Google</em></p>
<p>Let us now dissect the definition:</p>
<p><em>A service worker is a script</em> — It is composed of <strong>JavaScript.</strong> Also note, it is a worker and hence cannot access DOM elements [No more <em>alert(“hello!”)</em>], but has to communicate using messages.</p>
<p><em>Runs in the background —</em> It is run on a <strong>different thread</strong> than the main JS even loop. Note that it might be terminated when not in use, and restarted when required, hence using global variables is a very bad idea.</p>
<p><em>Opening the door to features —</em> It is a programmable network proxy and can intercept requests, respond on behalf of server and cache resources.</p>
<p><em>Don’t need a web page or user interaction —</em> Push notifications, background sync, payment updates — service works bring a lot of handy features to the web platform.</p>
<h2 id="service-worker-life-cycle">Service Worker Life Cycle</h2>
<p>The lifecycle of a service worker is not coupled with the web page. It starts with the first load of the page but persists long after the browser tab is closed.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1606738002464/6jy7oByZ-.png" alt="image.png" />
<em>Service Worker Life Cycle by <a target="_blank" href="https://developers.google.com/web/resources/contributors/mattgaunt">Matt Gaunt</a> on <a target="_blank" href="https://developers.google.com/web/fundamentals">Web Fundamentals</a></em></p>
<p>The first step of registering a service worker is the install step. <em>Typically, assets are downloaded and cached in this step</em>. If all goes well, it moves to the activated step, else moves to the error state. Once activated, it is ready to intercept requests and process messages. <em>Typically, old caches are invalidated here</em>. When there is no activity, it remains idle, and after a few seconds of idling, is terminated. No need to be alarmed, it is brought back to life when a new event occurs, like a request or message. Note that since the worker can be terminated at any point, using global variables is heavily discouraged. IndexedDB can be used to persist data, including cache. The service worker is terminated after some seconds of inactivity to ensure that they don’t live in memory, draining resources.</p>
<p>Service workers are extensively asynchronous and use Promises. No blocking actions are allowed in the worker, failing which it will be stopped.</p>
<h2 id="can-i-use-service-workers">Can I use Service Workers?</h2>
<p>Web developers have lost a lot of their hairs owing to browsers deviating from web standards, it is only natural to have this question at the back of your head while reading through this article. The short answer is no. While some do not support it all together, some allow limited features. The amount of storage also varies from platform to platform and from browser to browser.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1606738020731/p9GEWXoYS.png" alt="image.png" />
<em>Browser compatibility of Service Worker, screenshot from <a target="_blank" href="https://caniuse.com/?search=serviceworker">caniuse.com</a></em></p>
<p>Hence it is a good practice to do a feature test before installing a service worker. We should not have core functionalities in service workers as it might be executed in an incompatible platform-browser combination.</p>
<p>Another factor to keep in mind is that Service Workers can be used only on <strong>HTTPS</strong>-enabled websites. While it works on HTTP through <em>localhost</em>, it will not work in an insecure site. Service workers are powerful, and “<em>with great power, comes great responsibility</em>”. HTTPS ensures that the source of the script is the hosted site and protects against man-in-the-middle attacks.</p>
<h2 id="time-to-code">Time to Code</h2>
<p>Time to whip up some throwaway code! We will start with a simple HTML file with some script. We have a div with an id that we will change. We first check if we can rester a service worker, and if we can, go ahead to register it. Once it is registered, the DOM is updated. We also have logging of errors and meaningful messages to the DOM if something fails.</p>
<p><em>index.html</em></p>
<pre><code class="lang-html"><span class="hljs-meta">&lt;!doctype <span class="hljs-meta-keyword">html</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">title</span>&gt;</span>First Service Worker<span class="hljs-tag">&lt;/<span class="hljs-name">title</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>Service Worker Test<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"response"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">script</span>&gt;</span><span class="javascript">
<span class="hljs-comment">// chcek if the browser supports service workers</span>
<span class="hljs-keyword">if</span> (<span class="hljs-string">'serviceWorker'</span> <span class="hljs-keyword">in</span> navigator) {
    navigator.serviceWorker.register(<span class="hljs-string">"serviceworker.js"</span>,
        { <span class="hljs-attr">scope</span>: <span class="hljs-string">"/"</span> })
        .then( <span class="hljs-function"><span class="hljs-params">registration</span> =&gt;</span> {
            <span class="hljs-comment">// registration is an handle of the worker.</span>
            <span class="hljs-comment">// More event listeners can be attached or messages can be sent to this.</span>
            <span class="hljs-comment">// For this example, we just change the DOM to display message</span>
            <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">"response"</span>).innerHTML = 
                <span class="hljs-string">"Service Worker registered properly"</span>;
        })
        .catch( <span class="hljs-function"><span class="hljs-params">error</span> =&gt;</span> {
            <span class="hljs-comment">// Update DOM and log error in case resgistration fails</span>
            <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">"response"</span>).innerHTML = 
                <span class="hljs-string">"Service Worker NOT registered"</span>;
            <span class="hljs-built_in">console</span>.error(error);
        });
} <span class="hljs-keyword">else</span> {
    <span class="hljs-comment">// UPdate DOM to reflect service workers cannot be used</span>
    <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">"response"</span>).innerHTML = 
                <span class="hljs-string">"Service Worker NOT available"</span>;
}
</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
</code></pre>
<p><em>serviceworker.js</em></p>
<pre><code class="lang-js"><span class="hljs-built_in">console</span>.log(<span class="hljs-string">"We are a service worker"</span>);

<span class="hljs-comment">// This is called once the worker is installed</span>
self.addEventListener(<span class="hljs-string">"install"</span>, <span class="hljs-function"><span class="hljs-params">event</span> =&gt;</span> {
   <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Install event"</span>);
});

<span class="hljs-comment">// This is called once the worker becomes active</span>
self.addEventListener(<span class="hljs-string">"activate"</span>, <span class="hljs-function"><span class="hljs-params">event</span> =&gt;</span> {
   <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Activate event"</span>);
});
</code></pre>
<p>The <em>serviceworker.js</em> file is a barebone for now. We have logs to illustrate the flow. First, it is installed and then activated.</p>
<p>Let me walk you through on how to run this. You can get both the files from the above <em>gist</em>, but if you open the file in a browser it will not work. You’ll need to serve up the contents. The easiest way is to use the npm package called “<em>serve”</em> (assuming you have <a target="_blank" href="https://nodejs.org/en/download/">NodeJS</a> development environment setup). You can navigate to the folder where you have these files and execute the following:</p>
<pre><code class="lang-bash">npm i -g serve
serve
</code></pre>
<p>This will start serving the contents of the folder at port 5000. If you click on the link <a target="_blank" href="http://localhost:5000">http://localhost:5000</a> you’ll see the service worker is registered properly. If you click the network link (the one below local), the service worker will not work (remember HTTPS). In the debugger, you can see the details, as shown below, in the application tab. When you are developing, ensure that “Update on reload” is checked so that changes that you make to your worker are picked up. By default, a service worker once installed will always remain installed (but more on this later).</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1606738827384/m9mnqO8O9.png" alt="image.png" />
<em>Chrome Debug tool to inspect service worker</em></p>
<h2 id="coming-up">Coming up</h2>
<p>This is the first of the series. More on service workers would be posted in the coming weeks. In the meantime, this piece sites a lot of resources that you can explore. Stay tuned to keep learning!</p>
]]></content:encoded></item><item><title><![CDATA[React App and GitHub Actions]]></title><description><![CDATA[From development to go-live in under 2 minutes

As developers, we are often guilty of doing this. The problem statement is simple:

I have a React application and want it deployed on GitHub Pages.

The simplest way to achieve this is to locally build...]]></description><link>https://ones-zeros.royniladri.dev/react-app-and-github-actions</link><guid isPermaLink="true">https://ones-zeros.royniladri.dev/react-app-and-github-actions</guid><category><![CDATA[GitHub]]></category><category><![CDATA[github-actions]]></category><category><![CDATA[React]]></category><category><![CDATA[Web Development]]></category><category><![CDATA[2Articles1Week]]></category><dc:creator><![CDATA[Niladri Roy]]></dc:creator><pubDate>Mon, 30 Nov 2020 05:25:45 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1606713898499/mIVb5AY6K.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h4 id="from-development-to-go-live-in-under-2-minutes">From development to go-live in under 2 minutes</h4>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1606712595427/DQw_ikO8q.png" alt="Who are we" /></p>
<p>As developers, we are often guilty of doing this. The problem statement is simple:</p>
<blockquote>
<p>I have a React application and want it deployed on GitHub Pages.</p>
</blockquote>
<p>The simplest way to achieve this is to locally build it, and push the build directory to “<em>gh-pages”</em> branch and viola. Then I introduced <a target="_blank" href="https://travis-ci.org/">Travis CI</a> to achieve this and recently switched to GitHub Actions.</p>
<p>I have already spent more hours setting this up than I probably would have spent doing it manually, so let me first try to justify my actions:</p>
<ul>
<li><a target="_blank" href="https://github.com/features/actions">GitHub Action</a> is a new kid in town, and as developers, it is our responsibility to become early (debatable at this point) adopters</li>
<li>It has inherent support — I don’t have to share keys and secrets with another third party.</li>
<li>It has a vibrant ecosystem that will only get better with time. For instance, it is just 2 lines to set up a Linux machine with NodeJs.</li>
<li>As a corporate employee who used Jenkins, the setup process feels welcoming.</li>
<li>It supports parallelly running multiple jobs! You can let everything run parallel, or create dependencies. It promises to be quite versatile.</li>
</ul>
<p>Although my current problem statement does not require much of the aforementioned features, it is easier to get my hands dirty with a simpler project.</p>
<h2 id="how-to-get-started">How to get started?</h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1606712637414/iQe_hvJKb.png" alt="GitHub Actions Home" /></p>
<p>The simplest way to start a workflow is to go to the “Actions” tab on your repository and click “set up a workflow yourself”. This will create a file called <em>main.yml</em> with some basic workflow. There is a structure to this YAML file to understand which we need to understand the components of GitHub actions.</p>
<h2 id="the-components-of-github-actions">The Components of GitHub Actions</h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1606712685414/PQvQSr38S.png" alt="Components of GitHub Actions" />
<em>The Components of GitHub Actions, from <a target="_blank" href="https://docs.github.com/en/free-pro-team@latest/actions/learn-github-actions/introduction-to-github-actions#the-components-of-github-actions">GitHub Docs</a></em></p>
<p>GitHub events (push, pull requests, and so on) trigger one or more jobs. Each job is run on a server that is called Runner instance (Virtual machines or Docker instances). Each job comprises one or more steps and each step performs some actions, ranging from echo on a bash terminal to a complicated action developed by the GitHub community that does some heavy lifting. To know more about the components check out the <a target="_blank" href="https://docs.github.com/en/free-pro-team@latest/actions/learn-github-actions/introduction-to-github-actions#the-components-of-github-actions">official documentation</a>.</p>
<h2 id="plan-of-action">Plan of Action</h2>
<p>Now that we are equipped with the understanding of GitHub workflows, it is time to break our task at hand into smaller workable units.</p>
<p>We will be starting with a Ubuntu server, and get the latest NodeJS environment setup. We will have to check out the code and install dependencies. Then we can build and finally publish to GitHub Pages.</p>
<p>And at what point do I want to do this? To answer that, I need to talk briefly about the workflow I follow. I have a <em>development</em> branch on which I work. I make frequent commits and often I do not want to publish changes after each commit. Once I feel I have reached a stable point, I create a pull request on the <em>master</em> branch (this repository existed before they renamed <em>master</em> to <em>main</em>). So I want my action to kick in at a push on <em>master</em>. Note that if I trigger it on pull-request, it will be triggered when the request is created, and I want it to trigger after it is merged. If you have multiple developers, you’ll need to control who can commit on <em>master</em>/<em>main</em> directly.</p>
<h2 id="code-of-action">Code of Action</h2>
<pre><code class="lang-yml"><span class="hljs-attr">name:</span> <span class="hljs-string">build_deploy</span> <span class="hljs-string">CI</span>

<span class="hljs-attr">on:</span>
  <span class="hljs-attr">push:</span>
    <span class="hljs-attr">branches:</span> [ <span class="hljs-string">master</span> ]

<span class="hljs-attr">jobs:</span>
  <span class="hljs-attr">build:</span>
    <span class="hljs-attr">runs-on:</span> <span class="hljs-string">ubuntu-latest</span>

    <span class="hljs-attr">steps:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-attr">uses:</span> <span class="hljs-string">actions/checkout@v2</span>

      <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Use</span> <span class="hljs-string">Node.js</span> <span class="hljs-string">${{</span> <span class="hljs-string">matrix.node-version</span> <span class="hljs-string">}}</span>
        <span class="hljs-attr">uses:</span> <span class="hljs-string">actions/setup-node@v1</span>
        <span class="hljs-attr">with:</span>
          <span class="hljs-attr">node-version:</span> <span class="hljs-string">'12.x'</span>

      <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Install</span> <span class="hljs-string">dependencies</span>
        <span class="hljs-attr">run:</span> <span class="hljs-string">yarn</span> <span class="hljs-string">--frozen-lockfile</span>

      <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Build</span>
        <span class="hljs-attr">run:</span> <span class="hljs-string">yarn</span> <span class="hljs-string">run</span> <span class="hljs-string">build</span>

      <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Deploy</span>
        <span class="hljs-attr">uses:</span> <span class="hljs-string">peaceiris/actions-gh-pages@v3.7.3</span>
        <span class="hljs-attr">with:</span>
          <span class="hljs-attr">github_token:</span> <span class="hljs-string">${{</span> <span class="hljs-string">secrets.GITHUB_TOKEN</span> <span class="hljs-string">}}</span>
          <span class="hljs-attr">publish_dir:</span> <span class="hljs-string">./build</span>
          <span class="hljs-attr">cname:</span> <span class="hljs-string">&lt;domain_name&gt;</span>
          <span class="hljs-attr">enable_jekyll:</span> <span class="hljs-literal">false</span>
          <span class="hljs-attr">user_name:</span> <span class="hljs-string">'github-actions[bot]'</span>
          <span class="hljs-attr">user_email:</span> <span class="hljs-string">'github-actions[bot]@users.noreply.github.com'</span>
</code></pre>
<p>Let us go over the steps.</p>
<ol>
<li>The action has a name!</li>
<li>We run it on a push to master.</li>
<li>The job uses a Ubuntu server</li>
<li>Check out code</li>
<li>Setup NodeJS environment. We can specify the version(s), and yarn comes preinstalled.</li>
<li>We install the dependencies and ensure the lock file is not changed in the process.</li>
<li>We create an optimized production build.</li>
<li>We use an action from the GitHub community to push the changes to the specific branch. We can make customization by setting certain parameters. (Since I have a custom domain, I set that here with <em>cname</em>.)</li>
</ol>
<p>And that is all. You are all set to harness the goodness of GitHub Actions!</p>
<h2 id="the-results">The results</h2>
<p>Apart from this, I have another action that runs the build job on every push to <em>development</em> branch. This ensures I am not breaking anything that will prevent the build when I merge a pull request. Here is how it looks on my repository:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1606713498986/SYbPbB2Dl.png" alt="GitHub Actions in action.png" />
<em>GitHub Actions in action, Niladri Roy</em></p>
<p>The failing build on my development branch helped me correct my mistake and once that started passing, I opened a pull request and merged it. This triggered the “_build<em>deploy CI</em>” workflow, deploying my changes to my website, all in about a minute and a half! How cool is that?</p>
]]></content:encoded></item></channel></rss>