<?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: Leyang Yu</title>
    <description>The latest articles on DEV Community by Leyang Yu (@lyu4321).</description>
    <link>https://dev.to/lyu4321</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%2F701108%2F6a548f42-2baa-4872-bf86-5c946f669006.png</url>
      <title>DEV Community: Leyang Yu</title>
      <link>https://dev.to/lyu4321</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/lyu4321"/>
    <language>en</language>
    <item>
      <title>Finishing Up Release 0.4</title>
      <dc:creator>Leyang Yu</dc:creator>
      <pubDate>Fri, 10 Dec 2021 22:20:32 +0000</pubDate>
      <link>https://dev.to/lyu4321/finishing-up-release-04-2123</link>
      <guid>https://dev.to/lyu4321/finishing-up-release-04-2123</guid>
      <description>&lt;h2&gt;
  
  
  Intro
&lt;/h2&gt;

&lt;p&gt;Hello! This is my last blog post for OSD600 and this week, I worked on two pull requests for my last assignment. If you've read my previous &lt;a href="https://dev.to/lyu4321/open-source-part-13-finding-issues-43gn"&gt;blog post&lt;/a&gt;, I've been working on two issues for Seneca's IPC144 course website &lt;a href="https://github.com/Seneca-ICTOER/IPC144"&gt;repository&lt;/a&gt;. The first issue, which I blogged about &lt;a href="https://dev.to/lyu4321/converting-raster-images-to-svgs-26ap"&gt;last week&lt;/a&gt;, involves finding a way to convert raster images to SVGs. The second issue, which I worked on this week, involves updating the website style to work for both light and dark modes. This blog post will summarize the pull requests I created for both issues. &lt;/p&gt;

&lt;h2&gt;
  
  
  Issue 1
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/Seneca-ICTOER/IPC144/pull/147"&gt;PR&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This &lt;a href="https://github.com/Seneca-ICTOER/IPC144/issues/120"&gt;issue&lt;/a&gt; was about experimenting with &lt;a href="https://svgco.de/"&gt;SVGCode&lt;/a&gt; to see if it could be used to convert raster images to SVGs. I blogged about this process in my last &lt;a href="https://dev.to/lyu4321/converting-raster-images-to-svgs-26ap"&gt;post&lt;/a&gt;. I created a pull request which demoed the results of my research by including several SVGs that I created using SVGCode, Adobe Illustrator and Inkscape. Overall, I think that Inkscape produced the most consistent results for coloured and black and white images compared to other tools I tried, which I mentioned in my PR. &lt;/p&gt;

&lt;h2&gt;
  
  
  Issue 2
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/Seneca-ICTOER/IPC144/pull/145"&gt;PR&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For this &lt;a href="https://github.com/Seneca-ICTOER/IPC144/issues/112"&gt;issue&lt;/a&gt;, I had to come up with a strategy for styling that would work in both light and dark modes. For example, some table cells in dark mode originally had white text on a yellow background, which is very hard to see:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--TDPCXSnf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/w0vjri3pgea830xrq92m.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--TDPCXSnf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/w0vjri3pgea830xrq92m.png" alt="Original Dark Mode" width="880" height="585"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I went through the pages of the site and other than highlighting and image backgrounds, I didn't notice any major issues that appeared due to using a specific mode.&lt;/p&gt;

&lt;p&gt;For the highlighting issue, I decided to stick with the yellow background in light mode and for dark mode, I decided to use a different colour since the yellow seemed too bright on a dark background:&lt;/p&gt;

&lt;p&gt;Light Mode&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--qfn4GUCv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5shcf2m2gt5l7vb3928w.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--qfn4GUCv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5shcf2m2gt5l7vb3928w.png" alt="New Light Mode" width="880" height="434"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Dark Mode &lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--bHein7ZR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6jr3ig8kl4zaql41k18h.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--bHein7ZR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6jr3ig8kl4zaql41k18h.png" alt="New Dark Mode" width="880" height="429"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I did this by creating a class called highlight and applying different styles depending on the &lt;a href="https://docusaurus.io/docs/styling-layout#dark-mode"&gt;mode&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.highlight&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;background-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;rgb&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;255&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;255&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;224&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="cp"&gt;!important&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nt"&gt;html&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nt"&gt;data-theme&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;'dark'&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="nc"&gt;.highlight&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;background-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;rgb&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;72&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;77&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;91&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="cp"&gt;!important&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;In addition I added a white background to all images for both modes, since some images looked a bit weird on a black background:&lt;/p&gt;

&lt;p&gt;Before &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--WqCipqgQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bg8zhq70mp6by3ttoql6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--WqCipqgQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bg8zhq70mp6by3ttoql6.png" alt="Image Before" width="880" height="251"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--KXoJ-9pz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6kras5hf63gghuyfhc5j.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--KXoJ-9pz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6kras5hf63gghuyfhc5j.png" alt="Image After" width="880" height="250"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I did this by adding a white background when the site is in dark mode:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nt"&gt;html&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nt"&gt;data-theme&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;'dark'&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="nt"&gt;p&lt;/span&gt; &lt;span class="nt"&gt;img&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;background-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;rgb&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;255&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;255&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;255&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;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;As of this blog post (Dec 10), I haven't received any reviews on my pull requests from the maintainers. For the SVG issue, I don't expect my changes to get merged as the issue was just to experiment with &lt;a href="https://svgco.de/"&gt;SVGCode&lt;/a&gt; to see if this tool could be used in the project and the SVGs I included in the pull request were just samples of what I came up with based on my research. &lt;/p&gt;

&lt;p&gt;When starting off this assignment, my goal was to work on open-ended front-end issues that allowed me to be more creative. For my PRs, I was able to experiment with a variety of image editing tools, some which I've used before, such as Inkscape, and others which were new to me, such as SVGCode and Adobe Illustrator. I think this will be useful when I work on future projects involving different image formats. I was also able to experiment with different styles for light and dark modes. Overall, I think this was a great end to a wonderful course and I hope to continue contributing to the open source community even after completing OSD600. Thanks for reading! &lt;/p&gt;

</description>
      <category>opensource</category>
    </item>
    <item>
      <title>Converting Raster Images to SVGs</title>
      <dc:creator>Leyang Yu</dc:creator>
      <pubDate>Sat, 04 Dec 2021 01:11:54 +0000</pubDate>
      <link>https://dev.to/lyu4321/converting-raster-images-to-svgs-26ap</link>
      <guid>https://dev.to/lyu4321/converting-raster-images-to-svgs-26ap</guid>
      <description>&lt;h2&gt;
  
  
  Intro
&lt;/h2&gt;

