<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Ajah Chukwuemeka</title>
    <description>The latest articles on DEV Community by Ajah Chukwuemeka (@ajahso4).</description>
    <link>https://dev.to/ajahso4</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F37684%2F5af8f57d-6f8a-4a4e-acbf-15ef77fda1c1.JPG</url>
      <title>DEV Community: Ajah Chukwuemeka</title>
      <link>https://dev.to/ajahso4</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/ajahso4"/>
    <language>en</language>
    <item>
      <title>Vaas App (Data visualization as a service) - DOHackathon submission</title>
      <dc:creator>Ajah Chukwuemeka</dc:creator>
      <pubDate>Thu, 07 Jan 2021 22:23:15 +0000</pubDate>
      <link>https://dev.to/ajahso4/vaas-app-data-visualization-as-a-service-dohackathon-submission-ac2</link>
      <guid>https://dev.to/ajahso4/vaas-app-data-visualization-as-a-service-dohackathon-submission-ac2</guid>
      <description>&lt;h2&gt;
  
  
  What I built
&lt;/h2&gt;

&lt;p&gt;A data visualization as a service product that enables non-developers to create downloadable charts from their CSV or JSON data as well as developers to create charts using the provided API. It supports file uploads for non-developers, file url where the data can be downloaded and parsed for developers as well as data objects as JSON data. Users can download the data visualization charts and use it in their presentations or within their own apps or any way they see fit and they can title it accordingly so as to be able to access it in future if they come back to the app. &lt;/p&gt;

&lt;p&gt;Example visualization output:&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--EWwgiTiO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/4ok99b9jpxpv1k4qoz86.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--EWwgiTiO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/4ok99b9jpxpv1k4qoz86.png" alt="Vaas App image"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Category Submission:
&lt;/h3&gt;

&lt;p&gt;Built for Business&lt;/p&gt;

&lt;h3&gt;
  
  
  App Link
&lt;/h3&gt;

&lt;p&gt;My app submission can be found here: &lt;a href="https://vaasapp.co/"&gt;https://vaasapp.co/&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Screenshots
&lt;/h3&gt;

&lt;p&gt;Home page&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--GJtlfGoj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/ayx0cobk06oeexfxny5p.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--GJtlfGoj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/ayx0cobk06oeexfxny5p.png" alt="Home page 1"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Non-developers call to action&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--TgchDvXT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/4lrjzbeg8h05pfi3k6w2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--TgchDvXT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/4lrjzbeg8h05pfi3k6w2.png" alt="Non-developers CTA"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Developers call to action&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--oWA-qtzp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/ewb6lpsm0fngkncthcfz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--oWA-qtzp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/ewb6lpsm0fngkncthcfz.png" alt="Developers CTA"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Chart types&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--BG79Z-aQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/37kks0r564vbxzr1jx30.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--BG79Z-aQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/37kks0r564vbxzr1jx30.png" alt="Chart types"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Data visualization chart display with download button&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--NG7mcq2c--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/2x1osk6n2607ezmburz6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--NG7mcq2c--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/2x1osk6n2607ezmburz6.png" alt="Chart display and download"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Pricing page&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--XFV19cXH--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/lx9zv4evp0kv5ziouu95.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--XFV19cXH--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/lx9zv4evp0kv5ziouu95.png" alt="Pricing page"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Pricing page options description&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--oFvDgpHh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/waxm48z8wq3uhyldq8fo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--oFvDgpHh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/waxm48z8wq3uhyldq8fo.png" alt="Pricing page options description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Viewing all created visualizations&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--j8fpNPID--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/a3226iq0c6hylhacz7m5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--j8fpNPID--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/a3226iq0c6hylhacz7m5.png" alt="View all visualizations"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Creating a visualization as a non-technical person&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--yxK6uML---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/sozakrvcqiiqtobnojwd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--yxK6uML---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/sozakrvcqiiqtobnojwd.png" alt="Create visualization"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Description
&lt;/h3&gt;

&lt;p&gt;The app submission enables non-technical and technical people to create stunning data visualizations using their JSON or CSV data or even raw data  objects in HTTP post requests via API. For non-technical people, they can upload their file using the app user interface screen. It can be tried out here: &lt;a href="https://vaas-wu4a4.ondigitalocean.app/#try"&gt;https://vaas-wu4a4.ondigitalocean.app/#try&lt;/a&gt; and users of the app can download their data visualizations as PNG images and use it how ever they see fit. &lt;/p&gt;

&lt;h3&gt;
  
  
  Link to Source Code
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://github.com/ChukwuEmekaAjah/vaas"&gt;https://github.com/ChukwuEmekaAjah/vaas&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Permissive License
&lt;/h3&gt;

&lt;p&gt;MIT License&lt;br&gt;
Link: &lt;a href="https://github.com/ChukwuEmekaAjah/vaas/blob/master/license.md"&gt;https://github.com/ChukwuEmekaAjah/vaas/blob/master/license.md&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Background
&lt;/h2&gt;

&lt;p&gt;The decision to build this particular solution in this contest was spurred by my love for data visualizations. I've always wanted to build a SaaS product that empowers non-developers/non-technical people to create data visualizations of different types with their data easily thereby making it easy for them to get insights from their data. They wouldn't need to know how to use Excel or program in any programming language to be able to create data visualization charts with their CSV or JSON data file. Also, the ability to choose different chart types such as line, pie or bar charts was considered in the capabilities to give to non-technical people since they are the most popular chart types.&lt;/p&gt;

&lt;p&gt;In addition to this, bearing in mind that the service can be extended to developers who do not want to go through the process of developing their own visualization service and want to outsource the process to a product, I was motivated to build the product to include developers as prospective customers of the service using a simple-to-use API.&lt;/p&gt;

&lt;h3&gt;
  
  
  How I built it
&lt;/h3&gt;

&lt;p&gt;In order to build this service, I knew that I needed a Platform-as-a-service product to outsource the handling of hosting and deployment infrastructure. Digital Ocean with its new App platform offering made the process easy to use. Digital ocean's app platform service was easy-to-use and has a competitive pricing structure with app performance insights that would help developers see their product health and status.&lt;/p&gt;

&lt;p&gt;The app is built using NodeJS/ExpressJS for the HTTP server and routing, MongoDB for storage, Redis for session storage and Puppeteer for server-side HTML page rendering. &lt;/p&gt;