&lt;p&gt;In a &lt;a href="https://dev.to/lyu4321/open-source-part-13-finding-issues-43gn"&gt;previous post&lt;/a&gt;, I mentioned working on an &lt;a href="https://github.com/Seneca-ICTOER/IPC144/issues/120"&gt;issue&lt;/a&gt; for converting raster images to SVGs. This week, I did some research on the tool recommended in the issue, &lt;a href="https://svgco.de/"&gt;SVGCode&lt;/a&gt;, as well as other popular tools and in this post I will be discussing some of what I learned after trying them out. For the tools that I tried, I wanted to find something that is free and easy to use, while still being able to create high quality SVGs, as there are a lot of images to convert. (Disclaimer: I'm pretty new to working with images and image editing software so I'm probably not using all the right terminology here, but I'm trying to learn!)&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://svgco.de/"&gt;SVGCode&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--jTuSMJIZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3l3xrgwc0bu9kr36qfyp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--jTuSMJIZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3l3xrgwc0bu9kr36qfyp.png" alt="SVGCode" width="880" height="461"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After watching the &lt;a href="https://www.youtube.com/watch?v=kcvfyQh6J-0&amp;amp;ab_channel=GoogleChromeDevelopers"&gt;video tutorial&lt;/a&gt; and testing out the different settings, this is what I could come up with for one image. It looks decent here, but upon zooming in:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--40cQRLFt--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/aj5s9b45rm7k7tvdfaep.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--40cQRLFt--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/aj5s9b45rm7k7tvdfaep.png" alt="SVGCode Zoom" width="439" height="249"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can see that the outlines don't look great. I tried to de-speckle the image in order to create smoother outlines, but this left a lot of white space that I tried to fill using other methods such as by increasing stroke width, but the result wasn't much better. &lt;/p&gt;

&lt;p&gt;Although I think this tool is great considering it's free and very easy for anyone to learn and use, I decided to try out a few others to compare and see if I could get better results. &lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://www.adobe.com/ca/products/illustrator.html"&gt;Adobe Illustrator&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Another tool I tried was Adobe Illustrator, which luckily I have access to for free through my school!&lt;/p&gt;

&lt;p&gt;Personally, I liked the results using Adobe Illustrator and it was surprisingly easy to use as well. All you have to do after selecting an image is click on "Image Trace" in the toolbar and choose a preset.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--BRg3SubG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/c5zl8eirw2pbt1ecfpia.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--BRg3SubG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/c5zl8eirw2pbt1ecfpia.png" alt="Image Trace" width="711" height="379"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--WbNjsQme--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ij748jy1wyr5w6lwzof4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--WbNjsQme--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ij748jy1wyr5w6lwzof4.png" alt="Adobe Illustrator" width="880" height="414"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For this particular image, I found that "High Fidelity Photo" produced the closest result to the original image, but depending on your image, other presets may be more suitable.  &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--qtr381oz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dwafrp0bcuj558itzjl4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--qtr381oz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dwafrp0bcuj558itzjl4.png" alt="Adobe Illustrator Zoom" width="725" height="425"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here is an example of the image zoomed in, which although is not perfect, seems to be much cleaner compared to the image created through SVGCode. &lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://inkscape.org/"&gt;Inkscape&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;I also tried using Inkscape, which I had a bit of experience working with before in a previous project, where I modified an SVG logo. This tool was pretty easy to use as well. From the toolbar, you can click on "Path" and select "Trace Bitmap":&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--RaS2cGm---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/uxsa09lrjb1bkt13v838.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--RaS2cGm---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/uxsa09lrjb1bkt13v838.png" alt="Trace Bitmap" width="674" height="269"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After doing so, you should see this box appear, which allows you to customize the image that you wish to convert:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--X4YWEgl6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6pd6r7nn9nthe3oe4hxr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--X4YWEgl6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6pd6r7nn9nthe3oe4hxr.png" alt="Trace Bitmap 2" width="627" height="564"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For this image, there are 8 colours so I chose to do 8 scans and you can see the result below:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--GUcRZM0h--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/d7mmuemsuwuvwt3ktxey.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--GUcRZM0h--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/d7mmuemsuwuvwt3ktxey.png" alt="Inkscape" width="880" height="1035"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The top image is the original whereas the bottom image is the converted vector. However, upon zooming in, the SVG doesn't look that great:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--lDOCjk77--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/yp1nuiopflh9h32cdf3l.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--lDOCjk77--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/yp1nuiopflh9h32cdf3l.png" alt="Inkscape Zoom" width="880" height="614"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://vectormagic.com/"&gt;Vector Magic&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Vector Magic is a free online image conversion tool that I found. I think it's great because, like SVGCode, you don't need to download anything and you can edit the image right in your browser. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--y6ixA7e7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/21rr3kuy15grwig0xzyw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--y6ixA7e7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/21rr3kuy15grwig0xzyw.png" alt="Vector Magic" width="880" height="289"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--h9IfV-Tp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/c5okt7l141hlvc2rkpsr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--h9IfV-Tp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/c5okt7l141hlvc2rkpsr.png" alt="Vector Magic Zoom" width="845" height="483"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here are some images of the results. For a free program, I think the results are pretty decent but it's not as customizable as Illustrator, for example.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Overall, I learned a lot about different image conversion tools and hope you did as well after reading this blog post. Next week, I'll be creating a pull request with my different findings and suggestions and I'll be blogging about this as well. Thanks for reading!&lt;/p&gt;

</description>
      <category>opensource</category>
    </item>
    <item>
      <title>Publishing My First NPM Package</title>
      <dc:creator>Leyang Yu</dc:creator>
      <pubDate>Sat, 27 Nov 2021 03:25:05 +0000</pubDate>
      <link>https://dev.to/lyu4321/publishing-my-first-npm-package-5g7e</link>
      <guid>https://dev.to/lyu4321/publishing-my-first-npm-package-5g7e</guid>
      <description>&lt;h2&gt;
  
  
  Intro
&lt;/h2&gt;

&lt;p&gt;I published my first package, &lt;a href="https://www.npmjs.com/package/jellybean"&gt;jellybean&lt;/a&gt;, to &lt;a href="https://docs.npmjs.com/creating-and-publishing-unscoped-public-packages"&gt;npm&lt;/a&gt;! I actually published the package back when I first created the repository in September, just to experiment. However, it didn't work back then and I kind of forgot about it after that. This week, I fixed up the issues I was having and now it works. 😊 In this post, I'll be explaining the process of how I published the package and fixed the issues I previously encountered. &lt;/p&gt;

&lt;h2&gt;
  
  
  Preparing a Project to be Published
&lt;/h2&gt;

&lt;p&gt;I decided to publish my program to &lt;a href="https://docs.npmjs.com/creating-and-publishing-unscoped-public-packages"&gt;npm&lt;/a&gt; since it's the most common package manager for JavaScript programs. There are a few steps I followed in order to prepare the program to be published. First, in the package.json file, I added main and bin parameters. In addition, you need to have name and version parameters as well. For example, here is a snippet from my package.json file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"jellybean"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"1.0.10"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"description"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"From one small program, you can create an entire website. Jellybean is a static site generator created in Node.js that lets you easily convert your text/markdown files into HTML."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"main"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"src/index.js"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"bin"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"jellybean"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"src/index.js"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Name and version are pretty self-explanatory, but main specifies the main entry point into the program and bin specifies the command to run the associated executable file. In this case, when a user runs the command "jellybean" after installing the package, the file "src/index.js" will be executed. In addition, each time I published to npm, I incremented the &lt;a href="https://docs.npmjs.com/about-semantic-versioning#incrementing-semantic-versions-in-published-packages"&gt;version&lt;/a&gt; and if you forget to do so, you will receive an error message.&lt;/p&gt;

&lt;p&gt;In addition, I added the line:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#!/usr/bin/env node
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To the top of the file to be executed ("src/index.js" in this case), which specifies that the program should be run in a node environment.&lt;/p&gt;

&lt;h2&gt;
  
  
  Testing the Project
&lt;/h2&gt;

&lt;p&gt;Before publishing to npm, I tested the program by running:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;From within the same directory as the repository. Then I ran the program as if it had already been published (eg. running &lt;code&gt;jellybean --version&lt;/code&gt; would print the version number, etc.). You can read more about how to use npm link &lt;a href="https://docs.npmjs.com/cli/v8/commands/npm-link"&gt;here&lt;/a&gt;. &lt;/p&gt;

&lt;h2&gt;
  
  
  Publishing the Project
&lt;/h2&gt;

&lt;p&gt;Next, I published the program by running the commands:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm adduser
npm publish
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;npm adduser&lt;/code&gt; creates or links to your npm account. &lt;code&gt;npm publish&lt;/code&gt; publishes your package, which you should run each time you want to update your package. &lt;/p&gt;

&lt;h2&gt;
  
  
  Problems I Encountered
&lt;/h2&gt;

&lt;p&gt;Although the steps described above are quite simple, I encountered some problems along the way. Because I originally published the package in September and installed it, I had an older version of the jellybean files in my C:\Users\...\AppData\Roaming\npm folder. Therefore, every time I tried to run the jellybean command, I got the following error:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;amp; : The term '/user/bin/env.exe' is not recognized as the name of a cmdlet, function, script file, or operable program. Check
the spelling of the name, or if a path was included, verify that the path is correct and try again.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I fixed this issue by deleting the old files from the npm folder and once I published my package to npm, I reinstalled it globally and was able to successfully run the program. &lt;/p&gt;

&lt;h2&gt;
  
  
  Testing
&lt;/h2&gt;

&lt;p&gt;I partnered with another student from my class, &lt;a href="https://github.com/suhhee1011"&gt;Suhhee&lt;/a&gt;, in order to test each other's programs. When Suhhee tested my program, she received the following error:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Error: ENOENT: no such file or directory, open 'src/layout.html'
    at Object.openSync (fs.js:498:3)
    at Object.readFileSync (fs.js:394:35)
    at getHtmlLayout 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Because of this, I changed my file paths from relative to absolute paths using path.resolve() so that the program can be run from any directory. For example instead of:&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="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;readFileSync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;src/index.html&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="s1"&gt;utf8&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I updated the code to:&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="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;readFileSync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;__dirname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../src/layout.html&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="s1"&gt;utf8&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;In conclusion, the process of setting up an npm package was pretty straightforward, other than a few problems that I was able to resolve. Over the past almost three months, I've been working on this project every week and getting to publish it was a great end to this journey. If you're interested in trying out the program, you can read more about it &lt;a href="https://www.npmjs.com/package/jellybean"&gt;here&lt;/a&gt; or run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install -g jellybean
jellybean --help
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To get started. Thanks so much for reading!&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>node</category>
      <category>javascript</category>
      <category>npm</category>
    </item>
    <item>
      <title>Finding Issues to Work On</title>
      <dc:creator>Leyang Yu</dc:creator>
      <pubDate>Fri, 26 Nov 2021 21:19:05 +0000</pubDate>
      <link>https://dev.to/lyu4321/open-source-part-13-finding-issues-43gn</link>
      <guid>https://dev.to/lyu4321/open-source-part-13-finding-issues-43gn</guid>
      <description>&lt;h2&gt;
  
  
  Intro
&lt;/h2&gt;

&lt;p&gt;For my open source class, our next assignment is to find and contribute to a larger and more impactful issue compared to previous assignments. I'll be working on this over the next three weeks and blogging about my goals, progress, and results during this time. In this first week, I would like to talk about the process of finding a project and issues to work on and my goals for this assignment. &lt;/p&gt;

&lt;h2&gt;
  
  
  Finding a Project
&lt;/h2&gt;

&lt;p&gt;For this assignment, I wanted to continue my work on the &lt;a href="https://github.com/Seneca-ICTOER/IPC144"&gt;IPC144&lt;/a&gt; repository, which is the course notes repository for the IPC144 course. Previously, I had submitted a PR and also completed code reviews for other PRs for this repository. I want to continue working on this project on a deeper level and hopefully provide some fixes for things that I was not able to accomplish in the previous PR, which I'll explain in the next section.&lt;/p&gt;

&lt;h2&gt;
  
  
  Finding Issues
&lt;/h2&gt;

&lt;p&gt;One of my goals for this assignment is to work on something related to the front-end/UI as this is the area of development I am most interested in. In addition, I want to work on more open-ended issues that allow me to be more creative and come up with new ideas or solutions. Therefore, when I saw these two issues in the IPC144 repository, I was really excited to work on them:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/Seneca-ICTOER/IPC144/issues/112"&gt;Issue #1: Figure out highlighting colour(s) and strategy for light and dark mode&lt;/a&gt;&lt;br&gt;
&lt;a href="https://github.com/Seneca-ICTOER/IPC144/issues/120"&gt;Issue #2: Experiment with converting Raster images to SVGs&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;These two issues were both problems that I had encountered while working on my previous PR for this repository. For example, in my previous PR, I converted all tables from HTML to images due to sizing issues on different screen sizes. However, the images were a bit blurry, especially if you zoomed in, so I don't think the current solution is ideal. Therefore, I'm really interested in doing more research about &lt;a href="https://web.dev/svgcode/"&gt;SVGcode&lt;/a&gt;, which converts raster images to SVGs, to see if it would be a possible solution. In addition, another problem I previously encountered was dealing with tables and images in light vs dark modes, so in the upcoming weeks, I'll be working on a solution that allows pages to look great in either mode. &lt;/p&gt;

&lt;h2&gt;
  
  
  Approaching the Issues
&lt;/h2&gt;

&lt;p&gt;Next week, I'll be doing more research on SVGcode. The issue links to a &lt;a href="https://www.youtube.com/watch?v=kcvfyQh6J-0&amp;amp;ab_channel=GoogleChromeDevelopers"&gt;video tutorial&lt;/a&gt; which I will be following along with to convert a few raster images from the repository to see if and how it works. The issue regarding light and dark themes also links to a &lt;a href="https://docusaurus.io/docs/styling-layout"&gt;Docusaurus&lt;/a&gt; page, which provides more information on how to create styles for different themes. I will be testing this out and also experimenting with different colours to see what would be most suitable for the light and dark themes of the website. &lt;/p&gt;

&lt;p&gt;In the next week, I will be blogging about my progress on these two issues so far and any problems I've encountered or solutions I've come up with. Thanks for reading!&lt;/p&gt;

</description>
      <category>opensource</category>
    </item>
    <item>
      <title>Contributing to an Open Source Browser Extension</title>
      <dc:creator>Leyang Yu</dc:creator>
      <pubDate>Sat, 20 Nov 2021 00:35:56 +0000</pubDate>
      <link>https://dev.to/lyu4321/contributing-to-an-open-source-browser-extension-3881</link>
      <guid>https://dev.to/lyu4321/contributing-to-an-open-source-browser-extension-3881</guid>
      <description>&lt;h2&gt;
  
  
  Intro
&lt;/h2&gt;

&lt;p&gt;I've always wanted to try making my own browser extension and this week, I had the opportunity to contribute to a open source browser extension project called &lt;a href="https://github.com/jure965/OpenLorem"&gt;OpenLorem&lt;/a&gt;. I found OpenLorem while browsing through issues on GitHub and saw that they had several smaller issues open. In this post, I'll be talking about the issues I worked on, the difficulties I encountered, and what I learned during this process.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting Up the Project
&lt;/h2&gt;

&lt;p&gt;Setting up an extension for testing was surprisingly easier than I expected. After forking and cloning the repository to my computer, I could try out the extension in the following ways:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;In &lt;strong&gt;Firefox&lt;/strong&gt;, go to &lt;code&gt;about:debugging#/runtime/this-firefox&lt;/code&gt; and click the "Load Temporary Add-on..." button. Then upload the manifest.json file.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;In &lt;strong&gt;Chrome&lt;/strong&gt;, go to &lt;code&gt;Settings&lt;/code&gt; and then &lt;code&gt;Extensions&lt;/code&gt;. In the top right, there will be a toggle switch to turn on Developer Mode, which needs to be switched on. Then click "Load unpacked" and upload the folder containing the manifest.json file. &lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  The first and second issues
&lt;/h2&gt;

&lt;p&gt;The first two issues were fairly simple and small fixes. The &lt;a href="https://github.com/jure965/OpenLorem/issues/27"&gt;first&lt;/a&gt; issue was a CSS fix whereas the &lt;a href="https://github.com/jure965/OpenLorem/issues/28"&gt;second&lt;/a&gt; issue was finding a way to safely insert HTML into the DOM.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--EL8jIunE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2gos250aqvkusq9d5kly.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--EL8jIunE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2gos250aqvkusq9d5kly.png" alt="Contributors Before" width="151" height="134"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you can see, the CSS for the Contributors list before didn't look great. All I had to do was add a class selector to the &lt;code&gt;&amp;lt;ul&amp;gt;&lt;/code&gt; tag and apply some CSS to it to remove the bullet points. &lt;/p&gt;

&lt;p&gt;In the HTML:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;ul&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"contributors-list"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the CSS:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.contributors-list&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;list-style-type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;none&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;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--AGkOCid9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/302q4ohzbctcxykxx1ie.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--AGkOCid9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/302q4ohzbctcxykxx1ie.png" alt="Contributors After" width="169" height="146"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After the fix, the CSS looks better. &lt;/p&gt;

&lt;p&gt;The second issue was that a user could directly insert the generated text into the HTML via the context menu, but the innerHTML method being used was unsafe. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--A--Vqhmo--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qe2rh45k91qgkyi2rmz0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--A--Vqhmo--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qe2rh45k91qgkyi2rmz0.png" alt="Context Menu" width="405" height="353"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The repo owner suggested looking into the DOMParser.parseFromString() method. I did so and I found out that this method takes in a string containing HTML or XML and returns and HTMLDocument or XMLDocument. In this case, we are working with an HTML string, so parsing it 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;let&lt;/span&gt; &lt;span class="nx"&gt;loremText&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;DOMParser&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;parseFromString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;text/html&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, in order to get the contents of the &lt;code&gt;&amp;lt;body&amp;gt;&lt;/code&gt; tag, I did:&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;let&lt;/span&gt; &lt;span class="nx"&gt;loremText&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;DOMParser&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;parseFromString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;text/html&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;childNodes&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally, in order to replace the section of HTML with these child nodes, I used the replaceChildren() function 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="nx"&gt;clickedElement&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;parentNode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;replaceChildren&lt;/span&gt;&lt;span class="p"&gt;(...&lt;/span&gt;&lt;span class="nx"&gt;loremText&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The third issue
&lt;/h2&gt;

&lt;p&gt;The third issue took a bit more time. This issue involved modifying the icon for the extension because it had black text on a transparent background and was very hard to see in dark mode. At first I thought I could just change the transparent background to white, but the owner requested that I update the SVG as well and use this file to create the icons. I have never created or modified an SVG before, but I saw that the SVG that OpenLorem is using was created using Inkscape so I downloaded this program.&lt;/p&gt;

&lt;p&gt;Through some tutorials, I learned how to add a background, center it,  and also how to modify the shape of the background, as the owner requested rounded corners.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;rect&lt;/span&gt;
       &lt;span class="na"&gt;style=&lt;/span&gt;&lt;span class="s"&gt;"fill:#ffffff;stroke-width:0.937212"&lt;/span&gt;
       &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"rect1425"&lt;/span&gt;
       &lt;span class="na"&gt;width=&lt;/span&gt;&lt;span class="s"&gt;"354.33212"&lt;/span&gt;
       &lt;span class="na"&gt;height=&lt;/span&gt;&lt;span class="s"&gt;"353.82001"&lt;/span&gt;
       &lt;span class="na"&gt;x=&lt;/span&gt;&lt;span class="s"&gt;"0"&lt;/span&gt;
       &lt;span class="na"&gt;y=&lt;/span&gt;&lt;span class="s"&gt;"698.78735"&lt;/span&gt;
       &lt;span class="na"&gt;ry=&lt;/span&gt;&lt;span class="s"&gt;"86.73204"&lt;/span&gt;
       &lt;span class="na"&gt;inkscape:export-xdpi=&lt;/span&gt;&lt;span class="s"&gt;"4.0640001"&lt;/span&gt;
       &lt;span class="na"&gt;inkscape:export-ydpi=&lt;/span&gt;&lt;span class="s"&gt;"4.0640001"&lt;/span&gt;
       &lt;span class="na"&gt;transform=&lt;/span&gt;&lt;span class="s"&gt;"matrix(0.999996,-0.0028271,0,1,0,0)"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This was the bit of XML code generated after I made my changes. I made the modifications to the SVG file and exported these changes to PNG files to be used as the new icons. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--JCldI9TZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7x9priuwdo08mf7cegk4.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--JCldI9TZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7x9priuwdo08mf7cegk4.PNG" alt="Icon Before" width="184" height="85"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--zSZg3n-o--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gi0ffx6ui400t5sdaqbk.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--zSZg3n-o--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gi0ffx6ui400t5sdaqbk.PNG" alt="Icon After" width="203" height="95"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can see the results of these changes in the icons here. &lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Overall, I learned so much through contributing to this repository. I was able to work on a browser extension which is something I've never tried before and I also learned how to create SVGs and custom icons. &lt;/p&gt;

&lt;p&gt;Thanks for reading!&lt;/p&gt;

</description>
      <category>opensource</category>
    </item>
    <item>
      <title>Reviewing Code in a Class Repo</title>
      <dc:creator>Leyang Yu</dc:creator>
      <pubDate>Fri, 19 Nov 2021 18:28:26 +0000</pubDate>
      <link>https://dev.to/lyu4321/reviewing-code-in-a-class-repo-cp2</link>
      <guid>https://dev.to/lyu4321/reviewing-code-in-a-class-repo-cp2</guid>
      <description>&lt;h2&gt;
  
  
  Intro
&lt;/h2&gt;

&lt;p&gt;In &lt;a href="https://dev.to/lyu4321/contributing-to-a-class-repo-3one"&gt;another post&lt;/a&gt;, I talked about contributing to a &lt;a href="https://github.com/Seneca-ICTOER/IPC144"&gt;course website repository&lt;/a&gt; for a course at my school. I audited and fixed a markdown page and received a lot of great feedback and reviews from my classmates. In this post, I would like to talk about my experience reviewing other pull requests in the same repository.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://github.com/Seneca-ICTOER/IPC144/pull/72"&gt;Review #1&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;This pull request looked really good and there were not a lot of things to fix. However, I did find some small typos, which I mentioned to the author.&lt;/p&gt;

&lt;p&gt;For example "We store the &lt;strong&gt;SKUs&lt;/strong&gt;" instead of &lt;strong&gt;skus&lt;/strong&gt; and "[...] the algorithm picks [...] and &lt;strong&gt;swaps&lt;/strong&gt; the values [...]" instead of &lt;strong&gt;swap&lt;/strong&gt;. &lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://github.com/Seneca-ICTOER/IPC144/pull/75"&gt;Review #2&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;This pull request was really good as well, but one thing I noticed right away was the sidebar:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--iOxEKfhr--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/u0ybsra9oihhyo2er33e.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--iOxEKfhr--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/u0ybsra9oihhyo2er33e.png" alt="String Library Sidebar Before" width="264" height="353"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The String Functions section describes the functions that will be explained later, including String Length, String Copy, String Compare, and String Concatenate. However, all five of these sections had the same heading level. I suggested that perhaps the latter four section headers could be one level down since they were subsections of the larger String Functions section. The author agreed with my suggestion and changed the headings from second to third level so that the sidebar now looks like:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--3RW7Lzjo--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rmewsp0v20kmljst7b1b.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--3RW7Lzjo--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rmewsp0v20kmljst7b1b.png" alt="String Library Sidebar After" width="280" height="367"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://github.com/Seneca-ICTOER/IPC144/pull/78"&gt;Review #3&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;In the last code review I did, I made a few suggestions to the author. First was the Frontmatter, which initially only included the navbar/sidebar position. I suggested adding more details to the Frontmatter, such as id, title, slug, and description. &lt;/p&gt;

&lt;p&gt;Instead of:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;sidebar_position&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The Frontmatter now looks like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="s"&gt;--------&lt;/span&gt;
&lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;computers&lt;/span&gt;
&lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Computers&lt;/span&gt;
&lt;span class="na"&gt;sidebar_position&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
&lt;span class="na"&gt;slug&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/introduction/computers&lt;/span&gt;
&lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;This chapter will teach you about the major components of a modern computer and the software that controls them.&lt;/span&gt;
&lt;span class="s"&gt;--------&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I also suggested adding some intra-site links where it may be useful to users as well as adding descriptive text to links. For example, the first paragraph of the page mentions algorithms and libraries, which are other pages on the site. After adding links and descriptive text, it now looks like:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--R3lXPINS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7untxwnnpxqlpwuzxtzt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--R3lXPINS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7untxwnnpxqlpwuzxtzt.png" alt="Algorithms and Libraries" width="880" height="109"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Which is useful if a user wants more information about related topics. &lt;/p&gt;

&lt;p&gt;Finally, I also found a couple of typos which I mentioned and these were fixed as well.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;As I mentioned in my previous post about contributing to this repository, it was great to work on these issues as an open source community. I learned a lot from reviewing other people's code and it was interesting to see the different ways in which everyone approached similar tasks. Overall, I hope these reviews will help improve the quality of the code and create a better and more consistent website.&lt;/p&gt;

</description>
      <category>opensource</category>
    </item>
    <item>
      <title>Contributing to a Class Repo</title>
      <dc:creator>Leyang Yu</dc:creator>
      <pubDate>Fri, 19 Nov 2021 07:42:00 +0000</pubDate>
      <link>https://dev.to/lyu4321/contributing-to-a-class-repo-3one</link>
      <guid>https://dev.to/lyu4321/contributing-to-a-class-repo-3one</guid>
      <description>&lt;h2&gt;
  
  
  Intro
&lt;/h2&gt;

&lt;p&gt;One of the courses I previously took at Seneca, IPC144, is getting a major overhaul to their website, and through my open source class, I had the opportunity to contribute to this project. There was a huge &lt;a href="https://github.com/Seneca-ICTOER/IPC144/issues/18"&gt;meta issue&lt;/a&gt; with all the pages that needed to be updated and I decided to take on the task of auditing and fixing the arrays.md page.&lt;/p&gt;

&lt;h2&gt;
  
  
  Approaching the Task
&lt;/h2&gt;

&lt;p&gt;If you take a look at the &lt;a href="https://github.com/Seneca-ICTOER/IPC144/issues/40"&gt;issue&lt;/a&gt;, there was quite a significant list of things to be completed. I first forked and cloned the issue, created a new branch for my issue (called issue-40) and started up the website to see how it looked. After this, I tackled the list one by one, checking off tasks as I completed them and creating commits for each one.&lt;/p&gt;

&lt;p&gt;Some of the changes I made included:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;fixing typos&lt;/li&gt;
&lt;li&gt;adding intra-site links and adding descriptive text to links&lt;/li&gt;
&lt;li&gt;adding Frontmatter
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;arrays&lt;/span&gt;
&lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Arrays"&lt;/span&gt;
&lt;span class="na"&gt;sidebar_position&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
&lt;span class="na"&gt;slug&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/data-structures/arrays&lt;/span&gt;
&lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;An&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;array&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;is&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;a&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;data&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;structure&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;consisting&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;of&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;an&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;ordered&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;set&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;of&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;elements&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;of&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;common&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;type&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;that&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;are&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;stored&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;contiguously&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;in&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;memory."&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;adding syntax highlighting&lt;/li&gt;
&lt;li&gt;fixing some HTML that was causing console errors&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For example, in the HTML tables, there were no &lt;code&gt;&amp;lt;thead&amp;gt;&lt;/code&gt; or &lt;code&gt;&amp;lt;tbody&amp;gt;&lt;/code&gt; tags which caused the &lt;code&gt;&amp;lt;tr&amp;gt; cannot appear as a child of &amp;lt;table&amp;gt;&lt;/code&gt; error and the columns were using colspan instead of colSpan.&lt;/p&gt;

&lt;p&gt;I pushed all these changes to the issue-40 branch and created a pull request in the main repository.&lt;/p&gt;

&lt;h2&gt;
  
  
  Receiving Reviews
&lt;/h2&gt;

&lt;p&gt;I received so many helpful reviews to my pull request. For example, the image on the page was difficult to see in dark mode and I had forgotten to add alt text. Two of my classmates, &lt;a href="https://github.com/Seneca-ICTOER/IPC144/pull/76#issuecomment-969101607"&gt;Tengzhen&lt;/a&gt; and  &lt;a href="https://github.com/Seneca-ICTOER/IPC144/pull/76#issuecomment-969762369"&gt;Minsu&lt;/a&gt; pointed these out to me and Tengzhen suggested that I could save the image and add a white background so that the black text would still be visible on a black background. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--jFB11TsX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/s00hy2swx3c927fbum5j.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--jFB11TsX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/s00hy2swx3c927fbum5j.png" alt="Image Before" width="880" height="134"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is what the image looked like before. As you can see, the circled text is barely visible in dark mode. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--XQ4lGzlH--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/04s37z3bve1i0tgfhecz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--XQ4lGzlH--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/04s37z3bve1i0tgfhecz.png" alt="Image After" width="880" height="129"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After the fix, it's clearer. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/Seneca-ICTOER/IPC144/pull/76#issuecomment-970201478"&gt;Jerry&lt;/a&gt; suggested that I could convert the tables to images since the tables didn't look great on all screen sizes and in his case, he needed to scroll to see the full table. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--A-bvP6cV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/n6j9i1d3ygs81sx7rrgo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--A-bvP6cV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/n6j9i1d3ygs81sx7rrgo.png" alt="Table Before" width="880" height="441"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is how a table looked for Jerry.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--wRDY2vDW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/u50v4bohozeoi2u4ncwn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--wRDY2vDW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/u50v4bohozeoi2u4ncwn.png" alt="Table After" width="880" height="241"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After the fix, all the tables are images and resize according to the page size.&lt;/p&gt;

&lt;p&gt;Finally, &lt;a href="https://github.com/Seneca-ICTOER/IPC144/pull/76#discussion_r750541451"&gt;Kien&lt;/a&gt; pointed out a typo as well as a &lt;a href="https://github.com/Seneca-ICTOER/IPC144/pull/76#discussion_r750543605"&gt;broken link&lt;/a&gt; on the page. &lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Although I had checked over my work before creating the pull request, I guess the great thing about open source is even if you miss something, you can get a lot of great input from others and suggestions on how to make things even better. It was a bit overwhelming working on such a large meta issue because everyone had different ways of approaching the same tasks, but it was a great learning experience and made me very appreciative of working with an open source community. &lt;/p&gt;

</description>
      <category>opensource</category>
    </item>
    <item>
      <title>Adding Continuous Integration to a Project</title>
      <dc:creator>Leyang Yu</dc:creator>
      <pubDate>Fri, 19 Nov 2021 03:52:01 +0000</pubDate>
      <link>https://dev.to/lyu4321/adding-continuous-integration-to-a-project-13a8</link>
      <guid>https://dev.to/lyu4321/adding-continuous-integration-to-a-project-13a8</guid>
      <description>&lt;h2&gt;
  
  
  Intro
&lt;/h2&gt;

&lt;p&gt;After writing a few unit and E2E Integration tests for my static site generator, &lt;a href="https://github.com/lyu4321/jellybean"&gt;Jellybean&lt;/a&gt;, last week, this week I added Continuous Integration to the repository. It was very easy to set up and is useful if you or other contributors forget to manually test while making changes. It ensures that changes or pull requests made to the main branch are automatically tested by running a workflow.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting up GitHub Actions CI Workflow
&lt;/h2&gt;

&lt;p&gt;The process of setting up the workflow was very simple. In the "Actions" tab of my repository, I selected a workflow template for my program. In my case, I selected the Node.js template, which automatically created a .github/workflows folder in my repository containing a node.js.yml file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# This workflow will do a clean install of node dependencies, cache/restore them, build the source code and run tests across different versions of node&lt;/span&gt;
&lt;span class="c1"&gt;# For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions&lt;/span&gt;

&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Node.js CI&lt;/span&gt;

&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt; &lt;span class="nv"&gt;main&lt;/span&gt; &lt;span class="pi"&gt;]&lt;/span&gt;
  &lt;span class="na"&gt;pull_request&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt; &lt;span class="nv"&gt;main&lt;/span&gt; &lt;span class="pi"&gt;]&lt;/span&gt;