&lt;p&gt;Also, I knew I needed a way to dynamically render data visualization pages for API users and with some Google searches on how I could do that, I got to learn of Puppeteer; the headless chrome engine that can be used on NodeJS servers to render HTML pages. I learnt how to use Puppeteer to dynamically launch browsers and now, I believe I can apply the knowledge learnt to other projects of mine. I also learnt how to deploy apps with Digital Ocean App Platform and it's now a tool in my toolbelt of PaaS providers.&lt;/p&gt;

&lt;p&gt;Somehow, I stumbled upon a roadblock in the process of the building the service on the App Platform; the dependencies needed to install Puppeteer on my App instances could not be installed and this led me to do some digging for which I eventually found this link: &lt;a href="https://www.digitalocean.com/community/questions/how-to-setup-puppeteer-in-nodejs-app"&gt;https://www.digitalocean.com/community/questions/how-to-setup-puppeteer-in-nodejs-app&lt;/a&gt; which talks about the fact that the Digital Ocean Engineering team is working to make it possible to use Puppeteer on an app instance. With this setback in mind, I had to extract the Puppeteer component into an external HTTP service so that I could move forward with the app and make it available for developers to consume the API. &lt;/p&gt;

&lt;h3&gt;
  
  
  Additional Resources/Info
&lt;/h3&gt;

&lt;p&gt;Digital ocean engineering team on work being done to make Puppeteer available&lt;br&gt;
&lt;a href="https://www.digitalocean.com/community/questions/how-to-setup-puppeteer-in-nodejs-app"&gt;https://www.digitalocean.com/community/questions/how-to-setup-puppeteer-in-nodejs-app&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Vaas App Postman API documentation&lt;br&gt;
&lt;a href="https://documenter.getpostman.com/view/9506038/TVzNHK6P"&gt;https://documenter.getpostman.com/view/9506038/TVzNHK6P&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Vaas App API documentation&lt;br&gt;
&lt;a href="https://vaasapp.co/docs"&gt;https://vaasapp.co/docs&lt;/a&gt;&lt;/p&gt;

</description>
      <category>dohackathon</category>
    </item>
    <item>
      <title>Data Visualization as a service using the Digital Ocean App Platform - API documentation</title>
      <dc:creator>Ajah Chukwuemeka</dc:creator>
      <pubDate>Mon, 04 Jan 2021 07:59:26 +0000</pubDate>
      <link>https://dev.to/ajahso4/data-visualization-as-a-service-using-the-digital-ocean-app-platform-api-documentation-10lf</link>
      <guid>https://dev.to/ajahso4/data-visualization-as-a-service-using-the-digital-ocean-app-platform-api-documentation-10lf</guid>
      <description>&lt;p&gt;Since a core part of my proposed submission is an API, it is important that I create a robust and concise documentation for how developers who want to create charts via API can go ahead with it. I have successfully created the first draft of the API documentation and I'm looking forward to your comments on the ease of use of the API. &lt;/p&gt;

&lt;p&gt;The API documentation can be found here: &lt;a href="https://vaasapp.co/docs"&gt;https://vaasapp.co/docs&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I would appreciate your feedback on the clarity of the API documentation and suggestions on how to go about improving it. Thank you.&lt;/p&gt;

&lt;p&gt;Also, in my previous article, I talked about how Puppeteer wasn't working on the app platform and how the Digital Ocean Engineering team is working on it, my response was to extract that core component of my submission to an external HTTP service and I've successfully implemented it. Now, you can seamlessly create data visualizations and extract the generated image via API without the app crashing. &lt;/p&gt;

&lt;p&gt;Thank you for reading. I'm looking forward to my final submission later this week and hopefully, my product submission would be a top contender for the grand prize and developers with non-developers can start paying for the service once we go out of the present beta testing phase that it is at the moment. &lt;/p&gt;

</description>
      <category>dohackathon</category>
      <category>node</category>
      <category>digitalocean</category>
      <category>hackathon</category>
    </item>
    <item>
      <title>Data visualization as a service on the Digital Ocean app platform - Roadblock</title>
      <dc:creator>Ajah Chukwuemeka</dc:creator>
      <pubDate>Sat, 02 Jan 2021 21:00:03 +0000</pubDate>
      <link>https://dev.to/ajahso4/data-visualization-as-a-service-on-the-digital-ocean-app-platform-roadblock-41n6</link>
      <guid>https://dev.to/ajahso4/data-visualization-as-a-service-on-the-digital-ocean-app-platform-roadblock-41n6</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--zA1Rdo0L--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/8dy5202u1z388obx8g3o.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--zA1Rdo0L--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/8dy5202u1z388obx8g3o.png" alt="Puppeteer failing"&gt;&lt;/a&gt;&lt;br&gt;
As part of my proposed solution to the Digital Ocean App Platform hackathon solution, I require Puppeteer for rendering graphs via API and downloading the graph as an image. It works seamlessly on my local machine and hopefully, it should work on the app platform. &lt;/p&gt;

&lt;p&gt;However, from the image above, puppeteer fails to launch with the errors above. I tried to look for a way to install the required dependencies all to no avail. I did some quick Google searches to find a solution to it without success. Finally, I found this link with information on the situation in the Digital Ocean community support platform here: &lt;a href="https://www.digitalocean.com/community/questions/how-to-setup-puppeteer-in-nodejs-app"&gt;https://www.digitalocean.com/community/questions/how-to-setup-puppeteer-in-nodejs-app&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Luckily, the problem is being worked on by the Digital Ocean engineering team as stated in the comment found in the link above.&lt;/p&gt;

&lt;p&gt;Nonetheless, in order to make sure that the API service is functional by the submission date for the hackathon, I've decided to extract and create the Puppeteer rendering service via an external HTTP service and return the rendered graph image to my App Platform service to store on the DB. &lt;/p&gt;

&lt;p&gt;In addition to this, I have updated the home page of my app to enable people to access and try the app functionality without having to go through the process of signing up and verifying their email. You can take a look here: &lt;a href="https://vaasapp.co/"&gt;https://vaasapp.co/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Also, I'm happy about the Digital Ocean App Platform insights page which gives insights into CPU and memory usage as well as bandwidth consumption which are necessary data for optimizing your app and checking its health status. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--MPU-TDeZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/hxyhi5vp20gnwfhmo1sn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--MPU-TDeZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/hxyhi5vp20gnwfhmo1sn.png" alt="Insights page"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Hopefully, I would be able to bootstrap the puppeteer rendering service soon and be ready to showcase the API by the submission date. &lt;/p&gt;