&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;

    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;

    &lt;span class="na"&gt;strategy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;matrix&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;node-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;14.x&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;16.x&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
        &lt;span class="c1"&gt;# See supported Node.js release schedule at https://nodejs.org/en/about/releases/&lt;/span&gt;

    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v2&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Use Node.js ${{ matrix.node-version }}&lt;/span&gt;
      &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/setup-node@v2&lt;/span&gt;
      &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;node-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ matrix.node-version }}&lt;/span&gt;
        &lt;span class="na"&gt;cache&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;npm'&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm ci&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm run build --if-present&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm test&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The only thing I changed in the default template was the supported Node versions. By default, versions 12.x, 14.x, and 16.x are supported. However, I was using a function in my program called fs.rmSync(), which is not supported in version 12.x and I was running my program on version 14.17.5. Therefore, I decided to remove the option for version 12.x from the template and put a note about which version of Node to install in the README and CONTRIBUTING.md files.&lt;/p&gt;

&lt;p&gt;For my own project, I wrote a few more unit tests for two functions, just to ensure that the workflow was properly set up and working and my changes passed all the checks. I &lt;a href="https://github.com/lyu4321/jellybean/commit/cc5c7f09c50baa32d0f686cc72ec73c3647956e9"&gt;merged&lt;/a&gt; these changes to the repository.&lt;/p&gt;

&lt;p&gt;I also worked on another project, &lt;a href="https://github.com/minhhang107/mh-ssg"&gt;mh-ssg&lt;/a&gt;, and added tests to this project as well. I created unit tests for a function called processFolder(). This function accepts an input folder path, output folder path and stylesheet URL. I created two unit tests, one which tests when a valid input folder containing files is passed to the function and one which tests when a non-existent folder is passed to the function. The function logs a message to the console depending on how many files are saved in the output folder, so the tests I wrote tested for these console logs.&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;const&lt;/span&gt; &lt;span class="nx"&gt;MOCK_FILE_INFO&lt;/span&gt; &lt;span class="o"&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;/path/text.txt&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;Hello World!&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;/path/markdown.md&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;This is a markdown file&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;/output&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="nx"&gt;beforeEach&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;fs&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;__setMockFiles&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;MOCK_FILE_INFO&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;This part of the code sets up a mock file system. This is different from my own tests, as I used a real file system, but I think that in the future, I will change to using a mock file system as well because it reduces the need to create extra files.&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="nx"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;should log success message to console&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="o"&gt;=&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;mockSpy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;jest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;spyOn&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;log&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;processFolder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/path&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;/output&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;https://cdnjs.cloudflare.com/ajax/libs/tufte-css/1.8.0/tufte.min.css&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;mockSpy&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;toHaveBeenCalledWith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;chalk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;green&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="s2"&gt;`2 file(s) saved to folder /output successfully!`&lt;/span&gt;
    &lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="nx"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;should log success message to console&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="o"&gt;=&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;mockSpy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;jest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;spyOn&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;log&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;processFolder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/nonexistent&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;/output&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;https://cdnjs.cloudflare.com/ajax/libs/tufte-css/1.8.0/tufte.min.css&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;mockSpy&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;toHaveBeenCalledWith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;chalk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;green&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="s2"&gt;`0 file(s) saved to folder /output successfully!`&lt;/span&gt;
    &lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This part of the code contains the tests. I had to do some research on how to capture console logs in my tests and I discovered the jest.spyOn() function. By assigning mockSpy to jest.spyOn(console, "log"), I spied on the console.log function while running the function I was testing, and I could check to see whether it was called and the arguments it was called with. When passing a mock directory with two valid files, I expected console.log to have been called with:&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="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;chalk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;green&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="s2"&gt;`2 file(s) saved to folder /output successfully!`&lt;/span&gt;
    &lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;(Chalk is used to style the console output)&lt;/p&gt;