</description>
      <category>dohackathon</category>
      <category>puppeteer</category>
      <category>node</category>
      <category>digitalocean</category>
    </item>
    <item>
      <title>Data Visualization as a Service using Digital Ocean App Platform - Deployment process</title>
      <dc:creator>Ajah Chukwuemeka</dc:creator>
      <pubDate>Wed, 30 Dec 2020 11:36:20 +0000</pubDate>
      <link>https://dev.to/ajahso4/data-visualization-as-a-service-using-digital-ocean-app-platform-deployment-process-48g9</link>
      <guid>https://dev.to/ajahso4/data-visualization-as-a-service-using-digital-ocean-app-platform-deployment-process-48g9</guid>
      <description>&lt;p&gt;In preparation for the Digital Ocean hackathon leveraging the newly created app platform, I strongly believe that the ease of deployment is one of the selling points of the product and in this article I would be talking about how I deployed my app to the App Platform. This article would contain the step-by-step process as well as the roadblocks I encountered in the process. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--7zcCdZbN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/fv8l0zo28x07c2od9ee9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--7zcCdZbN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/fv8l0zo28x07c2od9ee9.png" alt="App Platform deployment page on the Digital Ocean Dashboard"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After I logged in to my dashboard and decided to create an app on the App platform, I was showed the screen above and I liked the fact that the user interface was easy to understand. Clicking on the Launch App button took me to the next screen:&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--_7IerfXC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/gsbe5e5c5xs158qwhfjj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--_7IerfXC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/gsbe5e5c5xs158qwhfjj.png" alt="Selecting a Github repository on the App Platform"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;On this screen, you are required to link your Github profile with Digital Ocean so that a seamless continuous integration and deployment process can be created for you. After linking my Github profile, I was able to select the repository I wanted Digital Ocean to access. The beautiful thing about it all is that you have the capability and luxury to select just a single repository you want to grant Digital Ocean access to without sharing your whole Github repository with them. Unto the next step I went. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--_3C33yFE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/oyadc1fyzz8xx4thz7h8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--_3C33yFE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/oyadc1fyzz8xx4thz7h8.png" alt="Creating app name and selecting GIT branch for deployment"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In this step, the app requires you to create a name for your app and select the GIT branch you want to continuously deploy. This is good because we could have multiple branches on our GIT repository. Selecting the branch that's the single source of truth is great for having your app function how you want it to be. Also, we are provided with the liberty to choose if we want to auto-deploy our app any time a push or merge is made to our selected branch. I like this feature. However, I would recommend that the developer puts in place testing strategies to make sure that the app is always good to go without breaking changes so it won't disrupt access to your app by your prospective users. Next step is selecting the infrastructure plan required for your app. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--sc27wiRI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/bsgm7g3gl5d4fqlmw11h.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--sc27wiRI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/bsgm7g3gl5d4fqlmw11h.png" alt="Selecting app plan"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;My app requires the NodeJS environment and Puppeteer to run effectively. Puppeteer is quite heavy and so I went with the 1GB RAM capacity to cater for the situations where I might be dynamically generating visualization images via the app API. The plans are quite flexible and I believe would suit diverse use cases based on your app needs. This was the final step in the app creation process after which you can now launch your app. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--vyJ_RNY0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/e018ifo5d7he7mwnkwss.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--vyJ_RNY0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/e018ifo5d7he7mwnkwss.png" alt="Launching your app"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I eventually was able to launch my app without success. The build was successful however the app didn't start. This is because some environmental variables needed to start the app weren't created on Digital Ocean already. I looked through the app dashboard to find where to add these environment variables and could not find any where to do so. I actually had my .do folder created with the deployment yaml file created in it but throughout the app creation process, it didn't ask me for my environment variables. So, this deployment strategy didn't work well for me even though the process was seamless and intuitive. I hope the product team can make adding/updating environment variables as easy as the deployment process. &lt;/p&gt;

&lt;p&gt;Nonetheless, I decided to try deployment with the Digital Ocean button in my repository:&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--YSfbh-Vu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/znair5gm5o6tzzdxckqc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--YSfbh-Vu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/znair5gm5o6tzzdxckqc.png" alt="Deploying using DO button on repo"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The reason I tried this option was to really understand the rationale why as part of the hackathon, it was recommended that we add the deploy to Digital Ocean button to our repo. The process was as follows:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--1yYyd3vX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/49o05yvygxkq047f1jw5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--1yYyd3vX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/49o05yvygxkq047f1jw5.png" alt="Setting environment variables"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It first asked me to set my environment variables values. I already set the environment variables that my app required in the app deployment template file. This process was straightforward and my gut feeling was that the app would deploy successfully this time around. &lt;/p&gt;

&lt;p&gt;After setting the environment variables and requesting that the app be launched, the build process started and as I waited patiently, I eventually got the message I wanted to see; my app had deployed successfully. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--7J3ipjoB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/t4ych952jvnvys43srpq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--7J3ipjoB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/t4ych952jvnvys43srpq.png" alt="Successful app deployment"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I was able to seamlessly deploy the app using the Deploy to Digital Ocean button. Now, I can go back to building my app and not bothering about the infrastructure needed to run it. &lt;/p&gt;

&lt;p&gt;On the app side of things, I've been able create the functionality to dynamically create data visualizations using Puppeteer rendering and data url extraction and storage. I hope to be able to make more progress on the app roadmap in the coming days with the ease of deployment and functionality that Digital Ocean Apps Platform provides. &lt;/p&gt;

</description>
      <category>dohackathon</category>
      <category>digitalocean</category>
      <category>node</category>
    </item>
    <item>
      <title>Data Visualization as a Service using Digital Ocean App Platform</title>
      <dc:creator>Ajah Chukwuemeka</dc:creator>
      <pubDate>Sun, 27 Dec 2020 20:17:12 +0000</pubDate>
      <link>https://dev.to/ajahso4/data-visualization-as-a-service-using-digital-ocean-app-platform-4ej4</link>
      <guid>https://dev.to/ajahso4/data-visualization-as-a-service-using-digital-ocean-app-platform-4ej4</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--PvTCrFVA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/t16ikj9biba92tzrlcz9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--PvTCrFVA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/t16ikj9biba92tzrlcz9.png" alt="Vaas App"&gt;&lt;/a&gt;&lt;br&gt;
The Digital Ocean App platform provides us with an opportunity to deploy our apps without worrying about the infrastructure required to make it available to consumers. The beauty and ease of deployment via Github pushes is great and I would love to be part of the hackathon creating products using this amazing platform. &lt;/p&gt;