&lt;p&gt;However, when passing a directory that doesn't exist, I expected console.log to have been called with:&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="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;chalk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;green&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="s2"&gt;`0 file(s) saved to folder /output successfully!`&lt;/span&gt;
    &lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;My tests passed and I created a merge request to the repository. The repository owner, Minh Hang, approved running the workflow on my &lt;a href="https://github.com/minhhang107/mh-ssg/pull/15"&gt;pull request&lt;/a&gt;, which passed, and &lt;a href="https://github.com/minhhang107/mh-ssg/commit/9f4ac5ab6de4c35a7320798e19b0e6cf0c1415df"&gt;merged&lt;/a&gt; my changes. &lt;/p&gt;

&lt;p&gt;Minh Hang also created a &lt;a href="https://github.com/lyu4321/jellybean/pull/32"&gt;PR&lt;/a&gt; for adding tests to my repository. When creating a PR in a repository for the first time, usually the owner needs to manually approve running the workflow and Minh Hang's changes looked good to me so I did so and all the checks passed. I was able to &lt;a href="https://github.com/lyu4321/jellybean/commit/2dccb2a6d513fd00de1be49a459081ab854c3657"&gt;merge&lt;/a&gt; her changes into my repository as well. &lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;If you work on any repository with others, you will probably come across CI sooner or later. Almost every repository I've contributed to uses them and sometimes my changes would work locally but fail when I created a merge or pull request and it would be hard to figure out why as I had never used CI in my own projects before. After learning more about testing and CI, I understand the benefit and importance of using them in projects and will continue to use them in the future.&lt;/p&gt;