&lt;p&gt;I would be contesting under the 'Built for business' category. The project I'm working on is a data visualization as a service product. It allows developers and non-developers to upload their JSON or CSV data and retrieve back a visualization of their choice. Non-developers would have the ability to utilize a user interface to upload their files and select the fields that would make up the X and Y axes as the case may be for the different kinds of supported chart types. They would have the ability to download this charts as images and use them in their presentations or reports or in whatever form they want to utilize the chart.&lt;/p&gt;

&lt;p&gt;However, developers would have an extra functionality of creating visualizations using an API that they can send data to with the accompanying fields they want to visualization and receive back either the visualization image or its raw data. &lt;/p&gt;

&lt;p&gt;Since it's a holiday season, my development pace has been quite slow but I believe that I've made good progress. You can find the repository here: (&lt;a href="https://github.com/ChukwuEmekaAjah/vaas"&gt;https://github.com/ChukwuEmekaAjah/vaas&lt;/a&gt;). I've been able to enable user registration, authentication and authorization within the app and non-developer users can now create visualizations and view their created visualizations. &lt;/p&gt;

&lt;p&gt;I hope to continue on this with the API component for developers and as well as subsequently add billing functionality when the product is due. &lt;/p&gt;

&lt;p&gt;For now, I'm working on the API component and I'm setting up my repository on Digital Ocean. Hopefully by the middle of the week, I would have these components up and running and by the end of the day, the app would have been deployed to Digital Ocean. &lt;/p&gt;

</description>
      <category>node</category>
      <category>dohackathon</category>
      <category>saas</category>
      <category>digitalocean</category>
    </item>
    <item>
      <title>How do you log NodeJS program state? Try Logpersist!</title>
      <dc:creator>Ajah Chukwuemeka</dc:creator>
      <pubDate>Tue, 26 Nov 2019 18:55:36 +0000</pubDate>
      <link>https://dev.to/ajahso4/how-do-you-log-nodejs-program-state-try-logpersist-1fkh</link>
      <guid>https://dev.to/ajahso4/how-do-you-log-nodejs-program-state-try-logpersist-1fkh</guid>
      <description>&lt;p&gt;Logpersist is a JavaScript logger library for error and log messages with provisions for console, file and remote logging of program status information. It also makes provision for grouping logs, assigning severity as well as triggering notifications based on severity levels. &lt;/p&gt;

&lt;h2&gt;
  
  
  Motivation
&lt;/h2&gt;

&lt;p&gt;Logpersist was built because I needed a persistent way to record and query error and log messages while my program is in a production environment and I believe other developers would have the same issues too. &lt;/p&gt;

&lt;h2&gt;
  
  
  What you get
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;The ability to persistently log messages to any of: console, file or remote API. &lt;/li&gt;
&lt;li&gt;Grouping of messages and assigning of severity levels&lt;/li&gt;
&lt;li&gt;Possibility of triggering notifications based on specified severity levels&lt;/li&gt;
&lt;li&gt;Recording of stack trace from exceptions thrown within the program&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How to use
&lt;/h2&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--save&lt;/span&gt; logpersist
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;





&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Logger&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;logpersist&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;sendGrid&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;sendgrid&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;configOptions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;destination&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;&lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;file&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;address&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;messages.log&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;group&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;basics&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;dev&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;notifications&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;1&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:[],&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;2&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:[],&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;3&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:[],&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;4&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:[],&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;5&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:[]&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="na"&gt;notificationService&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;sendGrid&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;consoleLogger&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;Logger&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;configOptions&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;consoleLogger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;User just signed up&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// logs the message to the file messages.log&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nb"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Failed to authenticate user&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;consoleLogger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// logs the error to the file messages.log&lt;/span&gt;

&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;logOptions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;destination&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;&lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;file&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;address&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;messages.log&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;group&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;basics&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;from&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;now&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="na"&gt;to&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;now&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="na"&gt;severity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;source&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;index.js&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nx"&gt;consoleLogger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getLogs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;logOptions&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// returns an array of message objects&lt;/span&gt;
&lt;span class="cm"&gt;/*
    [
        {
            source:String,
            message:String,
            time:Date,
            name:String,
            group:String,
            severity:Number,
            trace:String
        }
    ]
*/&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;You can create multiple logger objects and if an &lt;b&gt; option &lt;/b&gt; argument is not provided at instantiation time, it uses the default configuration which is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;configOptions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;destination&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;&lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;file&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;address&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;errors.log&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="na"&gt;group&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;general&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;dev&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;notifications&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;1&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:[],&lt;/span&gt;
            &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;2&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:[],&lt;/span&gt;
            &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;3&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:[],&lt;/span&gt;
            &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;4&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:[],&lt;/span&gt;
            &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;5&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:[]&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="c1"&gt;// notification keys are severity levels and the value is an array of email addresses of people to notify&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  API
&lt;/h2&gt;

&lt;p&gt;Methods on the logger object&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Logger.log()&lt;/li&gt;
&lt;li&gt;Logger.getLogs()&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Example usage for the API
&lt;/h2&gt;

&lt;p&gt;The log method can take a second options argument which can be used to specify any of the group, severity, name and destination of the log message. If any of the options list of properties is absent, the defaults from the Logger object are used and if the options argument is absent, the defaults from the logger object at instantiation time are used.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;fileLogger&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;Logger&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="nx"&gt;fileLogger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;User just signed in&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;findUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
            &lt;span class="nx"&gt;fileLogger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="na"&gt;group&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;userSearchErrors&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="na"&gt;severity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;user search&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="na"&gt;destination&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;&lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;file&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;address&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;usersearch.log&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="p"&gt;})&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;



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



&lt;p&gt;The getLogs method can take no argument wherein in uses the object instantiation configuration options to search for logs or it takes a single argument which can be a number (in this case it get logs based on the specified severity), a string (in this case it get logs based on their group name) or an object (in this case it gets the logs based on a set of retrieval options)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;    &lt;span class="nx"&gt;fileLogger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getLogs&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// returns an array of logged messages&lt;/span&gt;
    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;retrievalOptions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;destination&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;&lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;file&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;address&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;messages.log&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="na"&gt;source&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;index.js&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;severity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;group&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;userSearchErrors&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;from&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;now&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
        &lt;span class="na"&gt;to&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;2/2/2020&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nx"&gt;getTime&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nx"&gt;fileLogger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getLogs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;userSearchErrors&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;fileLogger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getLogs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;fileLogger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getLogs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;retrievalOptions&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  Contributing
&lt;/h2&gt;

&lt;p&gt;In case you have any ideas, features you would like to be included or any bug fixes, you can send a PR.&lt;/p&gt;

&lt;p&gt;(Requires Node v6 or above)&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Clone the repo
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/ChukwuEmekaAjah/logpersist.git
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;It was quite exciting building this project as I enjoyed every bit of the process and I hope we give it a spin in our next projects. I would appreciate some feedback and possible collaborations to make it better. &lt;/p&gt;

&lt;p&gt;Thanks for reading. Mucho gracias mi amigos.&lt;/p&gt;

</description>
      <category>logging</category>
      <category>node</category>
    </item>
    <item>
      <title>Beautiful-dom; a HTML parser built with TypeScript</title>
      <dc:creator>Ajah Chukwuemeka</dc:creator>
      <pubDate>Fri, 23 Aug 2019 16:41:46 +0000</pubDate>
      <link>https://dev.to/ajahso4/beautiful-dom-a-html-parser-built-with-typescript-26op</link>
      <guid>https://dev.to/ajahso4/beautiful-dom-a-html-parser-built-with-typescript-26op</guid>
      <description>&lt;h1&gt;Beautiful-dom&lt;/h1&gt;

&lt;p&gt;Beautiful-dom is a lightweight library that mirrors the capabilities of the HTML DOM API needed for parsing crawled HTML/XML pages. It models the methods and properties of HTML nodes that are relevant for extracting data from HTML nodes. It is written in TypeScript and can be used as a CommonJS library&lt;/p&gt;

&lt;h2&gt;
  
  
  What you get
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;The ability to parse HTML documents as if you were dealing with HTML documents in a live browser&lt;/li&gt;
&lt;li&gt;Fast queries that return essential data from HTML nodes&lt;/li&gt;
&lt;li&gt;In-place order of HTML nodes after searching and parsing.&lt;/li&gt;
&lt;li&gt;Complex queries with CSS selectors.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How to use
&lt;/h2&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--save&lt;/span&gt; beautiful-dom
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;





&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;BeautifulDom&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;beautiful-dom&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`
&amp;lt;p class="paragraph highlighted-text" &amp;gt;
  My name is &amp;lt;b&amp;gt; Ajah, C.S. &amp;lt;/b&amp;gt; and I am a &amp;lt;span class="work"&amp;gt; software developer &amp;lt;/span&amp;gt;
&amp;lt;/p&amp;gt;
&amp;lt;div class = "container" id="container" &amp;gt;
 &amp;lt;b&amp;gt; What is the name of this module &amp;lt;/b&amp;gt;
 &amp;lt;p&amp;gt; What is the name of this libray &amp;lt;/p&amp;gt;
 &amp;lt;a class="myWebsite" href="https://www.ajah.xyz" &amp;gt; My website &amp;lt;/a&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;form&amp;gt;
  &amp;lt;label for="name"&amp;gt; What's your name? &amp;lt;/label&amp;gt;
  &amp;lt;input type="text" id="name" name="name" /&amp;gt;
&amp;lt;/form&amp;gt;
`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;dom&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;BeautifulDom&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  API
&lt;/h2&gt;

&lt;p&gt;Methods on the document object.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;document.getElementsByTagName()&lt;/li&gt;
&lt;li&gt;document.getElementsByClassName()&lt;/li&gt;
&lt;li&gt;document.getElementsByName()&lt;/li&gt;
&lt;li&gt;document.getElementById()&lt;/li&gt;
&lt;li&gt;document.querySelectorAll()&lt;/li&gt;
&lt;li&gt;document.querySelector()&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Methods on the HTML node object&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;node.getElementsByClassName()&lt;/li&gt;
&lt;li&gt;node.getElementsByTagName()&lt;/li&gt;
&lt;li&gt;node.querySelector()&lt;/li&gt;
&lt;li&gt;node.querySelectorAll()&lt;/li&gt;
&lt;li&gt;node.getAttribute()&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Properties of the HTML node object&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;node.outerHTML&lt;/li&gt;
&lt;li&gt;node.innerHTML&lt;/li&gt;
&lt;li&gt;node.textContent&lt;/li&gt;
&lt;li&gt;node.innerText&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Their usage is as they are expected to be used in an actual HTML DOM with the desired method parameters.&lt;/p&gt;

&lt;h2&gt;
  
  
  Examples for document object
&lt;/h2&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;paragraphNodes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;dom&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getElementsByTagName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;p&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// returns a list of node objects with node name 'p'&lt;/span&gt;

&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;nodesWithSpecificClass&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;dom&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getElementsByClassName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;work&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// returns a list of node objects with class name 'work'&lt;/span&gt;

&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;nodeWithSpecificId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;dom&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;container&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// returns a node with id 'container'&lt;/span&gt;

&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;complexQueryNodes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;dom&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;querySelectorAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;p.paragraph b&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// returns a list of nodes that satisfy the complex query of CSS selectors&lt;/span&gt;

&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;nodesWithSpecificName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;dom&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getElementsByName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;name&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// returns a list of nodes with the specific 'name'&lt;/span&gt;

&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;linkNode&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;dom&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;a#myWebsite&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// returns a node object with with the CSS selector&lt;/span&gt;

&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;linkHref&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;linkNode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getAttribute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;href&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// returns the value of the attribute e.g 'https://www.ajah.xyz'&lt;/span&gt;

&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;linkInnerHTML&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;linkNode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;innerHTML&lt;/span&gt;
&lt;span class="c1"&gt;// returns the innerHTML of a node object e.g ' My website '&lt;/span&gt;

&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;linkTextContent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;linkNode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;textContent&lt;/span&gt; 
&lt;span class="c1"&gt;// returns the textContent of a node object e.g ' My website '&lt;/span&gt;

&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;linkInnerText&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;linkNode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;innerText&lt;/span&gt;
&lt;span class="c1"&gt;// returns the innerText of a node object e.g ' My website '&lt;/span&gt;

&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;linkOuterHTML&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;linkNode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;outerHTML&lt;/span&gt;
&lt;span class="c1"&gt;// returns the outerHTML of a node object i.e. '&amp;lt;a class="myWebsite" href="https://www.ajah.xyz" &amp;gt; My website &amp;lt;/a&amp;gt;'&lt;/span&gt;

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



&lt;h2&gt;
  
  
  Examples for a node object
&lt;/h2&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;paragraphNodes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;dom&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getElementsByTagName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;p&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// returns a list of node objects with node name 'p'&lt;/span&gt;

&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;nodesWithSpecificClass&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;paragraphNodes&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;getElementsByClassName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;work&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// returns a list of node objects inside the first paragraph node with class name 'work' &lt;/span&gt;