</description>
      <category>opensource</category>
    </item>
    <item>
      <title>Testing Using Jest</title>
      <dc:creator>Leyang Yu</dc:creator>
      <pubDate>Fri, 12 Nov 2021 22:20:44 +0000</pubDate>
      <link>https://dev.to/lyu4321/testing-using-jest-3ok1</link>
      <guid>https://dev.to/lyu4321/testing-using-jest-3ok1</guid>
      <description>&lt;h2&gt;
  
  
  Intro
&lt;/h2&gt;

&lt;p&gt;This week, I continued working on my static site generator &lt;a href="https://github.com/lyu4321/jellybean"&gt;Jellybean&lt;/a&gt; and focused on creating and running tests for the program. I decided to use &lt;a href="https://jestjs.io/"&gt;Jest&lt;/a&gt; for testing because it was what was recommended and also because I have tried other tools such as Jasmine and Karma before, but not Jest, so I thought this would be a good opportunity to learn how it works. &lt;/p&gt;

&lt;h2&gt;
  
  
  Testing Process
&lt;/h2&gt;

&lt;p&gt;By following the documentation, I installed Jest by running:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;and adding:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"scripts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"test"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"jest"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"test:watch"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"jest --watch --"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"coverage"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"jest --collectCoverage --"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;to the scripts in my package.json file. This allows the user to choose from three different commands to run tests:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;npm run test&lt;/code&gt; specifies that the tests should be run. &lt;br&gt;
&lt;code&gt;npm run test:watch&lt;/code&gt; specifies that the tests runner should watch for changes and if a change is made, the tests will be run automatically.&lt;br&gt;
&lt;code&gt;npm run coverage&lt;/code&gt; specifies that the tests should be run and a coverage report should be automatically generated.&lt;/p&gt;

&lt;p&gt;During this process, I created two types of tests. I created unit tests for a specific function in my program and E2E integration tests to test the entire program. &lt;/p&gt;

&lt;p&gt;The function I decided to test with unit tests is called getHtmlNav, which accepts a string or array as an argument and returns the navbar of a page as a string. &lt;/p&gt;

&lt;p&gt;For 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="nx"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Creates navbar with link to index page&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;getHtmlNav&lt;/span&gt;&lt;span class="p"&gt;()).&lt;/span&gt;&lt;span class="nx"&gt;toBe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="s2"&gt;`&amp;lt;div&amp;gt;&amp;lt;ul&amp;gt;&amp;lt;li&amp;gt;&amp;lt;a href='./index.html'&amp;gt;Home&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;/ul&amp;gt;&amp;lt;/div&amp;gt;`&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;When no arguments are passed, the function should return a navbar with a single link to the index page.&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="nx"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Creates navbar with link to index and user-defined pages (array of files)&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nx"&gt;getHtmlNav&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
            &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Silver Blaze.txt&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="s1"&gt;The Adventure of the Six Napoleans.txt&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="nx"&gt;toBe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="s2"&gt;`&amp;lt;div&amp;gt;&amp;lt;ul&amp;gt;&amp;lt;li&amp;gt;&amp;lt;a href='./index.html'&amp;gt;Home&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;&amp;lt;a href='./Silver Blaze.html'&amp;gt;Silver Blaze&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;&amp;lt;a href='./The Adventure of the Six Napoleans.html'&amp;gt;The Adventure of the Six Napoleans&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;/ul&amp;gt;&amp;lt;/div&amp;gt;`&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;When an array of strings is passed, the function should return a navbar with links to the index page and pages that are passed in the array (but the extension should be changed from .txt or .md to .html). There are several other scenarios, such as when a string is passed or when an empty array is passed, which I also tested for. &lt;/p&gt;

&lt;p&gt;In addition, I created E2E tests for the entire program.&lt;/p&gt;

&lt;p&gt;I created a file called run.js which runs the program using execa and another file that contains the tests. An example of an E2E test would be:&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="nx"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Print error message when no input&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;stderr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;stdout&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;exitCode&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;run&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="nx"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;exitCode&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;toBe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nx"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;stderr&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;toMatchSnapshot&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="nx"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;stdout&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;toEqual&lt;/span&gt;&lt;span class="p"&gt;(&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Which runs the program with no command line arguments. This expects the exitCode to be 1 with a stderr because arguments are required. &lt;/p&gt;

&lt;p&gt;One thing that my program didn't test for previously was a input folder that was empty. If a folder does not contain any .txt or .md files, then the program should not continue and should instead return an error message prompting for valid input.&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="nx"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Prints error message when empty folder&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;stderr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;stdout&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;exitCode&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;--input&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="s1"&gt;invalid-folder&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
        &lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nx"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;exitCode&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;toBe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nx"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;stderr&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;toMatchSnapshot&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="nx"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;stdout&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;toEqual&lt;/span&gt;&lt;span class="p"&gt;(&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This was the test that I wrote for the scenario and I had to go back and change my code so that if an input folder was empty or did not contain any valid files, the program would return an error:&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;let&lt;/span&gt; &lt;span class="nx"&gt;files&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;readdirSync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;input&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;filesArray&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;files&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;f&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
                            &lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;extname&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;f&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.txt&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt;
                            &lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;extname&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;f&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.md&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
                    &lt;span class="p"&gt;);&lt;/span&gt;
                    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;filesArray&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                        &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Input directory is empty.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                        &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I created a testing branch to add all of these changes and I used an &lt;a href="https://github.com/lyu4321/jellybean/commit/b9b9d8199a81d4872f202f5042e17b8baf4a5980"&gt;interactive rebase&lt;/a&gt; to squash all the changes together and merged them with the main branch. &lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Although testing is an essential part of software development, I don't have much experience with writing or running tests so this was a great opportunity to learn about two types of tests, unit and E2E integration tests. The tests I have written only cover a small portion of what is required for the entire program so I will definitely need to make adjustments in the future. However, I will definitely continue using the the tools and skills I learned during this process in my future projects.&lt;/p&gt;

</description>
      <category>opensource</category>
    </item>
    <item>
      <title>Formatting and Linting for JS</title>
      <dc:creator>Leyang Yu</dc:creator>
      <pubDate>Sat, 06 Nov 2021 00:23:52 +0000</pubDate>
      <link>https://dev.to/lyu4321/formatting-and-linting-for-js-dd0</link>
      <guid>https://dev.to/lyu4321/formatting-and-linting-for-js-dd0</guid>
      <description>&lt;h2&gt;
  
  
  Intro
&lt;/h2&gt;

&lt;p&gt;This week in my open source development course, we learned all about Static Analysis Tooling. Although I've worked on several projects that used tools such as Prettier, ESLint and Husky, I have never actually gone through the process of setting up these tools for other developers to use in my own projects. I added these tools to my static site generator, &lt;a href="https://github.com/lyu4321/jellybean" rel="noopener noreferrer"&gt;Jellybean&lt;/a&gt;, and I'll be talking about the process in this post. &lt;/p&gt;

&lt;h2&gt;
  
  
  Prettier
&lt;/h2&gt;

&lt;p&gt;I chose &lt;a href="https://prettier.io/" rel="noopener noreferrer"&gt;Prettier&lt;/a&gt; as the code formatter for my project, as I have used it before and it's probably one of the most well known code formatters for JavaScript. Following their installation guide, I was able to get Prettier installed by running the following commands:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--save-dev&lt;/span&gt; &lt;span class="nt"&gt;--save-exact&lt;/span&gt; prettier
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="o"&gt;{}&amp;gt;&lt;/span&gt; .prettierrc.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The second line &lt;code&gt;echo {}&amp;gt; .prettierrc.json&lt;/code&gt; caused an error, but thankfully, a few of my classmates also encountered this error and I learned that it was because Windows uses Unicode UTF-16LE encoding by default, but JSON files are encoded in UTF-8 by default. By running the command through Command Prompt, I was able to bypass this issue and successfully create the .prettierrc.json file. &lt;/p&gt;

&lt;p&gt;In my .prettierrc.json file, I added the following configurations. There are many other options available, which you can find in the &lt;a href="https://prettier.io/docs/en/options.html" rel="noopener noreferrer"&gt;Prettier docs&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"trailingComma"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"es5"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"tabWidth"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"singleQuote"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I added the following to the scripts in my package.json file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nl"&gt;"prettier"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"prettier --write ."&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"prettier-check"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"prettier --check ."&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And ran Prettier using &lt;code&gt;npm run prettier&lt;/code&gt;. This changed my code quite a bit. For example, Prettier added newlines in many places, semicolons where I had missed them before, and wrapped function arguments in parenthesis, among other changes.&lt;/p&gt;

&lt;h2&gt;
  
  
  ESLint
&lt;/h2&gt;

&lt;p&gt;Like Prettier, &lt;a href="https://eslint.org/" rel="noopener noreferrer"&gt;ESLint&lt;/a&gt; is a very commonly used tool that I see often so I chose it as the Linter for my repository. &lt;/p&gt;

&lt;p&gt;Again, I followed the installation docs and was able to install it quite easily by running these commands:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install &lt;/span&gt;eslint &lt;span class="nt"&gt;--save-dev&lt;/span&gt;
npx eslint &lt;span class="nt"&gt;--init&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When running the second command, you can specify details about your project through the command line such as what framework it uses, where it runs, etc. which is used to automatically generate a configurations file:&lt;/p&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl2tjpbqe86t4ptmopzn3.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl2tjpbqe86t4ptmopzn3.png" alt="ESLint Init"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;(Note: For "Where does your code run?", it should actually be "Node" instead of "Browser" and I had to go fix this in the config file later.)&lt;/p&gt;

&lt;p&gt;I also added the following to the scripts in the package.json file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nl"&gt;"eslint"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"npx eslint ."&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"eslint-fix"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"eslint --fix ."&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After checking my code with ESLint, I got one error from this line:&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="nx"&gt;md&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;markdownit&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ESLint showed the error ""'md' is not defined  no-undef" and once I added the keyword "let", such as:&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;let&lt;/span&gt; &lt;span class="nx"&gt;md&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;markdownit&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This problem was resolved. 😀&lt;/p&gt;

&lt;h2&gt;
  
  
  Integrating With VSCode
&lt;/h2&gt;

&lt;p&gt;First, I installed the Prettier and ESLint extensions in VSCode. After doing this, in the Command Palate, I searched for &lt;strong&gt;Configure Recommended Extensions (Workplace Folder)&lt;/strong&gt;. This creates an extensions.json file in your .vscode folder and you can add the extensions to your project by right clicking on an extension once it has been installed and selecting &lt;strong&gt;Add to Workspace Recommendations&lt;/strong&gt;, as shown below: &lt;/p&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3kq3lujqtxjugb2jzj8b.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3kq3lujqtxjugb2jzj8b.png" alt="Add to Workspace Recommendations"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;In the end, I added these two recommendations to my extensions.json file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="nl"&gt;"recommendations"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"esbenp.prettier-vscode"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"dbaeumer.vscode-eslint"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For settings, I created a settings.json file in the .vscode folder. &lt;/p&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp74jul5kfds1f62le2iw.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp74jul5kfds1f62le2iw.png" alt="Settings"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can see a list of possible options in the dropdown menu when you start typing. These are the configurations I added to my settings.json file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"editor.defaultFormatter"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"esbenp.prettier-vscode"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"editor.formatOnSave"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"eslint.lintTask.enable"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Husky
&lt;/h2&gt;

&lt;p&gt;The last step was to add a pre-commit hook, which checks staged files before you commit. I decided to use &lt;a href="https://typicode.github.io/husky/#/" rel="noopener noreferrer"&gt;Husky&lt;/a&gt; because I had heard of this tool before and it seemed like a popular choice as well.&lt;/p&gt;

&lt;p&gt;I ran the following commands:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install &lt;/span&gt;husky &lt;span class="nt"&gt;--save-dev&lt;/span&gt;
npm set-script prepare &lt;span class="s2"&gt;"husky install"&lt;/span&gt;
npx husky add .husky/pre-commit &lt;span class="s2"&gt;"npm test"&lt;/span&gt;
git add .husky/pre-commit
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The first line installs Husky, the second line adds a script to the package.json file, and the last two lines add the pre-commit hook. &lt;/p&gt;

&lt;p&gt;In the .husky/pre-commit file, I added the following lines:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm run prettier
npm run eslint
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To run Prettier and ESLint before a commit is made. &lt;/p&gt;

&lt;p&gt;Last but not least, I documented all these changes in a &lt;a href="https://github.com/lyu4321/jellybean/blob/main/CONTRIBUTING.md" rel="noopener noreferrer"&gt;CONTRIBUTING.md&lt;/a&gt; file so that anyone who works on the project in the future will understand what tools are used and how to work with them. &lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;I'm so glad I had a chance to learn about Static Analysis Tooling. Although I have used some of these tools before in other projects, I didn't have experience configuring them or adding scripts to run them from the command line, so this was a really useful exercise.&lt;/p&gt;

&lt;p&gt;I have worked on large-scale projects in the past where everyone was using their own way of formatting and it was a bit of a mess and sometimes very frustrating. By having a standard for formatting and checking the code, it simplifies the process of collaborating with others and I will definitely keep this process in mind when creating other projects in the future.&lt;/p&gt;

</description>
      <category>opensource</category>
    </item>
    <item>
      <title>Hacktoberfest Recap</title>
      <dc:creator>Leyang Yu</dc:creator>
      <pubDate>Sun, 31 Oct 2021 18:29:05 +0000</pubDate>
      <link>https://dev.to/lyu4321/hacktoberfest-recap-f91</link>
      <guid>https://dev.to/lyu4321/hacktoberfest-recap-f91</guid>
      <description>&lt;p&gt;I finally completed my first Hacktoberfest!!! 🎃🎃🎃 To recap, here are the issues and PRs that I worked on over the past four weeks:&lt;/p&gt;

&lt;h2&gt;
  
  
  Week 1:
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/Seneca-CDOT/telescope/issues/2299"&gt;Issue&lt;/a&gt;, &lt;a href="https://github.com/Seneca-CDOT/telescope/pull/2336"&gt;Pull Request&lt;/a&gt;, &lt;a href="https://dev.to/lyu4321/hacktoberfest-week-1-khe"&gt;Blog Post&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Summary:
&lt;/h3&gt;

&lt;p&gt;During the first week, I was feeling really overwhelmed with trying to find an issue to work on. I decided to tackle something I was relatively confident about working on, which was UI, and I fixed a UI bug in the Telescope project. Although it was a small styling fix involving just a few lines of code, I learned the basics of working on an issue, creating a pull request, and getting my code merged into the main repository.&lt;/p&gt;

&lt;h2&gt;
  
  
  Week 2:
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/WordPress/openverse-catalog/issues/176"&gt;Issue&lt;/a&gt;, &lt;a href="https://github.com/WordPress/openverse-catalog/pull/230"&gt;Pull Request&lt;/a&gt;, &lt;a href="https://dev.to/lyu4321/hacktoberfest-week-2-2hlp"&gt;Blog Post&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Summary:
&lt;/h3&gt;

&lt;p&gt;I worked on creating updated issue forms for the Openverse Catalog repository, by converting their existing issue templates from markdown to YAML. I learned about issue forms, YAML syntax, and for this pull request, I received a lot of feedback on my changes, which I fixed before my pull request was successfully merged. &lt;/p&gt;

&lt;h2&gt;
  
  
  Week 3:
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/microsoft/fluentui/issues/20166"&gt;Issue&lt;/a&gt;, &lt;a href="https://github.com/microsoft/fluentui/pull/20229"&gt;Pull Request&lt;/a&gt;, &lt;a href="https://dev.to/lyu4321/hacktoberfest-week3-b99"&gt;Blog Post&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Summary:
&lt;/h3&gt;

&lt;p&gt;This week, I was really interested in working on a bigger repository and I like React so Microsoft's Fluent UI repository seemed like a good choice. However, after working on the issue, I didn't receive any reviews on my pull request. I think that maybe this was because the issue was created by someone that wasn't a regular contributor to the repository and perhaps this change wasn't required. Therefore, even if a repository has the "Hacktoberfest" label, I think it's important to check if the code maintainers are active in an issue before working on it. &lt;/p&gt;

&lt;h2&gt;
  
  
  Week 4:
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/mihaiborbea/recipe-app/issues/25"&gt;Issue 1&lt;/a&gt;, &lt;a href="https://github.com/mihaiborbea/recipe-app/pull/28"&gt;Pull Request 1&lt;/a&gt;, &lt;a href="https://github.com/Mayank0255/Atari-Space-Invaders/issues/19"&gt;Issue 2&lt;/a&gt;, &lt;a href="https://github.com/Mayank0255/Atari-Space-Invaders/pull/23"&gt;Pull Request 2&lt;/a&gt;, &lt;a href="https://dev.to/lyu4321/hacktoberfest-week-4-22ni"&gt;Blog Post&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Summary:
&lt;/h3&gt;