&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;complexQueryNodes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;paragraphNodes&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;querySelectorAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;span.work&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// returns a list of nodes in the paragraph node that satisfy the complex query of CSS selectors&lt;/span&gt;


&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;linkNode&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;dom&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;a#myWebsite&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// returns a node object with with the CSS selector&lt;/span&gt;

&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;linkHref&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;linkNode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getAttribute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;href&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// returns the value of the attribute e.g 'https://www.ajah.xyz'&lt;/span&gt;

&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;linkInnerHTML&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;linkNode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;innerHTML&lt;/span&gt;
&lt;span class="c1"&gt;// returns the innerHTML of a node object e.g ' My website '&lt;/span&gt;

&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;linkTextContent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;linkNode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;textContent&lt;/span&gt; 
&lt;span class="c1"&gt;// returns the textContent of a node object e.g ' My website '&lt;/span&gt;

&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;linkInnerText&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;linkNode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;innerText&lt;/span&gt;
&lt;span class="c1"&gt;// returns the innerText of a node object e.g ' My website '&lt;/span&gt;

&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;linkOuterHTML&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;linkNode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;outerHTML&lt;/span&gt;
&lt;span class="c1"&gt;// returns the outerHTML of a node object i.e. '&amp;lt;a class="myWebsite" href="https://www.ajah.xyz" &amp;gt; My website &amp;lt;/a&amp;gt;'&lt;/span&gt;

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



&lt;h2&gt;
  
  
  Contributing
&lt;/h2&gt;

&lt;p&gt;In case you have any ideas, features you would like to be included or any bug fixes, you can send a PR.&lt;/p&gt;

&lt;p&gt;(Requires Node v6 or above)&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Clone the repo
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/ChukwuEmekaAjah/beautiful-dom.git
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;It was an exciting building this NodeJS module using TypeScript as I recently learned how to use TypeScript and what better way to practice and experiment with new knowledge? &lt;/p&gt;

&lt;p&gt;I would appreciate comments and contributions to the project as well as the opening of issues as regards edge cases that I may not have fathomed as well as errors encountered while you use the module. &lt;/p&gt;

</description>
      <category>typescript</category>
      <category>node</category>
      <category>dom</category>
    </item>
    <item>
      <title>Utilizing machine capability in NodeJS using the cluster module 1</title>
      <dc:creator>Ajah Chukwuemeka</dc:creator>
      <pubDate>Tue, 14 May 2019 15:01:30 +0000</pubDate>
      <link>https://dev.to/ajahso4/utilizing-machine-capability-in-nodejs-using-the-cluster-module-1-3cpj</link>
      <guid>https://dev.to/ajahso4/utilizing-machine-capability-in-nodejs-using-the-cluster-module-1-3cpj</guid>
      <description>&lt;p&gt;Humans naturally want to live to their full potential. We always believe that we have untapped potential welled within us with the conviction that our genes and nurturing has equipped us enough to be able to live above subpar lives. In building apps with NodeJS, the machines we utilize have different capabilities bearing in mind the number of cores possessed by the machine as well as the power of individual cores.&lt;/p&gt;

&lt;p&gt;A single instance of NodeJS doesn't utilize all the machine capabilities since it is single-threaded and you can't afford to let your app suffer from overload when it has dormant server resources that can be utilized to bear the weight of client-server communication. In light of this, NodeJS makes provision for the the &lt;strong&gt;cluster&lt;/strong&gt; module which helps fork multiple processes of a NodeJS app. For a web server, the cluster module helps spun multiple child processes that share a port with their parent process. Ehhh, not like a port can be shared by web servers. Technically, the parent module receives requests and efficiently distributes it to the client processes (just like the great Xavi and Iniesta did for Messi in their heydays). The cluster module is particularly useful for networking applications but it can still shine in other processes where we want to carryout CPU-intensive tasks across multiple workers.&lt;/p&gt;

&lt;p&gt;According to the NodeJS official documentation, the child processes (worker processes) are spawned using the child_process.fork() method, so that they can communicate with the parent via IPC (Inter-Process Communication) and pass server handles back and forth.&lt;/p&gt;

&lt;p&gt;In distributing incoming connections to the child processes, there are two methods adopted by the cluster module and they are platform related. The first one (and default on all platforms except Windows), is the round-robin approach (turn-based allocation without priority), where the master process listens on a port, accepts new connections and distributes them across the workers in a round-robin fashion, with some built-in smarts to avoid overloading a worker process. The second approach is where the master process creates the listen socket and sends it to interested workers. The workers then accept incoming connections directly.&lt;/p&gt;

&lt;p&gt;The workers are all separate processes implying that they can be killed or re-spawned depending on program needs without affecting other workers. As long as there are still hale and hearty workers, the master process would still be accepting connections. NodeJS doesn't bear the responsibility of managing the number of available workers and so, it is the application's responsibility to manage the worker pool based on its own needs.&lt;/p&gt;

&lt;p&gt;Now, lets dive into a use case of the cluster module. Remember we said the cluster module shines bright in networking applications? We would use a networking application for our example. We would prop up an http server and distribute requests across child processes based on the number of CPU cores our operating machine has.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const cluster = require('cluster');
const http = require('http');
const number_of_cpus = require('os').cpus().length;

if(cluster.isMaster){
    console.log(`Master with id ${process.pid} is running`);

    // setting up the workers
    for (let i = 0; i &amp;lt; number_of_cpus; i++){
        cluster.fork();
    }

    cluster.on('exit',(worker, code, signal) =&amp;gt; {
        console.log(` Worker with process id ${worker.process.pid} died`);
    });
}
else{
    http.createServer((req,res) =&amp;gt; {
        res.writeHead(200);
        res.end(`Hello world from ${process.pid}`)
    }).listen(80);
    console.log(`Worker with ${process.pid} started`)

}

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



&lt;p&gt;Since NodeJS is event-driven, both the master process and the worker processes listen for events and act accordingly (that's if there is provision for handling the events in the code.) We would talk about the events, methods and properties on both sides (worker and master) associated with the cluster module in the follow-up article on this topic. Thanks for your time.&lt;/p&gt;

</description>
      <category>node</category>
      <category>optimization</category>
      <category>scalability</category>
    </item>
    <item>
      <title>Timers and schedulers in Javascript</title>
      <dc:creator>Ajah Chukwuemeka</dc:creator>
      <pubDate>Mon, 06 May 2019 13:51:51 +0000</pubDate>
      <link>https://dev.to/ajahso4/timers-and-schedulers-in-javascript-2o7a</link>
      <guid>https://dev.to/ajahso4/timers-and-schedulers-in-javascript-2o7a</guid>
      <description>&lt;p&gt;In building programs that would eventually be integrated into our softwares, sometimes, we need to defer the execution of some part of our program with respect to time. Also, we might want to carry out some routine tasks at specific intervals from a given benchmark. In the bid to do this, Javascript developers mostly leverage on the specification of any of the setTimeout or setInterval global functions so as to achieve their aim. In this article, we would do a deep dive as well as experimentation on the use of these timer functions.&lt;/p&gt;

&lt;p&gt;First, we would start with the setTimeout function. It is used to schedule a task that would run only once after the event cycle has elapsed after the specified delay. The setTimeout function accepts a function or string as its first argument, a delay time in milliseconds as its second argument and an optional third or more arguments which are supposed to act as the function parameters. However, when the first argument to the setTimeout function is a string, it wraps it into an eval function internally and executes &lt;strong&gt;(this throws a TypeError in NodeJS runtime)&lt;/strong&gt; and when the delay argument is not provided, it assumes that the delay is 0ms. The return value of a setTimeout function is a reference which can be used to clear the timeout before or after it has executed so as to remove it from the event loop.&lt;/p&gt;

&lt;p&gt;Typical usage of the setTimeout function&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;let timeoutId = setTimeout(function(){
console.log(`Isn't Javascript a cute language?`)
}, 2000)

let timeoutId = setTimeout(`console.log('How are you')`)

const greeter = (name, time_of_day) =&amp;gt; {
console.log(`Good ${time_of_day}, ${name}`)
}

// then we call the setTimeout function with the greeter function as an argument
let timeoutId = setTimeout(greeter,2000,'Emeka','afternoon')
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;setTimeout function does have an anti-matter function which is responsible for cancelling and clearing the timeout function from the event loop. This function utilizes the return reference value of the setTimeout function so as to know which timeout function to cancel. It is used as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;let timeoutId = setTimeout(function(name){
console.log(`How are you today ${name}?`)
}, 2000, 'Emeka')

clearTimeout(timeoutId)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Since we have exhaustively talked about the use of the setTimeout function, we can now talk about the setInterval function. Its usage is the same as that of the setTimeout function. However, the beauty of it is that it performs an action after every specified delay time in the function call. More like repeatedly performs an action after the specified delay time in milliseconds. This function is good for time repetitive tasks that are time-bound.&lt;/p&gt;

&lt;p&gt;Typical usage of the setInterval function&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;let intervalId = setInterval(function(){
console.log(`Isn't Javascript a cute language?`)
}, 2000)

let intervalId = setInterval(`console.log('How are you')`)

const greeter = (name, time_of_day) =&amp;gt; {
console.log(`Good ${time_of_day}, ${name}`)
}
// then we call the setInterval function with the greeter function as an argument
let intervalId = setInterval(greeter,2000,'Emeka','afternoon')
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The first call to setInterval executes its assigned function every 2s whereas the second call executes the assigned function like a loop without any delay.&lt;/p&gt;

&lt;p&gt;However, as there is a clearTimeout function for canceling setTimeout functions and removing them from the event loop, there is a clearInterval function for removing setInterval functions also. It utilizes the return value of the setInterval call which serves as a reference parameter for it. It is used as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;let intervalId = setInterval(function(name){
console.log(`How are you today ${name}?`)
}, 2000, 'Emeka')

clearInterval(intervalId)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;In addition to this, in NodeJS there is also another scheduler function called setImmediate which is executed at the end of the turn of the NodeJS event loop. It works like setTimeout function with a 0ms delay value. It also has the clearImmediate anti-matter for cancelling it and garbage collection.It is used thus:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;let immediate = setImmediate(function(name){
console.log(`How are you today ${name}?`)
}, 'Emeka')

clearImmediate(immediate)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;In NodeJS, the above timer functions do have extra methods that can only be accessed within the NodeJS runtime. These are the ref, hasRef, refresh (for setTimeout only) and unRef methods that can be used with the return value of the functions.&lt;/p&gt;

&lt;p&gt;To read more about timers and schedulers in Javascript, please follow the links below. They helped me a bunch. Thank you for your time.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://alligator.io/js/settimeout-setinterval/"&gt;Scheduling Tasks in JavaScript Using setTimeout &amp;amp; setInterval&lt;/a&gt;&lt;br&gt;
&lt;a href="https://javascript.info/settimeout-setinterval"&gt;Scheduling: setTimeout and setInterval&lt;/a&gt;&lt;br&gt;
&lt;a href="https://nodejs.org/api/timers.html#timers_class_immediate"&gt;Timers | NodeJS&lt;/a&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>node</category>
    </item>
    <item>
      <title>Eventish: A wrapper around NodeJS raw events API</title>
      <dc:creator>Ajah Chukwuemeka</dc:creator>
      <pubDate>Sun, 03 Jun 2018 21:45:45 +0000</pubDate>
      <link>https://dev.to/ajahso4/eventish-a-wrapper-around-nodejs-raw-events-api-419k</link>
      <guid>https://dev.to/ajahso4/eventish-a-wrapper-around-nodejs-raw-events-api-419k</guid>
      <description>&lt;p&gt;Hello friends! I built a lightweight library to put to practice what I learnt from the NodeJS events API. I require your inputs on the library design, interface, possible uses and every other help possible. &lt;/p&gt;

&lt;h2&gt;
  
  
  Link to the code is at
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/ChukwuEmekaAjah/eventish"&gt;Eventish&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  NPM module is at
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://www.npmjs.com/package/eventish"&gt;Eventish&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;By the way, this work was inspired by the work done by my friend &lt;a href="https://dev.to/shalvah"&gt;Adebayoh Shalvah&lt;/a&gt; with his beautiful library &lt;a href="https://github.com/shalvah/burns"&gt;burns&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Thanks for your most anticipated response.&lt;/p&gt;

</description>
      <category>showdev</category>
      <category>help</category>
      <category>node</category>
    </item>
    <item>
      <title>A real-time developers' board to keep up with tech articles on the web.</title>
      <dc:creator>Ajah Chukwuemeka</dc:creator>
      <pubDate>Fri, 25 May 2018 00:38:53 +0000</pubDate>
      <link>https://dev.to/ajahso4/a-real-time-developers-board-to-keep-up-with-tech-articles-on-the-web-39fn</link>
      <guid>https://dev.to/ajahso4/a-real-time-developers-board-to-keep-up-with-tech-articles-on-the-web-39fn</guid>
      <description>&lt;h1&gt;
  
  
  What I built
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fupxkyrjkz58s79aqwn55.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fupxkyrjkz58s79aqwn55.PNG" alt="front page of app"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A platform where developers can post articles they find useful from around the web and others can see these articles and as well glean the available knowledge. It is updated in real-time courtesy of the Pusher channels API.&lt;/p&gt;

&lt;h2&gt;
  
  
  Demo Link
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://pusher-comp-dev.herokuapp.com" rel="noopener noreferrer"&gt;https://pusher-comp-dev.herokuapp.com&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Link to Code
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/ChukwuEmekaAjah/pusher" rel="noopener noreferrer"&gt;https://github.com/ChukwuEmekaAjah/pusher&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  How I built it (what's the stack? did I run into issues or discover something new along the way?)
&lt;/h1&gt;

&lt;p&gt;I used NodeJS/ExpressJS for the back-end stack. jQuery and materializecss was used for the front-end code. Pusher channels API for both client and server were also included.&lt;br&gt;
I hosted the app on Heroku.&lt;/p&gt;

&lt;h1&gt;
  
  
  Additional Resources/Info
&lt;/h1&gt;

&lt;p&gt;The app has features that update in real-time courtesy of the Pusher channels API. These features are the newly added channels, articles, articles liked, articles visited. This hack provides a framework that would allow users of the platform to see new as well as trending articles in real time.&lt;br&gt;
The beauty of real-time communication and the developer board created would be of very much importance to fellow developers in their journey to becoming master software craftsmen leveraging the scattered publicly available knowledge on the world-wide web.&lt;/p&gt;

</description>
      <category>pushercontest</category>
    </item>
    <item>
      <title>Scoped closures</title>
      <dc:creator>Ajah Chukwuemeka</dc:creator>
      <pubDate>Mon, 23 Apr 2018 10:32:15 +0000</pubDate>
      <link>https://dev.to/ajahso4/scoped-closures-dde</link>
      <guid>https://dev.to/ajahso4/scoped-closures-dde</guid>
      <description>&lt;p&gt;JavaScript is an easy-to-grasp cool language with many quirks that justify the reason why some authors wrote books on the good parts of the language. In all these, the coolness of the language is that you can quickly become productive with it without understanding the intricacies of the language or even giving a f*** at the quirks (probably until it bites you). &lt;/p&gt;

&lt;p&gt;However, in this article, I intend to help fellow JavaScript developers in understanding the concept of scope and closures. Like I read in the: You Don't Know JavaScript series, a proper understanding of these two concepts would improve your grasp of the language and so for that reason, I would try to give my 2 cents in order to show off my understanding of these concepts and most importantly, help people like me who are seeking for true understanding of the language.&lt;/p&gt;

&lt;p&gt;First, we would start with the concept of &lt;b&gt;scope&lt;/b&gt;. Scope to me can be viewed like an organisation with different levels of hierarchy. Imagine an organisation with an organisation-wide document access system. At the different levels, there are certain levels of access to documents and managers can view documents created or worked on by their subordinates but the subordinates cannot view the documents created by their managers. Coming back to JavaScript, functions inside other functions have access to the variables created by their parent functions in the outer scope but the parent functions don't have access to variables created in the inner functions. Let's look at an example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;   &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;outerFunction&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
                            &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                            &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;y&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                            &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;adder&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="p"&gt;(){&lt;/span&gt;
                                &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                                &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                            &lt;span class="p"&gt;}&lt;/span&gt;
                            &lt;span class="nx"&gt;adder&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
                            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                       &lt;span class="p"&gt;}&lt;/span&gt;
   &lt;span class="nx"&gt;outerFunction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// we see 5 in the console and Uncaught ReferenceError: z is             &lt;/span&gt;
                     &lt;span class="c1"&gt;//  not defined with the stack trace&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;As we can see, the line workers in an organization don't have access to top-level information being discussed at the higher levels unless they are explicitly told of it and in our case, that would be through an explicit return statement from the adder function and corresponding assignment of it to a variable z. So if we try to replicate a situation where line workers are given a glimpse of top-level management decisions, the code would look like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;   &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;outerFunction&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
                            &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                            &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;y&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                            &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;adder&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="p"&gt;(){&lt;/span&gt;
                                &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                                &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                                &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                            &lt;span class="p"&gt;}&lt;/span&gt;
                            &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;adder&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
                            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                       &lt;span class="p"&gt;}&lt;/span&gt;
   &lt;span class="nx"&gt;outerFunction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// we see 5 twice in the console twice from the log and      &lt;/span&gt;
                      &lt;span class="c1"&gt;// return statements respectively.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, let's talk about the concept of &lt;b&gt;closures&lt;/b&gt;. Closures are cool in the sense that it can be related to the fact that we still have access to information even after it has been removed from the public space or the job of the original information generator is done. Let's go back to our organisational structure analogy. When the line workers generate data from the field, clean it up and probably make them presentable and pass it down to their managers, the job of the line workers may be done but the manager still has access to the document created and can interpret it the way he wants to. Going back to JavaScript, closures provide an avenue for nested functions to still have access to data generated from their parent function even after the parent function has completed its call stack. Although this works only if the nested function is returned. Let's take a look at some code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;   &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;lineFunction&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
                            &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                            &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;y&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                            &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;adder&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="p"&gt;(){&lt;/span&gt;
                                &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                                &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                            &lt;span class="p"&gt;}&lt;/span&gt;
                            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;adder&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                       &lt;span class="p"&gt;}&lt;/span&gt;
   &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;dataHandover&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;lineFunction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// this instantiates the line function&lt;/span&gt;
   &lt;span class="nx"&gt;dataHandover&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="c1"&gt;// this returns 5 on the console. Notice it still had access to &lt;/span&gt;
                   &lt;span class="c1"&gt;// the x and y arguments even after the lineFunction is called&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;The beauty of all these for both &lt;b&gt;scopes&lt;/b&gt; and &lt;b&gt;closures&lt;/b&gt; is that they can be nested to any level that we deem fit although there is need for control so as to retain understanding. Remember that code is mostly read than it is written.&lt;/p&gt;

&lt;p&gt;Nevertheless, some people would ask: what are the applications of these concepts? I can get by without them. Scopes are useful when we want to implement sub-routines in main functions that would perform some trivial task whereas closures are good for implementing a module pattern for our code. Closures help in implementing the concept of private and public functions.&lt;/p&gt;

&lt;p&gt;I hope to see more scoped closures from you all. Thanks for reading.&lt;/p&gt;

</description>
      <category>javascript</category>
    </item>
  </channel>
</rss>