&lt;p&gt;Since my third pull request did not get reviewed, I decided to work on two issues in my last week. Because Hacktoberfest was coming to an end, I really wanted to challenge myself to try something new and out of my comfort zone. I worked on form validation in Angular and added a feature to a game in Python. I was honestly so surprised to find out how much I could accomplish using a completely new language (Python). The scope of these two issues was definitely much bigger than the issues I've worked on previously and I think it was a great way to end off an eventful month.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Overall, I learned a lot and also made some mistakes along the way:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;I always avoided issues that had comments because I thought that this meant someone else was already working on them. However, I think these issues are still worth taking a look at. Sometimes, it's just the code maintainers providing input on the issue. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;I wanted to work on some larger projects at first because it seemed they had more activity and more issues, but I realized that smaller repositories are also a great way to find issues. You can work on larger issues (because there are fewer contributors) or issues that are more beginner friendly (if it's a repository that's just getting started for example). &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Last but not least, it may seem daunting to take on an issue in something you've never worked with before (such as a new language) but I think this event is a perfect opportunity try something new and you will be surprised by what you can get done.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I'm so grateful that my open source development course and professor introduced me to this event and it was such a great experience to both learn and improve as a developer and contribute to the open source community! &lt;/p&gt;

</description>
      <category>opensource</category>
      <category>hacktoberfest</category>
    </item>
    <item>
      <title>Hacktoberfest Week 4</title>
      <dc:creator>Leyang Yu</dc:creator>
      <pubDate>Sun, 31 Oct 2021 16:55:09 +0000</pubDate>
      <link>https://dev.to/lyu4321/hacktoberfest-week-4-22ni</link>
      <guid>https://dev.to/lyu4321/hacktoberfest-week-4-22ni</guid>
      <description>&lt;p&gt;It's the fourth and last week of Hacktoberfest. My third PR that I submitted last week wasn't reviewed, so for this final week, I decided to work on two different issues, one of which was for a recipe app written using Angular and another which was a Space Invaders game written in Python.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://foodilo.app/auth?mode=login"&gt;Foodilo&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/mihaiborbea/recipe-app/issues/25"&gt;The issue&lt;/a&gt;&lt;br&gt;
&lt;a href="https://github.com/mihaiborbea/recipe-app/pull/28"&gt;The pull request&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  The Issue
&lt;/h3&gt;

&lt;p&gt;I found this issue interesting because I have also worked on a recipe app in the past using React. However, this project was written using Angular, which I am not as familiar with. I wanted to challenge myself this week so I thought this would be a good place to start.&lt;/p&gt;

&lt;p&gt;For this issue, the main problem was that for the Sign Up form, the  password and confirm password fields should have matching inputs before the form can be submitted. However, the validation was not working and therefore, a user could submit the form with different passwords.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--3VmN2PxI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qxa355ompqmwrwu8v6vw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--3VmN2PxI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qxa355ompqmwrwu8v6vw.png" alt="Before Password Validation" width="880" height="350"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  The Code
&lt;/h3&gt;

&lt;p&gt;The program uses a Directive to compare whether or not the inputs are the same. The problem before was that the input was not being correctly passed to the validate() function, which I rewrote in my pull request:&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="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;MustMatchDirective&lt;/span&gt; &lt;span class="kr"&gt;implements&lt;/span&gt; &lt;span class="nx"&gt;Validator&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Input&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;appMustMatch&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nx"&gt;appMustMatch&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="kd"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

  &lt;span class="nx"&gt;validate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;control&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;AbstractControl&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;ValidationErrors&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;confirmPassword&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;control&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;password&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;control&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;root&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;appMustMatch&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// return null if controls haven't initialised yet&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;password&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;confirmPassword&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&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="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// return null if another validator has already found an error on the matchingControl&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;password&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;errors&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="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// set error on matchingControl if validation fails&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;password&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;password&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="nx"&gt;confirmPassword&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&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="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;appMustMatch&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&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="kc"&gt;null&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The argument passed to the function, &lt;code&gt;control&lt;/code&gt; is used to get the confirmPassword field and &lt;code&gt;control.root.get(this.appMustMatch)&lt;/code&gt; is used to get the password field since I added the property &lt;code&gt;appMustMatch="password"&lt;/code&gt; to the HTML tag for the confirmPassword field. To be honest, I don't have much experience with form validation in Angular and it was my first time using Directives, so this &lt;a href="https://scotch.io/tutorials/how-to-implement-a-custom-validator-directive-confirm-password-in-angular-2"&gt;tutorial&lt;/a&gt; greatly helped me understand how to approach this issue. &lt;/p&gt;

&lt;h3&gt;
  
  
  Feedback
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--_KzYx_hy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vp39f9e3pgci7ca20aai.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--_KzYx_hy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vp39f9e3pgci7ca20aai.png" alt="After Password Validation" width="880" height="362"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After the changes were made, you can see that if the passwords don't match, the form will show an error and the Sign Up button will be disabled. After I submitted this pull request, it was promptly accepted and successfully merged. &lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://github.com/Mayank0255/Atari-Space-Invaders"&gt;Atari Space Invaders&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/Mayank0255/Space-Invaders/issues/19"&gt;The issue&lt;/a&gt;&lt;br&gt;
&lt;a href="https://github.com/Mayank0255/Space-Invaders/pull/23"&gt;The pull request&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  The Issue
&lt;/h3&gt;

&lt;p&gt;I wanted to work on this issue because I really liked the project and it is also written in Python which I have no experience with but want to learn.&lt;/p&gt;

&lt;p&gt;The issue was that the game had a default size of 750x750 pixels, but the project owner wanted to add the option to run the game in full screen mode.&lt;/p&gt;

&lt;p&gt;The project uses pygame, which provides a lot of built-in functions and features to create games. &lt;/p&gt;
&lt;h3&gt;
  
  
  The Code
&lt;/h3&gt;

&lt;p&gt;First I created a class that has a function to toggle between default and full screen modes, which is triggered by pressing [f]:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;DisplayControls&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
     &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;toggle_full_screen&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
        &lt;span class="n"&gt;screen&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pygame&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;display&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_surface&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="n"&gt;screen&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_flags&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;pygame&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FULLSCREEN&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="n"&gt;pygame&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;display&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set_mode&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="mi"&gt;750&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;750&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;info&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pygame&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;display&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Info&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="n"&gt;pygame&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;display&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set_mode&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;info&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;current_w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;info&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;current_h&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;pygame&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FULLSCREEN&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;display_cfg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;DisplayControls&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I also added the following label to the screen:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;        &lt;span class="n"&gt;sfx_label&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;control_font&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'Toggle Full Screen'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;225&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="n"&gt;CANVAS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;blit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sfx_label&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;starting_x&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;125&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;655&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="n"&gt;sfx_key_label&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;keys_font&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'[f]'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;240&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="n"&gt;CANVAS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;blit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sfx_key_label&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;starting_x&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;470&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;655&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--kFMw5Q1h--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8st1p8j37jozl7hmpr77.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--kFMw5Q1h--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8st1p8j37jozl7hmpr77.png" alt="Controls Screen" width="747" height="787"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The hardest part about this issue for me was that the aspect ratio of the game was a square and had to be centered in full screen mode. Because each element was placed on the screen individually, I had to reposition everything. This is the method I used to center the background in the middle of the screen:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;         &lt;span class="n"&gt;screen_rect&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;CANVAS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_rect&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
         &lt;span class="n"&gt;centerx&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;screen_rect&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;centerx&lt;/span&gt;
         &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;centerx&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rectBGimg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;width&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
         &lt;span class="n"&gt;CANVAS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;blit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;bgimage&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;bgY1&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
         &lt;span class="n"&gt;CANVAS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;blit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;bgimage&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;bgY2&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The first two lines determine the center of the window and self.rectBGimg.width / 2 determines half the size of the background. By setting the starting x coordinate to centerx - self.rectBGimg.width / 2 instead of 0, this centers the background in the middle of the screen. I used a similar formula to place all other elements onto the screen. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--UkSVJtLy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/nnzhy4zrov6529urbpc5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--UkSVJtLy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/nnzhy4zrov6529urbpc5.png" alt="Game End Result" width="880" height="660"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;h2&gt;
  
  
  Feedback
&lt;/h2&gt;

&lt;p&gt;The repository owner provided a lot of feedback on my changes.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--KQ9rTcB9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bd5ylbmxvn2aodfazs3i.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--KQ9rTcB9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bd5ylbmxvn2aodfazs3i.png" alt="Pixels Issue" width="880" height="660"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The first was that when playing the game using a mouse, the ship would move off the screen. Although this problem wasn't introduced by my code, it became apparent once the game was in full screen mode because there was blank space on either side of the game and the pixels would get stuck once the ship moved out of bounds. &lt;/p&gt;

&lt;p&gt;Second of all, the way I implemented the toggle full screen was using a key up event. However, the repo owner wanted the user to be able to click the maximize button in the title bar. After some discussion through Discord over how this can be achieved using pygame, we came to the conclusion that the scope of this change would be greater than a simple toggle between default size and full screen and so I agreed to create a new issue after Hacktoberfest to continue working on this. &lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Although it was a bit stressful working on two issues in the last week and particularly using a language I've never used before, it was such a great experience to try something new and contribute to two projects that I found really interesting. I was really surprised at how much I was able to accomplish and feel really happy about ending my Hacktoberfest with these last two pull requests.&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>hacktoberfest</category>
    </item>
  </channel>
</rss>
