<?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: merlos</title>
    <description>The latest articles on DEV Community by merlos (@merlos).</description>
    <link>https://dev.to/merlos</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%2F466450%2F86e7e781-afc4-4481-8eb3-4f6abea7531b.jpeg</url>
      <title>DEV Community: merlos</title>
      <link>https://dev.to/merlos</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/merlos"/>
    <language>en</language>
    <item>
      <title>Agent orchestration. The end of coding as we know.</title>
      <dc:creator>merlos</dc:creator>
      <pubDate>Thu, 26 Feb 2026 01:45:31 +0000</pubDate>
      <link>https://dev.to/merlos/agent-orchestration-the-end-of-coding-as-we-know-jih</link>
      <guid>https://dev.to/merlos/agent-orchestration-the-end-of-coding-as-we-know-jih</guid>
      <description>&lt;p&gt;Are we doomed or it's the best time to be a software developer? &lt;/p&gt;

&lt;p&gt;These days, if you don't mention AI in your writing, you risk appearing obsolete. Software engineering is currently undergoing a profound paradigm shift—one that may see traditional engineering disappear in favor of what can be called &lt;strong&gt;Code Agent Orchestration&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Rise of the AI Agent
&lt;/h2&gt;

&lt;p&gt;You have likely heard of &lt;a href="https://openclaw.ai" rel="noopener noreferrer"&gt;OpenClaw&lt;/a&gt;, an open-source personal assistant that has gained massive traction on GitHub. Its creator was recently hired by OpenAI. &lt;/p&gt;

&lt;p&gt;While the product itself is interesting, its tagline is what truly resonates: &lt;em&gt;"An agent that actually does things."&lt;/em&gt; What I find most enlightening is how it was developed. In a recent interview on the &lt;a href="https://lexfridman.com/peter-steinberger" rel="noopener noreferrer"&gt;Max Friedman podcast, Peter Steinberger&lt;/a&gt;, the creator of OpenClaw explained his development process.&lt;/p&gt;

&lt;p&gt;Essentially, to evolve the product, he engages in a conversation with a coding AI (using tools like Claude Code or CodeX). Indeed he does this with several in parallel. And these agents are the ones actually writing the code in the repository.&lt;/p&gt;

&lt;h2&gt;
  
  
  From Code Snippets to Repo Access
&lt;/h2&gt;

&lt;p&gt;Steinberger explains in the podcast how he leveraged AI agents to generate the code. And the key change is the &lt;strong&gt;agentic nature&lt;/strong&gt; of the LLM—the ability of the AI to work directly on the codebase. &lt;/p&gt;

&lt;p&gt;In the "early days" (only a year or two ago!), the workflow was incredibly high-friction. To get anything done with ChatGPT, you had to follow a manual loop:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Prompt&lt;/strong&gt;: Provide a detailed spec in a chat window.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Wait&lt;/strong&gt;: Watch the code chunk generate line-by-line.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Manual Labor&lt;/strong&gt;: Copy-paste the code into your IDE.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Debug&lt;/strong&gt;: Copy-paste the error back to the chat if it failed and repeat.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This process was clunky and fragmented.&lt;/p&gt;

&lt;p&gt;Now, the code agent removes the "middle-human" for these repetitive tasks, allowing the AI to work directly on the codebase. It can:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Read the existing architecture.&lt;/li&gt;
&lt;li&gt;Modify source files directly.&lt;/li&gt;
&lt;li&gt;Write and run tests to verify the changes.&lt;/li&gt;
&lt;li&gt;Fix runtime problems before finishing the task.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This is further enabled by increased &lt;strong&gt;context windows&lt;/strong&gt;. Where early models could only "remember" a few hundred lines of code, modern models can hold entire relatively large codebases in memory, allowing the agent to understand complex dependencies across a large project.&lt;/p&gt;

&lt;p&gt;Because it can take some time for an agent to complete a task, to be more productive, Steinberger was launching several agents in parallel. For instance, while one was completing a complex refactor, he was discussing the architectural approach of a new feature with another. Indeed, he achieved such level of proficiency that he confessed he had to purchase several accounts because he run out of credits. &lt;/p&gt;

&lt;p&gt;Peter Steinberger also confesses that he no longer reviews every line of code; he focuses only on critical components. His rationale is that most code is "boring"—simply moving data from one place to another or transforming between formats. Newer models are now proficient enough to handle these tasks autonomously.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Death of Language Barriers
&lt;/h2&gt;

&lt;p&gt;Another interesting shift is that you no longer need to be "proficient" in a specific language to build with it. Most programming languages share common concepts: variables, loops, and conditions. While the syntax varies—semicolons here, indentation there—the logic remains similar.&lt;/p&gt;

&lt;p&gt;Historically, the real barrier was learning the &lt;strong&gt;libraries and ecosystems&lt;/strong&gt;. This is what separated a senior developer from a newbie. However, LLMs have "read" all the documentation. This enables a frontend developer who knows JavaScript to suddenly write a Python backend, a native iOS app in Swift, or even C++ for an IoT microcontroller. &lt;/p&gt;

&lt;p&gt;Language is no longer the barrier, but your skill to instruct the agent to write what you need.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Future: Creative Destruction
&lt;/h2&gt;

&lt;p&gt;We are at the "steam engine" moment of software development. This is a period of &lt;strong&gt;creative destruction&lt;/strong&gt;. How may this affect our industry?&lt;/p&gt;

&lt;h3&gt;
  
  
  At the Individual Level
&lt;/h3&gt;

&lt;p&gt;A developer might see the glass as half-empty: years of skill-building are being devalued as LLMs do the job faster and cheaper. However, the glass is also half-full: these tools provide superpowers. You can now build ideas in weeks that previously required a full team and months of effort.&lt;/p&gt;

&lt;h3&gt;
  
  
  At the Market Level:
&lt;/h3&gt;

&lt;p&gt;TheseWe can expect software development costs to &lt;strong&gt;plummet&lt;/strong&gt;. Here is how I believe this shift will affect the industry:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Layoffs and Salaries:&lt;/strong&gt; We can expect a market correction. As a single developer becomes as productive as five, the demand for traditional "junior" roles may decrease. Additionally, the barriers to entry will lower; as more people enter the market, we may see a downward trend in average salaries.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;SaaS Competition:&lt;/strong&gt; Established enterprise software giants will face a "mushrooming" of new competitors who can offer the same core features at a fraction of the price. In an even more saturated market, strategies to make your product shine among the others.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Commoditization of Development:&lt;/strong&gt; Small to medium companies that previously relied on off-the-shelf SaaS or complex enterprise systems may now choose to build custom, in-house tools. While custom software can be perfectly integrated into a company's specific processes, enterprise software often requires the company to adapt to the tool—cluttering the experience with unnecessary features and a steeper learning curve.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  A Paradox of Creativity
&lt;/h2&gt;

&lt;p&gt;There is a strange paradox in this revolution. We once imagined technology would automate "blue-collar" labor—cleaning floors or filing invoices—to free humans for the "white-collar" joy of writing, drawing, and coding.&lt;/p&gt;

&lt;p&gt;Instead, we are seeing a world where generative AI targets the tasks we find most intellectually rewarding, while humans are still required for the physical labor.&lt;/p&gt;

&lt;p&gt;I love coding. Even after 20 years, I still find it magical to see logic come to life on a screen.  However, I’ve been playing with this "mini-army" of agentic minions lately, and it is transformative. &lt;/p&gt;

&lt;p&gt;While agentic workflows might commoditize the syntax, they amplify the vision. We aren't losing the craft; we are evolving into &lt;strong&gt;Code Agent Orchestrators&lt;/strong&gt;. The ceiling for what a single developer can build has just been shattered. What a time to be alive. &lt;/p&gt;

&lt;p&gt;Are you ready to lead the orchestra?&lt;/p&gt;

</description>
      <category>agents</category>
      <category>developers</category>
      <category>ai</category>
      <category>career</category>
    </item>
    <item>
      <title>ChatGPT bot with your own data</title>
      <dc:creator>merlos</dc:creator>
      <pubDate>Sat, 25 Mar 2023 07:33:25 +0000</pubDate>
      <link>https://dev.to/merlos/chatgpt-bot-with-your-own-data-3e7k</link>
      <guid>https://dev.to/merlos/chatgpt-bot-with-your-own-data-3e7k</guid>
      <description>&lt;p&gt;In this article I will explain how you can build a &lt;strong&gt;simple custom bot based on ChatGPT API that will answer questions based on a custom knowledge base&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;As we know, ChatGPT and other Large Language Models (LLM) have been trained with the materials publicly available on the Internet. In particular ChatGPT knowledge base only covers till 2021. &lt;/p&gt;

&lt;p&gt;In addition, it is also well known that the internet is just the tip of the iceberg, and there is a lot of content, &lt;a href="https://en.wikipedia.org/wiki/Deep_web" rel="noopener noreferrer"&gt;the deep web&lt;/a&gt;, that is not publicly available and resides behind intranets, require to login or are so specific that ChatGPT may not reach that knowledge level.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Felkxw72c9n90i72g9ooz.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Felkxw72c9n90i72g9ooz.jpg" alt="Tip of the iceberg is small compared with what is under the water" width="413" height="600"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So, the question is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Can we create a ChatGPT like bot that provides answers based on our small piece of deep web or with a very specific content custom made knowledge base?&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Yes, and it is fairly simple.
&lt;/h2&gt;

&lt;p&gt;Here is what you'll achieve after following this tutorial. In this case I tested it with the contents of &lt;a href="https://www.merlos.org" rel="noopener noreferrer"&gt;my personal webpage&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fekh5nrnzr5zawjrlo64l.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fekh5nrnzr5zawjrlo64l.gif" alt="ChatGPT demo" width="877" height="740"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Cool, isn't it?&lt;/p&gt;

&lt;h2&gt;
  
  
  So, What's the process you need to follow?
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Gather the base of knowledge you want to use for your bot.&lt;/strong&gt; For example, a set of webpages PDF, markdown, word files, etc. Create the corpus with the content that has the answers to the questions.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Convert the corpus plain text files.&lt;/strong&gt; Convert those files into plain text. We need this step because the model that generates the answer needs plain text as input.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Create a set of embeddings&lt;/strong&gt;. Embeddings is a way to translate information into a vector format to perform a semantic search. In our case the embeddings are used to find the documents that most probably have the information that can be used to generate the answer to our question. To create the embeddings the text files will be broken in chunks and we will call an OpenAI API to create embeddings for each chunk.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  What do I need?
&lt;/h2&gt;

&lt;p&gt;You only have a couple of pre-requisites:&lt;/p&gt;

&lt;p&gt;1) A box with python (tested with 3.9 and 3.11) &lt;br&gt;
2) &lt;a href="https://platform.openai.com/" rel="noopener noreferrer"&gt;OpenAI account&lt;/a&gt;, and an &lt;a href="https://platform.openai.com/account/api-keys" rel="noopener noreferrer"&gt;API key&lt;/a&gt;. You get some USD of free credits for testing. &lt;/p&gt;

&lt;p&gt;The free credits should be enough even for a relatively large knowledge base. &lt;/p&gt;

&lt;p&gt;The code that we will use on this tutorial uses &lt;code&gt;GPT3.5turbo&lt;/code&gt; model, which is the version prior to GPT4. It's API is compatible with GPT4 API. So, if you get access to it, you just need to change the model.&lt;/p&gt;

&lt;p&gt;In addition, some basic python knowledge may help you to customize the code.&lt;/p&gt;
&lt;h2&gt;
  
  
  Let's bot it!
&lt;/h2&gt;

&lt;p&gt;First, clone the repo and install the dependencies:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/merlos/ask-me/
&lt;span class="nb"&gt;cd &lt;/span&gt;ask-me
pip &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; requirements.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you haven't done it yet, create the &lt;a href="https://platform.openai.com/" rel="noopener noreferrer"&gt;OpenAi account&lt;/a&gt; and get an &lt;a href="https://platform.openai.com/account/api-keys" rel="noopener noreferrer"&gt;API key&lt;/a&gt;. Then, set this environment variable within the command prompt:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# OSX and GNU/Linux&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;OPENAI_API_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&amp;lt;your key&amp;gt;

&lt;span class="c"&gt;# Windows&lt;/span&gt;
setenv &lt;span class="nv"&gt;OPENAI_API_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&amp;lt;your key&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Collect your knowledge base
&lt;/h3&gt;

&lt;p&gt;The goal of this step is to gather the data that will be used as corpus and convert each file it into a plain text file.  &lt;/p&gt;

&lt;p&gt;Although the repo comes with a few basic tools, depending on your particular use case and you may need to do some additional work for gathering and converting the content.&lt;/p&gt;

&lt;p&gt;In any case, I would start with a small dataset to test the answers and play around. &lt;/p&gt;

&lt;p&gt;Also note, that these large language models are optimized for ingesting text, so formats such has data tables won't provide good results.&lt;/p&gt;

&lt;p&gt;The repo comes with a few tools that may be useful.&lt;/p&gt;

&lt;p&gt;The first one is &lt;code&gt;scrapper.py&lt;/code&gt;. It takes as argument a webpage address and goes through all the pages that are within the domain. For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python scrapper.py https://www.merlos.org
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As output, it will create the folder &lt;code&gt;./text/www.merlos.org/&lt;/code&gt; with the scrapped pages in text format. The scrapper is not the best in the world, so it may have small glitches. The source code is pretty well explained.&lt;/p&gt;

&lt;p&gt;For more corporate environments. Another tool provided is is &lt;code&gt;DownloadSharePointDocs.ps1&lt;/code&gt; This is a PowerShell script downloads the files from a SharePoint library.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# In a powershell prompt&lt;/span&gt;
.&lt;span class="se"&gt;\D&lt;/span&gt;ownloadSharePointDocuments.ps1 &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;-SiteUrl&lt;/span&gt; &lt;span class="s2"&gt;"https://&amp;lt;tenant name&amp;gt;.sharepoint.com/sites/yoursite/"&lt;/span&gt; 
    &lt;span class="nt"&gt;-LibraryName&lt;/span&gt; &lt;span class="s2"&gt;"Library"&lt;/span&gt;
    &lt;span class="nt"&gt;-DownloadFolder&lt;/span&gt; &lt;span class="s2"&gt;"./LibraryDocuments"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note that &lt;code&gt;DownloadFolder&lt;/code&gt; must exist. The script downloads the required powershell modules.&lt;/p&gt;

&lt;p&gt;To run it on a GNU/Linux or a Mac you need to &lt;a href="https://github.com/PowerShell/PowerShell" rel="noopener noreferrer"&gt;install PowerShell&lt;/a&gt; (f.i &lt;code&gt;brew install pwsh&lt;/code&gt;). On windows you need to run it as Administrator if you don't have the modules required.&lt;/p&gt;

&lt;p&gt;The last helper that is provided is &lt;code&gt;pdftotext.py&lt;/code&gt;. This script takes a folder with a set of PDFs and converts them into txt files. You can download or collect PDFs, leave them in a folder and this script will convert them into plain text.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python pdftotext ./path/with/pdfs &lt;span class="nt"&gt;--output&lt;/span&gt; ./text/filesfolder/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For other types of documents such as word documents or slide deck presentations, you may need to find some other tools to convert them into plain txt files. The only requirement for the next step is to place all the documents converted into plain text, in a folder for the next step. &lt;/p&gt;

&lt;p&gt;You can leave in the comments any other tool that you have used for gathering the data.&lt;/p&gt;

&lt;h2&gt;
  
  
  Process the data.
&lt;/h2&gt;

&lt;p&gt;Now, you have a folder full of plain text files that will be your corpus. The next step is to break down these files in smaller chunks of text, and include something called &lt;a href="https://en.wikipedia.org/wiki/Word_embedding" rel="noopener noreferrer"&gt;embeddings&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;We break down the files in small chunks because the OpenAI API has a limit on the amount of text it can process in one single call. &lt;/p&gt;

&lt;p&gt;The creation of embeddings is a technique widely used in natural language processing (NLP) and will help us to do a semantic search. &lt;/p&gt;

&lt;p&gt;To get the embeddings run the following script indicating what is the source folder with the text files from the previous step.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python process.py ./text/www.merlos.org
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This script will output the files: &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;processed/corpus.csv&lt;/code&gt;, which is just a list of the txt files in one single csv files, and&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;processed/embeddings.csv&lt;/code&gt; that includes the embeddings.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This step is relatively slow, consequently you may prefer start with a small subset of docs for testing.&lt;/p&gt;

&lt;p&gt;During the implementation it was noticed that the reliability of OpenAPI was poor (maybe because I was in the free tier?). It returned errors in many occasions. If there is an error, you can relaunch the script and it will recover the session.&lt;/p&gt;

&lt;p&gt;If you have a large corpus you can use this loop that will relaunch the script automatically.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="k"&gt;until &lt;/span&gt;python process.py ./text/folder-with-txt-files&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Restarting..."&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="k"&gt;done&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You have some additional documentation about this on the &lt;a href="https://github.com/merlos/ask-me#step-2-process-the-data" rel="noopener noreferrer"&gt;README file of the repo&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Test it
&lt;/h2&gt;

&lt;p&gt;Ok, now it's time for the coolest part. We have the corpus with the embeddings that is everything we need.&lt;/p&gt;

&lt;p&gt;You can test it in the command line.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;python ask.py "this is my question?"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or you can do the same launching a browser&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;python web.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And open the browser at &lt;a href="http://localhost:5000" rel="noopener noreferrer"&gt;http://localhost:5000&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What happens behind the scenes when you ask a question?
&lt;/h2&gt;

&lt;p&gt;The first thing that will be done is to try to find the chunks of text that most probably have the answer to the question. To search that text we will use the embeddings we calculated on the processing step.&lt;/p&gt;

&lt;p&gt;An embeddings is just a way to represent a word - or strictly speaking a token - in a vector format. Therefore, instead of having the word &lt;code&gt;king&lt;/code&gt; or &lt;code&gt;queen&lt;/code&gt;, you will have a vectors, for instance, &lt;code&gt;(1,1,1)&lt;/code&gt; and &lt;code&gt;(1,1.4,1)&lt;/code&gt;, but witch a lot more of dimensions. The values on the different dimensions will depend on how "close" they are. In the example, king and queen will be close because they are semantically related.&lt;/p&gt;

&lt;p&gt;When we pose the question, there is an algorithm that is run on the server that searches in the local dataset for the chunks of texts whose content have the closest embeddings to the question and, therefore, are more likely to have the answer to the question. &lt;/p&gt;

&lt;p&gt;Once we have the chunks of texts that most likely have the answer, we will send those chunks of texts (the context) together with the question and we will will literally ask ChatGPT to provide an answer based on the text provided, similarly to a prompt that you would provide in the ChatGPT website. This is what is sent the API:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Based on the following context:
   {context}
answer the following question:
   {question}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Where {context} are replaced with the chunks of text found and the question is the {question} provided by the user.&lt;/p&gt;

&lt;h2&gt;
  
  
  Hack the code
&lt;/h2&gt;

&lt;p&gt;The source code of the repo is pretty straight forward and, even if you don't have much python knowledge you should be able to follow it. &lt;/p&gt;

&lt;p&gt;Alternatively, you can paste the code into ChatGPT and ask it to do the changes on your behalf :).&lt;/p&gt;

&lt;h2&gt;
  
  
  Last words
&lt;/h2&gt;

&lt;p&gt;Definitely large language models and Generative AI are going to change the way we learn, work and find information. &lt;/p&gt;

&lt;p&gt;However, right now only big tech companies like OpenAI (aka CloseAI), Google with Bart, or Facebook with LlaMa, seem to have the capacity to release these kind of models, but my hope is that either soon computing these models will be accessible to anyone or that some organization will release a truly open model similarly to what happened in the image field with &lt;a href="https://en.wikipedia.org/wiki/Stable_Diffusion" rel="noopener noreferrer"&gt;Stable Diffusion&lt;/a&gt;. That will foster innovation and will make these technologies available even in countries and organizations with less resources.  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Original Iceberg image: &lt;a href="https://en.wikipedia.org/wiki/File:Iceberg.jpg" rel="noopener noreferrer"&gt;https://en.wikipedia.org/wiki/File:Iceberg.jpg&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>python</category>
      <category>chatgpt</category>
      <category>tutorial</category>
      <category>ai</category>
    </item>
    <item>
      <title>How to setup Metasploitable in a Mac with M1 chip</title>
      <dc:creator>merlos</dc:creator>
      <pubDate>Wed, 30 Nov 2022 20:30:44 +0000</pubDate>
      <link>https://dev.to/merlos/how-to-setup-metasploitable-in-a-mac-with-m1-chip-44ph</link>
      <guid>https://dev.to/merlos/how-to-setup-metasploitable-in-a-mac-with-m1-chip-44ph</guid>
      <description>&lt;h2&gt;
  
  
  Intro
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/rapid7/metasploitable3/" rel="noopener noreferrer"&gt;Metasploitable&lt;/a&gt; is a virtual machine image that includes lots of vulnerabilities (on purpose) and that can be used to learn how to hack into a machine.&lt;/p&gt;

&lt;p&gt;There are two virtual machines for Metasploitable (v3):&lt;br&gt;
1) Ubuntu 14.04&lt;br&gt;
2) Windows 2008 server &lt;/p&gt;

&lt;p&gt;Whereas I was able to setup the Ubuntu virtual machine, I could not find the way to run the Windows one and I could not find any reference of someone that made it work.&lt;/p&gt;

&lt;p&gt;There is a previous version, Metasploitable 2, based on GNU/Linux that is also fun to use. The steps are also explained below.&lt;/p&gt;
&lt;h2&gt;
  
  
  Pre-requisites
&lt;/h2&gt;

&lt;p&gt;You need to have installed two tools:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;a href="https://getutm.app/" rel="noopener noreferrer"&gt;UTM&lt;/a&gt;, that is a Virtual Machine engine that runs in M1 chips&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://brew.sh/" rel="noopener noreferrer"&gt;Homebrew&lt;/a&gt;, which is basically a package manager that allows you to install many open source tools easily&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Below you have the steps to install them, but if you already have them, you can skip the steps.&lt;/p&gt;
&lt;h3&gt;
  
  
  Install UTM
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Go to &lt;a href="https://docs.getutm.app/installation/macos/" rel="noopener noreferrer"&gt;https://docs.getutm.app/installation/macos/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Click on the button &lt;strong&gt;Download from GitHub&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Install the package. &lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;
  
  
  Install HomeBrew
&lt;/h3&gt;

&lt;p&gt;You just need to run this in a console:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;/bin/bash &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;curl &lt;span class="nt"&gt;-fsSL&lt;/span&gt; https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note: You may need to install Xcode’s Command Line Tools if you don't have them. Just run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;xcode-select &lt;span class="nt"&gt;--install&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At the end of the installation check out that &lt;strong&gt;there are some instructions to add to your &lt;code&gt;.zshrc&lt;/code&gt; file&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;After the installation you should be able to run the &lt;code&gt;brew&lt;/code&gt; command. If you run &lt;code&gt;brew doctor&lt;/code&gt; you should get &lt;code&gt;Your system is ready to brew&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;brew doctor 
Your system is ready to brew.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Download the Metaexploit 3 image
&lt;/h3&gt;

&lt;p&gt;Thankfully, the guys of Rapid7, the company behind meta exploit, have already created a two images that can be used in &lt;a href="https://www.virtualbox.org/" rel="noopener noreferrer"&gt;Virtual Box&lt;/a&gt;, an open source Virtual Machine Engine. However, VirtualBox is not compatible with M1 chips at the time of writing this article, that's why we are using UTM.&lt;/p&gt;

&lt;p&gt;So, now, let's see how to download the images and what we need in order to run Metaexploit 3 in UTM.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Go to &lt;a href="https://app.vagrantup.com/rapid7" rel="noopener noreferrer"&gt;https://app.vagrantup.com/rapid7&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Select the VM you want to download. In this case, the Ubuntu one.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.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%2F9sh17lubfe806jvllk3v.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2F9sh17lubfe806jvllk3v.png" alt="rapid7 vagrant home page" width="800" height="613"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Download the file&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fscbdqev6tpioqwl62j0a.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fscbdqev6tpioqwl62j0a.png" alt="rapid7 vagrant download page" width="800" height="613"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The name of the downloaded file has a &lt;em&gt;weird&lt;/em&gt; name (some kind of unique id) and does not have extension, but behind the scenes it is a &lt;code&gt;.zip&lt;/code&gt; file. So, you need to rename it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;Downloads
&lt;span class="nb"&gt;mv &lt;/span&gt;e41199c7-4afd-42b0-80fd-61ee0126e19d metasploitable3-ub1404.zip
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then &lt;code&gt;unzip&lt;/code&gt; the file and enter the folder:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;metasploitable3-ub1404
&lt;span class="nb"&gt;ls&lt;/span&gt; &lt;span class="nt"&gt;-la&lt;/span&gt;                    
total 4407704
drwx------@   6 user  staff         192 Nov 30 08:50 &lt;span class="nb"&gt;.&lt;/span&gt;
drwx------@ 588 user  staff       18816 Nov 30 09:18 ..
&lt;span class="nt"&gt;-rw-r--r--&lt;/span&gt;@   1 user  staff         258 Oct 29  2020 Vagrantfile
&lt;span class="nt"&gt;-rw-r--r--&lt;/span&gt;@   1 user  staff        6367 Oct 29  2020 box.ovf
&lt;span class="nt"&gt;-rw-r--r--&lt;/span&gt;@   1 user  staff          26 Oct 29  2020 metadata.json
&lt;span class="nt"&gt;-rw-r--r--&lt;/span&gt;@   1 user  staff  2256726016 Oct 29  2020 metasploitable3-ub1404-disk001.vmdk
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next step is to convert the VirtualBox image format &lt;code&gt;.vmdk&lt;/code&gt;, into a format that UTM understands. For that we need to install &lt;code&gt;qemu&lt;/code&gt; (used by UTM behind the scenes) using &lt;code&gt;brew&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;brew &lt;span class="nb"&gt;install &lt;/span&gt;qemu
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, to convert the file just use the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;qemu-img convert &lt;span class="nt"&gt;-O&lt;/span&gt; qcow2 &lt;span class="nt"&gt;-c&lt;/span&gt; ./metasploitable3-ub1404-disk001.vmdk ./metasploitable3-ub1404-disk001.qcow2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;where &lt;code&gt;-c&lt;/code&gt; indicates the source file and &lt;code&gt;-O&lt;/code&gt; is for the output format, in this case qcow2  &lt;/p&gt;

&lt;h2&gt;
  
  
  Create the UTM VM
&lt;/h2&gt;

&lt;p&gt;The last step is to setup and run the virtual machine in UTM  &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Open UTM&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Create a new VM (button with symbol &lt;code&gt;+&lt;/code&gt;) and select "Emulate". &lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.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%2F8nh1h3vmb33v7a7n9pvu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2F8nh1h3vmb33v7a7n9pvu.png" alt="A dialog box that shows to options: Emulate and virtualize" width="800" height="899"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;3 Click on other and "Other,"&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Ft72d1acw82hpcdvhacqe.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Ft72d1acw82hpcdvhacqe.png" alt="UTM new VM: Select the OS: Windows, Linux, other" width="800" height="918"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Click on  "Skip ISO boot." &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fq6b8owrhr9mnsu1qhnzo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fq6b8owrhr9mnsu1qhnzo.png" alt="UTM new VM dialog box with Skip ISO boot" width="800" height="914"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;For hardware, leave it as is. but lower the RAM if you want, it only needs like 1024 MB (maybe less). &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.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%2F1l8wtvxw9fdp2j5otj2e.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2F1l8wtvxw9fdp2j5otj2e.png" alt="UTM new VM Hardware selection dialog box with default values except the RAM memory" width="800" height="902"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;For the rest of the options just next, next, next... until you get to the "Summary" page. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;On the summary page, select "Open vm settings" then "Save".&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fqw7ap33qglvk96ihjmwr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fqw7ap33qglvk96ihjmwr.png" alt="UTM new VM Summary page dialog box" width="800" height="902"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;A new dialog box with the settings of the VM will appear. You can change the name of the VM. &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.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%2F4fyj7fv5kwotgn81r7t8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2F4fyj7fv5kwotgn81r7t8.png" alt="UTM VM settings main dialog box where you can edit the name" width="800" height="462"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Click on the "QEMU" in the sidebar and uncheck "UEFI Boot". &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fccx1hutw6vujdx4c9a7t.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fccx1hutw6vujdx4c9a7t.png" alt="UTM VM settings QEMU menu dialog box with UEFI Boot option unchecked" width="800" height="463"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Under "Drives" section of the sidebar menu, select "IDE Drive" and delete it. &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.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%2F3q9kiwjdf84ap703ct3s.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2F3q9kiwjdf84ap703ct3s.png" alt="UTM VM settings, IDE drive section with delete and new drive buttons where you need to click highlighted" width="800" height="458"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Now in the Drive section, click on "New Drive", and then in "Import".&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fff51idcyvi7nyzorriuo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fff51idcyvi7nyzorriuo.png" alt="Dialog box that appears when you click on New Drive with the button Import highlighted" width="800" height="288"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Select the &lt;code&gt;.qcow2&lt;/code&gt; file you created earlier with the &lt;code&gt;qemu-img&lt;/code&gt; command&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Click Save and start the VM.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.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%2F3p0gr9clc8073nstm9r0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2F3p0gr9clc8073nstm9r0.png" alt="Item that appears in the list of VM" width="502" height="162"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you need to login you can use username &lt;code&gt;vagrant&lt;/code&gt; and &lt;code&gt;vagrant&lt;/code&gt; also as password.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bonus: Metasploitable 2
&lt;/h2&gt;

&lt;p&gt;Now that you have everything in place installing metasploitable2, another Linux machine, is very simple&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Go to &lt;a href="https://sourceforge.net/projects/metasploitable/" rel="noopener noreferrer"&gt;https://sourceforge.net/projects/metasploitable/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;And download the &lt;code&gt;.zip&lt;/code&gt; file&lt;/li&gt;
&lt;li&gt;Unzip.&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Use &lt;code&gt;qemu-img&lt;/code&gt; convert&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;Metasploitable2-Linux
qemu-img convert &lt;span class="nt"&gt;-O&lt;/span&gt; qcow2 Metasploitable.vmdk Metasploitable.qcow2
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Repeat the same steps in UTM as for installing the Metasploitable 3 but now, when you create the new drive, use the &lt;code&gt;Metasploitable.qcow2&lt;/code&gt; file.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;To login you can use &lt;code&gt;msfadmin&lt;/code&gt; for both username and password.&lt;/p&gt;

&lt;p&gt;In both machines to get the IP addresses, just run the command&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.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%2Fv7rk1rotyhgphnv3wllw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fv7rk1rotyhgphnv3wllw.png" alt=" " width="800" height="485"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;Now you can play around with the VM.&lt;/p&gt;

&lt;p&gt;If you found this article interesting and &lt;strong&gt;you would like me to write some more articles exploiting the vulnerabilities&lt;/strong&gt;, just drop a comment below.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;EOF&lt;/code&gt;&lt;/p&gt;

</description>
      <category>java</category>
      <category>discuss</category>
    </item>
    <item>
      <title>How to write a good README</title>
      <dc:creator>merlos</dc:creator>
      <pubDate>Mon, 17 Oct 2022 04:33:59 +0000</pubDate>
      <link>https://dev.to/merlos/how-to-write-a-good-readme-bog</link>
      <guid>https://dev.to/merlos/how-to-write-a-good-readme-bog</guid>
      <description>&lt;p&gt;&lt;strong&gt;The README file is the one-stop documentation file&lt;/strong&gt;. Usually, it is not only the first file any person will read when reaching your project for the first time, but also it is the key document for your recurring visitors.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why is important the README?
&lt;/h2&gt;

&lt;p&gt;A few weeks back I had to install an open source project in my computer. It was the first time I was interacting with the project and experience was horrible, something that should have taken me no more than one or two hours to do, took me two days, and the main reason it took me so long was because it had a README file that could be improved to help developers new to the project to have a better first interaction. &lt;/p&gt;

&lt;p&gt;Integrate and use open source solutions, library or tools in our own projects is the day-to-day for many developers, and the starting point for this tasks is arguably the README file.  So a good README, is as indispensable for an open source project as it is the quality of the code. &lt;/p&gt;

&lt;h2&gt;
  
  
  Who is your audience?
&lt;/h2&gt;

&lt;p&gt;Before digging into what are good contents and how to write a README file, let's dig into who's going to read this document.&lt;/p&gt;

&lt;p&gt;To write a good README &lt;strong&gt;one of the keys is to think about the reader&lt;/strong&gt;. Who is this file for? Who is your audience? In this regard, I like to classify them in three categories. &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;End users&lt;/strong&gt;. They are the actual users of your application. These may also be business analysts that are seeking for a solution. They may not have a strong technical knowledge and they are more worried about the functional aspects of your solution and not so much about the technology implementation.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Technical users&lt;/strong&gt;. These are people that have technical background and are going to install or setup the project in their own environment. You can consider them also as some kind of integrators. They are going to take your project and integrate it into the project they are working on. They care about the technical aspects, but just as a user, that is, they do not care too much about how it is implemented, but more about the functionality offered. For example, if your project exposes an API or it is a library, they want to use the API/library, but they are not interested in learning about all the implementation details. &lt;/p&gt;

&lt;p&gt;Note that depending on the project type, sometimes the &lt;em&gt;end user&lt;/em&gt; and the &lt;em&gt;technical user&lt;/em&gt; may be the same target audience. For example, if your project is a Javascript library such as React JS, your end user is also, most of the time, the technical user, a developer. However, if your repository is an iOs application, your end user - someone with an iPhone who will use App Store - is not necessarily the same as your technical user - someone that wants to install the app using Xcode.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Contributors&lt;/strong&gt;. They are people you are going to interact with somewhat because they go one step beyond in their involvement with your project. For example, a contributor can be a technical user that needs some support to install the solution, someone that wants to report a bug or suggest a new feature, someone that wants to submit a pull request with an enhancement, or someone that wants to support economically the project. As you can see, this is the most diverse group, but including all of them in one group keeps things simple.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  README format and writing style
&lt;/h2&gt;

&lt;p&gt;Although README files are plain text files because most of the source code hostings such as &lt;a href="https://github.com" rel="noopener noreferrer"&gt;Github&lt;/a&gt;, &lt;a href="https://gitlab.com/" rel="noopener noreferrer"&gt;GitLab&lt;/a&gt; or &lt;a href="https://azure.microsoft.com/en-us/products/devops/repos/?nav=min" rel="noopener noreferrer"&gt;Azure Repos&lt;/a&gt; support the &lt;a href="https://en.wikipedia.org/wiki/Markdown" rel="noopener noreferrer"&gt;Markdown format&lt;/a&gt;. Because of that, most of the README files you will see in the wild are written using the &lt;a href="https://www.markdownguide.org/basic-syntax" rel="noopener noreferrer"&gt;Markdown syntax&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;This text format is pretty simple but rich enough for having a nice output. It supports headings, bold, italic, bulleted lists, numbered lists, code blocks, links, etc. Indeed, behind the scenes, this blog post is written in Markdown too. &lt;/p&gt;

&lt;p&gt;Quick example of Markdown:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;
&lt;span class="gh"&gt;# Heading 1&lt;/span&gt;

Preprending a &lt;span class="sb"&gt;`#`&lt;/span&gt; at the beginning of the first 
line of a paragraph converts it into a heading 
1 (biggest font heading).

&lt;span class="gu"&gt;## Heading 2&lt;/span&gt;

Two &lt;span class="sb"&gt;`#`&lt;/span&gt; is for heading 2. And so on so forth till 6.

To set a text in &lt;span class="ge"&gt;*bold*&lt;/span&gt; just enclose it 
in asterisks. For _italic_ use the underscore. 

Markdown also supports &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;links&lt;/span&gt;&lt;span class="p"&gt;](&lt;/span&gt;&lt;span class="sx"&gt;http:/dev.to/merlos&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Based on the axiom &lt;em&gt;"&lt;a href="https://www.nngroup.com/articles/how-users-read-on-the-web/" rel="noopener noreferrer"&gt;people don't read, they scan&lt;/a&gt;"&lt;/em&gt;, the proper use of Markdown will allow you to give the document some visual structure and help users scan the contents of the file.&lt;/p&gt;

&lt;p&gt;By setting a structure (using headers, lists, paragraphs) you are helping you users to quickly find the information they are seeking. &lt;/p&gt;

&lt;p&gt;For example, a developer found your project while he was in the subway coming back home, because he was on the phone he starred it and a few days later came back to install it. Some weeks later he found a bug, and he wanted to report it. By adding headings - that is structure - to your README - he will have it much easier to find the particular section he is interested in.&lt;/p&gt;

&lt;p&gt;Furthermore, to &lt;strong&gt;adapt the text to the way we read online&lt;/strong&gt;, i.e. scanning, searching for key words, etcetera, you can follow some basic principles for &lt;a href="https://www.usability.gov/how-to-and-tools/methods/writing-for-the-web.html" rel="noopener noreferrer"&gt;writing for the web&lt;/a&gt;, like the following:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Use short paragraphs&lt;/strong&gt;. Using around 3 to 5 lines is a good rule of thumb. Each paragraph should have only one concept. This will help scanning.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Use bulleted or numbered list&lt;/strong&gt; instead of comma separated lists. This list of basic rules is na example. Again this helps scanning.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;a href="https://www.smashingmagazine.com/2012/06/links-should-never-say-click-here/" rel="noopener noreferrer"&gt;Never ever use &lt;code&gt;click here&lt;/code&gt;&lt;/a&gt;&lt;/strong&gt; for a link, use some meaningful text instead. Among other  reasons, using &lt;a href="https://www.lamar.edu/web-communication/resources/avoid-using-click-here.html" rel="noopener noreferrer"&gt;click here&lt;/a&gt; forces users to read the context around the link, whereas a more appropriate text, will explain the reader &lt;a href="http://stephanieleary.com/2015/05/why-click-here-is-a-terrible-link-and-what-to-write-instead/" rel="noopener noreferrer"&gt;why you shall never use click here&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Highlight key words or sentences paragraphs&lt;/strong&gt; with bold. Avoid using underline, because it may be confused with a link.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Start with the most important information&lt;/strong&gt; in each paragraph. &lt;a href="https://www.aresearchguide.com/inverted-pyramid-structure-in-writing.html" rel="noopener noreferrer"&gt;Use inverted pyramid structure&lt;/a&gt;** in your writing. Start with the content that is most important to your audience, and then provide additional details.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  README contents
&lt;/h2&gt;

&lt;p&gt;Ok, now that we know who are we writing for and good practices about how to give structure and form to the file, let's see some suggested contents for the README. &lt;/p&gt;

&lt;p&gt;The structure presented here follows the natural way of interacting with your project:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;First we will shortly &lt;strong&gt;explain what it is the project about&lt;/strong&gt;, &lt;/li&gt;
&lt;li&gt;then, we will continue on &lt;strong&gt;how to install and how to get started with it&lt;/strong&gt; and,&lt;/li&gt;
&lt;li&gt;finally, we will provide the reader &lt;strong&gt;how to get involved&lt;/strong&gt;, how to collaborate.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This structure follows the level of involvement with your project it is expected from each of the categories of users we have presented. End user just wants to learn about the project.&lt;/p&gt;

&lt;p&gt;Note that some sections may not fit your project in particular or you may prefer to label them differently, but in any case the three level structure above will apply for sure.&lt;/p&gt;

&lt;p&gt;Let's start with the sections: &lt;/p&gt;

&lt;h3&gt;
  
  
  Overview
&lt;/h3&gt;

&lt;p&gt;Here you want to &lt;strong&gt;briefly introduce your project&lt;/strong&gt;. It should not be more than two or three paragraphs. Think what you need to tell to someone that is looking at your project for the first time. The main audience for this section are your &lt;em&gt;end users&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;After this short intro, you may include links to the website, wiki page with further explanation and/or a demo for those that are interested in getting more about your project.&lt;/p&gt;

&lt;p&gt;Finally, you may want to list some of the technologies, frameworks that you are using or supporting (if it is not obvious). This piece of info is interesting for the &lt;em&gt;technical users&lt;/em&gt; that may need to evaluate if it fits the architecture of their project or organization.&lt;/p&gt;

&lt;p&gt;Here is an example of the React JS project (in Markdown)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;React is a JavaScript library for building user interfaces.
&lt;span class="p"&gt;
1.&lt;/span&gt; Declarative: React makes it painless to create interactive UIs. Design simple views for each state in your application, and React will efficiently update and render just the right components when your data changes. Declarative views make your code more predictable, simpler to understand, and easier to debug.
&lt;span class="p"&gt;2.&lt;/span&gt; Component-Based: Build encapsulated components that manage their own state, then compose them to make complex UIs. Since component logic is written in JavaScript instead of templates, you can easily pass rich data through your app and keep the state out of the DOM.
&lt;span class="p"&gt;3.&lt;/span&gt; Learn Once, Write Anywhere: We don't make assumptions about the rest of your technology stack, so you can develop new features in React without rewriting existing code. React can also render on the server using Node and power mobile apps using &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;React Native&lt;/span&gt;&lt;span class="p"&gt;](&lt;/span&gt;&lt;span class="sx"&gt;).&lt;/span&gt;

&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;Learn how to use React in your project&lt;/span&gt;&lt;span class="p"&gt;](&lt;/span&gt;&lt;span class="sx"&gt;).&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;As you can see, first the project is showcased and at the end, you get a link to more info. In this case, the main audience are developers, and therefore &lt;em&gt;end users&lt;/em&gt; and &lt;em&gt;technical users&lt;/em&gt; are the same. &lt;/p&gt;

&lt;h3&gt;
  
  
  Install
&lt;/h3&gt;

&lt;p&gt;At this point, you got enough attention from the README reader, so he wants to go one step beyond and try it.&lt;/p&gt;

&lt;p&gt;Here you have to &lt;strong&gt;expose the steps to install your stuff&lt;/strong&gt;. For example for a NodeJS application, usually you will instruct something like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone http://url-to-my-repo
npm &lt;span class="nb"&gt;install
&lt;/span&gt;npm start
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or for a python library&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;your-library-name
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and so on so forth.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;PRO Tip:&lt;/strong&gt; In Markdown you can enclose code blocks with three apostrophes. If you add the name of the language after the first set of three apostrophes (for instance &lt;code&gt;ruby&lt;/code&gt;, &lt;code&gt;javascript&lt;/code&gt;, &lt;code&gt;typescript&lt;/code&gt;, &lt;code&gt;swift&lt;/code&gt;, &lt;code&gt;bash&lt;/code&gt;) when rendered, syntax highlighting will be applied. &lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2F2hhyfbslnq0dnug7bh5f.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2F2hhyfbslnq0dnug7bh5f.png" alt="Markdown for the javascript that is displayed after the text Is rendered below" width="596" height="146"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Is rendered:&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="c1"&gt;// This is my Javascript code&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;a&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;b&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;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;Note that in this case you are assuming that the reader has the package managers, &lt;code&gt;npm&lt;/code&gt; or &lt;code&gt;pip&lt;/code&gt;, installed on his system, which may not be the case. So, &lt;strong&gt;think about specifying the pre-requisites needed before attempting to install your project&lt;/strong&gt;. Just providing a link to the install page of each pre-requirement may be a great help for your reader. In the NodeJS example above:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;  To install this application you need 
  (Node JS 16.0 or above)[https://nodejs.org/en/download/]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Usage / Getting started
&lt;/h3&gt;

&lt;p&gt;Now that the reader has your project in his system, it is time to showcase the superpowers he can do now thanks to your stuff. &lt;/p&gt;

&lt;p&gt;In getting started you can either include some basic instructions inline or point to a more rich documentation.&lt;/p&gt;

&lt;p&gt;The goal is to &lt;strong&gt;guide the reader in what to do once he has just installed&lt;/strong&gt; your project in his environment.&lt;/p&gt;

&lt;h3&gt;
  
  
  Documentation
&lt;/h3&gt;

&lt;p&gt;In addition to the basic first steps/getting started the reader may want to dive into all the functionality of the project. It may depend on the kind of project:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;For an application it may describe how to use it, the options, how to set it up for different use cases. &lt;/li&gt;
&lt;li&gt;For a library, framework it may describe API, methods, classes, or some advanced examples.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Some additional documentation you may think about are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Deployment good practices. How to deploy it in a production environment.&lt;/li&gt;
&lt;li&gt;Security guidelines. How to harden any installation to avoid any cybersecurity issue. &lt;/li&gt;
&lt;li&gt;Troubleshooting.&lt;/li&gt;
&lt;li&gt;etc.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Depending on how you structure your documentation and your README you may merge this section with the &lt;em&gt;Getting started&lt;/em&gt; one. &lt;/p&gt;

&lt;h3&gt;
  
  
  Development
&lt;/h3&gt;

&lt;p&gt;From now on, this and the following sections will be for the readers that get into the nitty-gritty of your project or that want to become an active member of the community. Within the classification of potential readers are the ones that we called the contributors.&lt;/p&gt;

&lt;p&gt;This development section is for setting up the environment in &lt;em&gt;dev mode&lt;/em&gt;. What are the tools that you need and how to run the project in debug mode, run the unit testing, etc.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Example of running the automated unit test suite&lt;/span&gt;
npm &lt;span class="nb"&gt;test&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Contributing
&lt;/h3&gt;

&lt;p&gt;This section is for providing any additional information for the reader that wants to really contribute. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How to report a bug&lt;/li&gt;
&lt;li&gt;Code of conduct &lt;/li&gt;
&lt;li&gt;Coding Style guide&lt;/li&gt;
&lt;li&gt;How to make a pull request (PR)&lt;/li&gt;
&lt;li&gt;How to get support&lt;/li&gt;
&lt;li&gt;How to make a donation&lt;/li&gt;
&lt;li&gt;How to contact for commercial support&lt;/li&gt;
&lt;li&gt;etc.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You may want to add part of this documentation in a separate file. For example, &lt;a href="https://docs.github.com/en/communities/setting-up-your-project-for-healthy-contributions/adding-a-code-of-conduct-to-your-project" rel="noopener noreferrer"&gt;GitHub allows you to set up the  &lt;code&gt;CODE_OF_CONDUCT.md&lt;/code&gt;&lt;/a&gt; and &lt;a href="https://docs.github.com/en/communities/setting-up-your-project-for-healthy-contributions/about-community-management-and-moderation" rel="noopener noreferrer"&gt;other files&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Acknowledgements
&lt;/h3&gt;

&lt;p&gt;It is a good practice to &lt;strong&gt;acknowledge those who have been &lt;em&gt;inspiration&lt;/em&gt; of your work&lt;/strong&gt; (other repos, other projects) or &lt;strong&gt;mention those key contributors&lt;/strong&gt; of the project, that is, those that have added new features, submitted pull requests, fixed bugs, etc.&lt;/p&gt;

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

&lt;p&gt;The last section of the README typically is reserved for the copyright and license.&lt;/p&gt;

&lt;p&gt;Though, at a first glance, you may think that this is not important, the truth is that it setting up a &lt;strong&gt;license is key as it helps other developers to understand the limits of the use&lt;/strong&gt; of your software.&lt;/p&gt;

&lt;p&gt;Here you have a list of &lt;a href="https://opensource.org/licenses" rel="noopener noreferrer"&gt;open source licenses&lt;/a&gt;. You should have a rough idea of what each license means. Personally, I usually choose between GPL3 and MIT.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://opensource.org/licenses/MIT" rel="noopener noreferrer"&gt;MIT&lt;/a&gt; is the simplest license one, more or less it says: you can do whatever you want with this piece of code. Do it at your own risk and do not suit me. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://opensource.org/licenses/gpl-license" rel="noopener noreferrer"&gt;GPL&lt;/a&gt;, is a &lt;a href="https://en.wikipedia.org/wiki/Copyleft" rel="noopener noreferrer"&gt;copyleft license&lt;/a&gt;. It is a more restrictive license than the MIT as it forces any contribution or customization of the code to be publicly released, as well as to be distributed under the same GPL license. It is less attractive for a commercial usage, but better for the overall community as any contribution reverts back to the community. For example the &lt;a href="https://www.kernel.org/doc/html/latest/process/license-rules.html" rel="noopener noreferrer"&gt;GNU/Linux kernel&lt;/a&gt; is distributed under this license. &lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In this section of the README, you don't need to add the whole text of the license, just the banner, but usually, you should include a copy of the whole license in the file &lt;code&gt;LICENSE&lt;/code&gt; or &lt;code&gt;LICENSE.md&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Extra balls
&lt;/h2&gt;

&lt;p&gt;A couple of things that you can add to your project README are images and status badges.&lt;/p&gt;

&lt;h3&gt;
  
  
  Images
&lt;/h3&gt;

&lt;p&gt;As it was mentioned earlier, README files generally are written in Markdown. This language, allows you to link images within that will be displayed once the Markdown is rendered. &lt;/p&gt;

&lt;p&gt;In particular there are two cases which this may be useful:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;To make it look cooler. For example adding a logo at the beginning of the readme, makes it look good. It gives a good first impression.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Showcasing / Providing a demo. An image is 1,000 words worth. You can record a simple animated GIF and showcase key features of your project helping the reader to grasp what's your project about with less effort.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Status badges
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.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%2F7br0d13rgvk2id0env0z.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2F7br0d13rgvk2id0env0z.png" alt="A bunch of status badges from a GitHub repo" width="800" height="63"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Another "cool" thing you can add in your README file is a status badge. A status badge displays what is the status of a particular aspect of your repo, it can be if the unit testings are passing failing, if your pipelines are working, what is the latest version released, the code coverage, and a long etcetera.&lt;/p&gt;

&lt;p&gt;It gives a snapshot to your visitors in a nutshell some indicators of the project.&lt;/p&gt;

&lt;p&gt;You can check the &lt;a href="https://github.com/badges/shields" rel="noopener noreferrer"&gt;badges/shields repo&lt;/a&gt; to add some badges to your project.&lt;/p&gt;

&lt;p&gt;The only drawback of using images and the badges in the README is that they will not be rendered in a simple text editor, but  you can ignore it as most of the time this file will be displayed either in the repo website or in a &lt;em&gt;developer friendly editor&lt;/em&gt; which usually support Markdown rendering.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;If you are working in an Open Source project, the &lt;strong&gt;README file is a key one-stop document&lt;/strong&gt; that can boost the developer experience.&lt;/p&gt;

&lt;p&gt;To write a good readme you need to &lt;strong&gt;keep in mind the types of audience&lt;/strong&gt; that will read the file: end-users, technical users and contributors. &lt;/p&gt;

&lt;p&gt;You should &lt;strong&gt;pay attention on how people read on the web&lt;/strong&gt;, helping them to scan your README using Markdown, and the good practices for writing for the web such as short paragraphs, lists and the inverted pyramid writing schema.&lt;/p&gt;

&lt;p&gt;The contents of the README should &lt;strong&gt;follow a structure&lt;/strong&gt; that first introduces the project, then explains how install and  use it and, finally, explains how to get involved in the project as contributor.&lt;/p&gt;

&lt;p&gt;I hope you enjoyed the article. One final question. &lt;strong&gt;What is the best or your favorite README file?&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>github</category>
      <category>git</category>
      <category>writing</category>
      <category>documentation</category>
    </item>
    <item>
      <title>Write code for people: Dos and don'ts to improve your React code</title>
      <dc:creator>merlos</dc:creator>
      <pubDate>Sat, 18 Jun 2022 20:43:50 +0000</pubDate>
      <link>https://dev.to/merlos/write-code-for-people-dos-and-donts-to-improve-your-react-code-59j7</link>
      <guid>https://dev.to/merlos/write-code-for-people-dos-and-donts-to-improve-your-react-code-59j7</guid>
      <description>&lt;p&gt;During the last three years I have reviewed many pull requests of React applications. I consistently observed in different developers some practices that could be improved just by keeping in mind the following sentence:&lt;/p&gt;

&lt;blockquote&gt;
&lt;h3&gt;
  
  
  I am writing code for other people.
&lt;/h3&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Why write code for humans?
&lt;/h2&gt;

&lt;p&gt;Either if you are writing enterprise applications or creating an open source project, &lt;strong&gt;your code is going to be read and maintained by humans&lt;/strong&gt;. This is a &lt;strong&gt;mantra&lt;/strong&gt; you must always keep in mind. &lt;/p&gt;

&lt;p&gt;Some readers may pose that code is run on machines, so if the code is not efficient you cannot consider it good code. That's a good point, but if the code is readable bot not efficient, it will be easier to understand where to change it to make it faster.&lt;/p&gt;

&lt;p&gt;Good code that is developer-friendly has several advantages.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;It is more pleasant to read&lt;/strong&gt; and easier to understand.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Reduces onboarding time&lt;/strong&gt;. Development teams sometimes need more capacity, so new staff or consultants may join the team. On those cases, human centered code makes on boarding much smoother and less time costly.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Takes less time to maintain&lt;/strong&gt;. It is very common to spend a lot of time in an application/library, then you release it, and, for a while, you don't modify it. One day, after some months you need to change something and... guess what, now you don't remember what you did, so you need to &lt;strong&gt;read&lt;/strong&gt; your own code. &lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Dos and don'ts to make : Recipes / Tips
&lt;/h2&gt;

&lt;p&gt;We'll start with some general JavaScript tips and then move to more specific tips for React.&lt;/p&gt;

&lt;h3&gt;
  
  
  Do use significant names in variables.
&lt;/h3&gt;

&lt;p&gt;Whenever you create a variable ask yourself: Does the name of a variable convey what is the content of the variable?&lt;/p&gt;

&lt;p&gt;In general, follow these rules:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Use the &lt;strong&gt;shortest&lt;/strong&gt; name,&lt;/li&gt;
&lt;li&gt;But also be as &lt;strong&gt;precise&lt;/strong&gt; as possible.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt; &lt;span class="c1"&gt;//  ❌  Not good&lt;/span&gt;
 &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;list&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="s1"&gt;USA&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;India&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;Peru&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;Spain&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
 &lt;span class="nx"&gt;list&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

 &lt;span class="c1"&gt;//  ✅  Better&lt;/span&gt;
 &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;countries&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="s1"&gt;USA&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;India&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;Peru&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;Spain&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
 &lt;span class="nx"&gt;countries&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;country&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;country&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In general do not use generic names such as &lt;code&gt;list&lt;/code&gt;, &lt;code&gt;item&lt;/code&gt;, they are short but not very meaningful. A list can contain anything and it will not give any clue about its contents to the reader of your code. A more precise name, such as &lt;code&gt;countries&lt;/code&gt;in the example above, is better. &lt;/p&gt;

&lt;p&gt;Also, I personally prefer to avoid acronyms in variables as they may be harder to understand for junior/new developers.&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="c1"&gt;//  ❌  Not that good&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handleClk&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;e&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;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;User clicked the button&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&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="c1"&gt;//  ✅  Better&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handleClick&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;event&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;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;User clicked the button&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This "rule" makes the code more verbose but also easier to understand.&lt;/p&gt;

&lt;p&gt;In other languages like Python it is common to use acronmys/abreviated versions - for example when importing modules - which is somewhat fine as these are widely spread conventions across existing documentation, examples and even novice learners.&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="c1"&gt;# Typical way of renaming modules in python
&lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;numpy&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;np&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;tensorflow&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;tf&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;seaborn&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;sns&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The rational of this convention is to type less, be more productive (Now with autocomplete of the editors is no longer true), make the code less verbose and "faster" to read for expert eyes.&lt;/p&gt;

&lt;p&gt;Following this idea, there may be cases in JavaScript in which you use shorter versions, 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="c1"&gt;// doc instead of document &lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;doc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createNewDocument&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As summary, do give some thought when naming variables in your code. I believe this is one of the hardest part of software development and it differentiates good developers from bad developers.&lt;/p&gt;

&lt;h3&gt;
  
  
  Do use consistent names across the app.
&lt;/h3&gt;

&lt;p&gt;Give good names to variables is not enough, they have to be consistent across the whole react app. &lt;/p&gt;

&lt;p&gt;To solve complex problems we create small independent logic units. We follow the strategy of &lt;em&gt;divide and conquer&lt;/em&gt; to make it easier. We implement components in an isolated way, they have some inputs and throw some output. However, we should not forget these units belong to a higher order organism, your application.&lt;/p&gt;

&lt;p&gt;Ask yourself upon creating a variable, function, component or a file, if its name is consistent with the names already used in the application. 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="c1"&gt;//  ❌  Not that good&lt;/span&gt;
  &lt;span class="c1"&gt;//File1.jsx&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;sectorsData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useSelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;sectorsSelector&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="c1"&gt;//File2.jsx&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;sectorsList&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useSelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;sectorsSelector&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


   &lt;span class="c1"&gt;//  ✅  Better&lt;/span&gt;
  &lt;span class="c1"&gt;//File 1&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;sectors&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useSelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;sectorsSelector&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="c1"&gt;//File 2&lt;/span&gt;
   &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;sectors&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useSelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;sectorsSelector&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For files:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;/redux/constants/&amp;lt;entity&amp;gt;Constants.js&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/redux/actions/&amp;lt;entity&amp;gt;Actions.js&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/redux/selectors/&amp;lt;entity&amp;gt;Selector.js&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;etc..&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Do follow the &lt;em&gt;Don't repeat yourself&lt;/em&gt; (DRY) principle.
&lt;/h3&gt;

&lt;p&gt;That is, if you see that your are repeating similar code or logic in two places, refactor that code to use a function, component, etc.&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="c1"&gt;//  ❌  Not that good&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;getPdfName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;country&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;now&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Date&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;pdfName&lt;/span&gt; &lt;span class="o"&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;country&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;now&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getFullYear&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;now&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getMonth&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;now&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getDay&lt;/span&gt;&lt;span class="p"&gt;()}&lt;/span&gt;&lt;span class="s2"&gt;.pdf`&lt;/span&gt; 
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;pdfName&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;getExcelName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;country&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;now&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Date&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;xlsName&lt;/span&gt; &lt;span class="o"&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;country&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;now&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getFullYear&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;now&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getMonth&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;now&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getDay&lt;/span&gt;&lt;span class="p"&gt;()}&lt;/span&gt;&lt;span class="s2"&gt;.xls`&lt;/span&gt; 
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;xlsName&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;//  ✅  Better&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;buildFilename&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;extension&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;now&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;name&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;now&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getFullYear&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;now&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getMonth&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;now&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getDay&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;extension&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;gePdfName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;country&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="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;buildFileName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;country&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.pdf&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;getExcelName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;country&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="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;builExcelName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;country&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.xls&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;h3&gt;
  
  
  Do keep files short
&lt;/h3&gt;

&lt;p&gt;I use 200 lines as a benchmark. Specially when we talk about React components, if you have a file that has more than 200 lines, ask yourself if you can split it in smaller components.&lt;/p&gt;

&lt;p&gt;Also, if the large majority of your component code is for fetching and processing data, think about moving that code to support/helper files. For example, you can create a folder &lt;code&gt;/src/lib/&lt;/code&gt; and keep there your utility functions.&lt;/p&gt;

&lt;p&gt;Also, it is not advisable to have more than a certain amount of files (~10-20) in the same folder. Structuring the folder into sub-folders makes the project more readable. &lt;/p&gt;

&lt;h3&gt;
  
  
  Do create a compact code.
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;  &lt;span class="c1"&gt;// ❌ Not that good&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handleClick&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;newValue&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;valueAsString&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;newValue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toString&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;onClick&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;valueAsString&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;

  &lt;span class="c1"&gt;// ✅ Better&lt;/span&gt;
  &lt;span class="c1"&gt;// Previous code in 1 single line.&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handleClick&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;newValue&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;onClick&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nf"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;newValue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Although compact code as a general principle is good, it may sometimes obfuscate what is the code actually doing. So:&lt;/p&gt;

&lt;h3&gt;
  
  
  Do document your code.
&lt;/h3&gt;

&lt;p&gt;Specially for helper functions the interface needs to be clear.&lt;/p&gt;

&lt;p&gt;Do include comments for pieces of code that may not be very obvious. 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="c1"&gt;// ❌ Not that good&lt;/span&gt;
  &lt;span class="nx"&gt;editor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;countWorths&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;nodes&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;content&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;editor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;serialize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;nodes&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;match&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;\b[&lt;/span&gt;&lt;span class="sr"&gt;-?(&lt;/span&gt;&lt;span class="se"&gt;\w&lt;/span&gt;&lt;span class="sr"&gt;+)?&lt;/span&gt;&lt;span class="se"&gt;]&lt;/span&gt;&lt;span class="sr"&gt;+&lt;/span&gt;&lt;span class="se"&gt;\b&lt;/span&gt;&lt;span class="sr"&gt;/gi&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;length&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="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;// ✅ Better&lt;/span&gt;
  &lt;span class="cm"&gt;/**
   * Counts the number of words within the passed nodes
   *
   * @param {Node} SlateJS nodes
   * @returns {integer} Number of words
   */&lt;/span&gt;
  &lt;span class="nx"&gt;editor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;countWords&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;nodes&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;content&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;editor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;serialize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;nodes&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// one string with all node contents&lt;/span&gt;
    &lt;span class="c1"&gt;//Extracts number of words with the regex unless empty string (0)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;match&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;\b[&lt;/span&gt;&lt;span class="sr"&gt;-?(&lt;/span&gt;&lt;span class="se"&gt;\w&lt;/span&gt;&lt;span class="sr"&gt;+)?&lt;/span&gt;&lt;span class="se"&gt;]&lt;/span&gt;&lt;span class="sr"&gt;+&lt;/span&gt;&lt;span class="se"&gt;\b&lt;/span&gt;&lt;span class="sr"&gt;/gi&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;length&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="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Do use linters and code formatters
&lt;/h3&gt;

&lt;p&gt;&lt;em&gt;Linters&lt;/em&gt; are code analyzers that provide estilistic suggestions. The most widely spread in Javascript is &lt;a href="https://eslint.org/" rel="noopener noreferrer"&gt;esLint&lt;/a&gt;. Setting it up in a react application is pretty easy.&lt;/p&gt;

&lt;p&gt;The other tool that will make your code more readable and save you time is a code formatter. It will indent and break the lines of your code. It will really make your code much easier to read and will save you time. In JavaScript we are lucky, we have  &lt;a href="https://prettier.io/" rel="noopener noreferrer"&gt;prettier&lt;/a&gt; that formats your code on save. &lt;/p&gt;

&lt;h3&gt;
  
  
  Do use &lt;code&gt;on&lt;/code&gt; and &lt;code&gt;handle&lt;/code&gt; as prefix on event props and handlers
&lt;/h3&gt;

&lt;p&gt;This is a &lt;em&gt;de facto&lt;/em&gt; standard on React naming conventions. It is widely used on the official react documentation and gives the reader a cue on what is the prop for.&lt;/p&gt;

&lt;p&gt;For event props use &lt;code&gt;on&lt;/code&gt; as prefix (for instance, &lt;code&gt;onClick&lt;/code&gt;, &lt;code&gt;onSubmit&lt;/code&gt;, &lt;code&gt;onBlur&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;For the handlers of those events use the prefix &lt;code&gt;handle&lt;/code&gt; (for instance, &lt;code&gt;handleClick&lt;/code&gt;, &lt;code&gt;handleSubmit&lt;/code&gt;, &lt;code&gt;handleBlur&lt;/code&gt;).&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="c1"&gt;// ❌ Not that good&lt;/span&gt;
    &lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;SendEmailForm&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;sendEmail&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="c1"&gt;/// process / validate email form&lt;/span&gt;
    &lt;span class="nf"&gt;sendEmailWasClicked&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;sendEmail&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nf"&gt;sendEmail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;formFields&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="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;form&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
       &lt;span class="p"&gt;...&lt;/span&gt;
       &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt; &lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;submit&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;sendEmailWasClicked&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;Send&lt;/span&gt; &lt;span class="nx"&gt;email&lt;/span&gt;
       &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/input&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;       &lt;span class="p"&gt;...&lt;/span&gt;
     &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/form&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;// ✅ Better&lt;/span&gt;
    &lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;SendEmailForm&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;onSendEmail&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

      &lt;span class="nf"&gt;handleSubmit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// process email info&lt;/span&gt;
        &lt;span class="c1"&gt;// ...&lt;/span&gt;
        &lt;span class="c1"&gt;//&lt;/span&gt;
        &lt;span class="nx"&gt;onSendEmail&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nf"&gt;onSendEmail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="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="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;form&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
         &lt;span class="p"&gt;...&lt;/span&gt; 
         &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt; &lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;submit&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;handleSubmit&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;Send&lt;/span&gt; &lt;span class="nx"&gt;email&lt;/span&gt;
         &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/input&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;         &lt;span class="p"&gt;...&lt;/span&gt;
     &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/form&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="p"&gt;)&lt;/span&gt;

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

&lt;/div&gt;



&lt;h3&gt;
  
  
  Do not add handler code in the render
&lt;/h3&gt;

&lt;p&gt;In my experience it makes the code harder to read when the logic of the handler is within the render.&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="c1"&gt;// ❌ Not that good&lt;/span&gt;
  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt; &lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="o"&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="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="o"&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;span class="nf"&gt;setError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Name is mandatory&lt;/span&gt;&lt;span class="dl"&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="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;surname&lt;/span&gt;&lt;span class="o"&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;span class="nf"&gt;setError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Name is mandatory&lt;/span&gt;&lt;span class="dl"&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="nx"&gt;onSubmit&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nf"&gt;onSubmit&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;surname&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="nx"&gt;Submit&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/button&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;
    &lt;span class="c1"&gt;// ✅ Better&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handleOnSubmit&lt;/span&gt; &lt;span class="o"&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="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&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;span class="nf"&gt;setError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Name is mandatory&lt;/span&gt;&lt;span class="dl"&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="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;surname&lt;/span&gt; &lt;span class="o"&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;span class="nf"&gt;setError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Surname is mandatory&lt;/span&gt;&lt;span class="dl"&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="nx"&gt;onSubmit&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nf"&gt;onSubmit&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;surname&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="k"&gt;return&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;lt;&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt; &lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;handleOnSubmit&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;Submit&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/button&lt;/span&gt;&lt;span class="err"&gt;&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;One liners may be ok to make code more compact.&lt;br&gt;
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="c1"&gt;// ✅ This is ok&lt;/span&gt;
    &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt; &lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="o"&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="nx"&gt;onCancel&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nf"&gt;onCancel&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;Cancel&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/button&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Do use &lt;code&gt;const&lt;/code&gt; by default
&lt;/h3&gt;

&lt;p&gt;Whenever you create a &lt;em&gt;variable&lt;/em&gt; use &lt;code&gt;const&lt;/code&gt; by default. Use &lt;code&gt;let&lt;/code&gt;&lt;br&gt;
only when it is going to be assigned several times. Avoid &lt;code&gt;var&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;It will save you some hard to find bugs.&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="c1"&gt;// ❌ Not that good&lt;/span&gt;
    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;today&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;  &lt;span class="c1"&gt;// Today 99.9999999% won't be reasigned&lt;/span&gt;

    &lt;span class="c1"&gt;// ✅ Better&lt;/span&gt;
     &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;today&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note that you assign a variable when the &lt;code&gt;name&lt;/code&gt; is in front of an &lt;code&gt;=&lt;/code&gt;. So  you can modify Arrays and Objects as constants.&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="c1"&gt;// ✅ This will run &lt;/span&gt;
    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;day&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; 
    &lt;span class="nx"&gt;day&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="c1"&gt;// ❌ It will not run&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;day&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; 
    &lt;span class="nx"&gt;day&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;  &lt;span class="c1"&gt;// you cannot reasign a const&lt;/span&gt;

    &lt;span class="c1"&gt;// ✅ This will run &lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;myObject&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;a&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;prop created during assignment&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nx"&gt;myObject&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="na"&gt;b&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;object content can be modified after creation&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;animals&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="s1"&gt;dog&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;cat&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="nx"&gt;animals&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;lion&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;Only when you put a &lt;code&gt;const&lt;/code&gt; before &lt;code&gt;=&lt;/code&gt; more than once, the code won't run.&lt;/p&gt;

&lt;h3&gt;
  
  
  Do use the best maping function in arrays
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Use &lt;code&gt;map()&lt;/code&gt; for returning an array with the same number of elements.
&lt;/li&gt;
&lt;/ol&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;numbers&lt;/span&gt; &lt;span class="o"&gt;=&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="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;double&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;  &lt;span class="nx"&gt;numbers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nx"&gt;number&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;number&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="c1"&gt;// [2, 4, 6]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Use &lt;code&gt;filter()&lt;/code&gt; for returning the items that match a &lt;em&gt;criterium&lt;/em&gt;.&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;numbers&lt;/span&gt; &lt;span class="o"&gt;=&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="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;double&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;  &lt;span class="nx"&gt;numbers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nx"&gt;number&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;number&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="c1"&gt;// [2, 3]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Use &lt;code&gt;find()&lt;/code&gt; for searching the first item that matches a &lt;em&gt;cirterium&lt;/em&gt;.&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;numbers&lt;/span&gt; &lt;span class="o"&gt;=&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="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;double&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;  &lt;span class="nx"&gt;numbers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nx"&gt;number&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;number&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="c1"&gt;// [2]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Use &lt;code&gt;forEach()&lt;/code&gt; for not returing an array.&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ol&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;list&lt;/span&gt; &lt;span class="o"&gt;=&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="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; 
     &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;sum&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
     &lt;span class="nx"&gt;list&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nx"&gt;number&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;sum&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="nx"&gt;number&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// 6&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Do handle situations in which there is no value
&lt;/h3&gt;

&lt;p&gt;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="c1"&gt;// ❌ Not that good&lt;/span&gt;
  &lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;MyForm&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="nx"&gt;onSubmit&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="c1"&gt;//...&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handleOnSubmit&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;newValue&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="c1"&gt;// do whatever other transformations&lt;/span&gt;
      &lt;span class="nf"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;newValue&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;//...&lt;/span&gt;

    &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="cm"&gt;/* this assumes input handles null or empty values correctly */&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Input&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="o"&gt;=&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="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Button&lt;/span&gt; &lt;span class="nx"&gt;onSubmit&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;handleOnSubmit&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;Submit&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/Button&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;// ✅ Better&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;MyForm&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="nx"&gt;onSubmit&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="c1"&gt;//...&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handleOnSubmit&lt;/span&gt; &lt;span class="o"&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="c1"&gt;// It won't do anything BUT won't crash.&lt;/span&gt;
        &lt;span class="nx"&gt;onClick&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nf"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;values&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;//...&lt;/span&gt;

  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Example 2:&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="c1"&gt;// ❌ Not that good&lt;/span&gt;
    &lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;IndicatorsList&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="nx"&gt;sectors&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="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ul&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;sector&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;indicators&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;indicator&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;li&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;indicator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&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;indicator&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="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/&amp;gt; &lt;/span&gt;&lt;span class="se"&gt;)&lt;/span&gt;&lt;span class="err"&gt;}
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/ul&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// ✅ Better&lt;/span&gt;
    &lt;span class="c1"&gt;//It receives the indicator list&lt;/span&gt;
    &lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;IndicatorsList&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="nx"&gt;indicators&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;indicators&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;indicators&lt;/span&gt; &lt;span class="o"&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;indicators&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="p"&gt;(&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;No&lt;/span&gt; &lt;span class="nx"&gt;indicators&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/p&lt;/span&gt;&lt;span class="err"&gt;&amp;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="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ul&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;indicators&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nx"&gt;indicator&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;li&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;indicator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&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;indicator&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="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/&amp;gt; &lt;/span&gt;&lt;span class="se"&gt;)&lt;/span&gt;&lt;span class="err"&gt;}
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ul&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

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

&lt;/div&gt;



&lt;h3&gt;
  
  
  Be consistent on the order in which you write the code.
&lt;/h3&gt;

&lt;p&gt;Always follow the same order of the imports, variables and functions within the code of the components.For example, I like the folowing order:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;imports&lt;/li&gt;
&lt;li&gt;state, variables and constants &lt;/li&gt;
&lt;li&gt;
&lt;code&gt;useEffects&lt;/code&gt; &lt;/li&gt;
&lt;li&gt;effect handlers (&lt;code&gt;handleOnClick&lt;/code&gt;, etc.)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;return()&lt;/code&gt; function&lt;/li&gt;
&lt;li&gt;Prop defaults and PropTypes&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Indeed, for the imports, you may even define an actual order:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;React related stuff&lt;/li&gt;
&lt;li&gt;General such as react-router&lt;/li&gt;
&lt;li&gt;External UI related components&lt;/li&gt;
&lt;li&gt;Redux actions, selectors&lt;/li&gt;
&lt;li&gt;Hooks&lt;/li&gt;
&lt;li&gt;Custom Application UI components&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Do add validations for fields and handle form errors.
&lt;/h3&gt;

&lt;p&gt;Gererally, when you read a tutorial or watch a video that teaches react or any other library/programming language, they do not manage errors other than display a console message. Their code is simple, but in real applications user may fill unexpected data, there may be network errors, API may have bug, the user may not have permissions to access a resource, or your authentication token may have expired. Your code has to manage all these situations gracefully and display the appropriate feedback to the user so he can recover from them.&lt;/p&gt;

&lt;p&gt;Types of errors and how to manage them from the user experience and from the code point of view is something that requires a deep dive, but we will leave that for another article.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrapping up
&lt;/h2&gt;

&lt;p&gt;Always keep in mind: &lt;/p&gt;

&lt;blockquote&gt;
&lt;h3&gt;
  
  
  &lt;strong&gt;I write code for other people.&lt;/strong&gt;
&lt;/h3&gt;
&lt;/blockquote&gt;

&lt;p&gt;So always try to think if a reader would understand it. Code being consistent, using meaninful variables, document the code, and follow some wide spread conventions.  &lt;em&gt;developer (human) friendly&lt;/em&gt;  code will be much easier to maintain, less prone to errors and if a new team member joins, she/he will be on boarded and productive in less time. &lt;/p&gt;

&lt;p&gt;Note that the above mentioned dos and don'ts  are general guidelines, and some of the recommendationsmay have corner cases in which you can argue not to follow them, in those cases use your common sense.&lt;/p&gt;

</description>
      <category>react</category>
      <category>javascript</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>How to use ML5 with Nodejs and puppeteer step by step</title>
      <dc:creator>merlos</dc:creator>
      <pubDate>Wed, 11 Nov 2020 01:10:17 +0000</pubDate>
      <link>https://dev.to/merlos/how-to-use-ml5-with-nodejs-and-puppeteer-step-by-step-132e</link>
      <guid>https://dev.to/merlos/how-to-use-ml5-with-nodejs-and-puppeteer-step-by-step-132e</guid>
      <description>&lt;p&gt;In this article we are going to train and save a simple model using ML5 and NodeJS.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://ml5js.org/" rel="noopener noreferrer"&gt;ML5&lt;/a&gt; is a high level machine learning library that is very easy to use and that behind the scenes uses &lt;a href="https://www.tensorflow.org/js" rel="noopener noreferrer"&gt;TensorFlow JS&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;One limitation of ML5 is that it was developed to be used within a browser. According to the documentation ML5 will eventually natively support NodeJS, but at the moment of writing this article ml5 requires a browser to run.&lt;/p&gt;

&lt;p&gt;The thing is that because it is so easy to use you may still want to use it also in a pipeline or in a NodeJS script.&lt;/p&gt;

&lt;p&gt;Thankfully, we have &lt;a href="https://github.com/puppeteer/puppeteer" rel="noopener noreferrer"&gt;puppeteer&lt;/a&gt; to help us overcome that limitation. &lt;br&gt;
For those who do not know puppeteer, it is a headless browser based on Chromium that can be controlled programmatically using NodeJS. &lt;br&gt;
What we will do is create the a simple HTML page with the ml5 script and then call puppeteer to run it.&lt;/p&gt;

&lt;p&gt;For this article we are going to train an image classification model. We will develop it using a browser as a normal ml5 script. Then, we will just need to create a node script that will open that page in puppeteer, it will wait till the ml5 script is completed and it will download the output.&lt;/p&gt;

&lt;p&gt;Besides this approach is very simple it still may have some limitations. For example, the number of images that can be loaded on the browser is finite, specially if you have many classes and many training samples. &lt;/p&gt;

&lt;p&gt;Also, the model we will train is based in MobileNet which is a lightweight model that has low latency on mobile and embedded devices, but it may not be as accurate as you may need. &lt;/p&gt;
&lt;h2&gt;
  
  
  The ML5 script
&lt;/h2&gt;

&lt;p&gt;As example, using &lt;a href="https://en.wikipedia.org/wiki/Transfer_learning" rel="noopener noreferrer"&gt;transfer learning&lt;/a&gt;, we will train a classification model to differentiate between two types of skateboards: longboards (left) and regular street skateboards (right).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Frgc5qosmlvvdxko1eko5.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Frgc5qosmlvvdxko1eko5.jpg" alt="Alt Text" width="318" height="159"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The javascript code for training the modeñ that I will be using here is heavily based on the fantastic &lt;a href="https://www.youtube.com/watch?v=26uABexmOX4&amp;amp;feature=youtu.be&amp;amp;list=PLRqwX-V7Uu6YPSwT06y_AEYTqIwbeam3y" rel="noopener noreferrer"&gt;ML5 tutorial of The Coding Train&lt;/a&gt; by &lt;a href="https://twitter.com/shiffman" rel="noopener noreferrer"&gt;Daniel Shiffman&lt;/a&gt;.&lt;/p&gt;
&lt;h1&gt;
  
  
  Setup
&lt;/h1&gt;

&lt;p&gt;First, we initialize our project&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir &lt;/span&gt;myproject
&lt;span class="nb"&gt;cd &lt;/span&gt;my project
npm init
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When running &lt;code&gt;npm init&lt;/code&gt; we will be asked a few simple questions. Don't worry too much about what you fill, if you need to change something you can always edit &lt;code&gt;package.json&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Now let's install a couple of dependencies that we will be using. The first one is &lt;code&gt;puppeteer&lt;/code&gt;, our headless browser and the second one is &lt;code&gt;serve&lt;/code&gt;, a very simple http server. We will use it for serving the HTML file that is loaded by puppeteer.&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;puppeteer
npm &lt;span class="nb"&gt;install &lt;/span&gt;serve
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we are going to create the HTML file that will hold the script to train the model.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir &lt;/span&gt;public
&lt;span class="nb"&gt;cd &lt;/span&gt;public
&lt;span class="nb"&gt;touch &lt;/span&gt;public/index.html
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now edit the file &lt;code&gt;public/index.html&lt;/code&gt;and add some code&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="cp"&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;html&lt;/span&gt; &lt;span class="na"&gt;lang=&lt;/span&gt;&lt;span class="s"&gt;"en"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;title&amp;gt;&lt;/span&gt;Getting Started with ml5.js&lt;span class="nt"&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"viewport"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"width=device-width, initial-scale=1.0"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://unpkg.com/ml5@0.5.0/dist/ml5.min.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;Hello ml5&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
      &lt;span class="cm"&gt;/* We will add the code to train our model here */&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, let's run the server to validate it works&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;./node_modules/serve/bin/serve.js ./public/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Open your browser in &lt;a href="http://localhost:5000" rel="noopener noreferrer"&gt;http://localhost:5000&lt;/a&gt; and you should see the text &lt;em&gt;Hello ml5&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Alternatively, you can import the script using the attribute 'src' in the script tag&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;head&amp;gt;&lt;/span&gt;
...
...
&lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"script.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
...
&lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For this example, we are going to pre-load the images in the HTML, and then we will add them to the classifier. The images will go just after the &lt;code&gt;&amp;lt;body&amp;gt;&lt;/code&gt; and before the &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt;. In a more realistic environment you can &lt;a href="https://github.com/ml5js/ml5-library/issues/260" rel="noopener noreferrer"&gt;include the images dynamically&lt;/a&gt;.&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="cp"&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;html&lt;/span&gt; &lt;span class="na"&gt;lang=&lt;/span&gt;&lt;span class="s"&gt;"en"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;title&amp;gt;&lt;/span&gt;Getting Started with ml5.js&lt;span class="nt"&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"viewport"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"width=device-width, initial-scale=1.0"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://unpkg.com/ml5@0.5.0/dist/ml5.min.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
  &lt;span class="c"&gt;&amp;lt;!-- images to train the classifier --&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"./longboard1.jpg"&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"longboard1"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"./longboard2.jpg"&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"longboard2"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"./longboard3.jpg"&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"longboard3"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"./longboard4.jpg"&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"longboard4"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"./longboard5.jpg"&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"longboard5"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"./longboard6.jpg"&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"longboard6"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;

  &lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"./skateboard1.jpg"&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"skateboard1"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"./skateboard2.jpg"&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"skateboard2"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"./skateboard3.jpg"&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"skateboard3"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"./skateboard4.jpg"&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"skateboard4"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"./skateboard5.jpg"&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"skateboard5"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"./skateboard6.jpg"&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"skateboard6"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;

  &lt;span class="c"&gt;&amp;lt;!-- images to test --&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"./d.jpg"&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"longboard"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"./skateboard.jpg"&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"skateboard"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
     &lt;span class="cm"&gt;/* We will add the code to train our model here */&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, we have to write the code we will use to train the cad-longboard classifier. The steps we will follow are:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Get the classifier from the pre-trained model (MobileNet).&lt;/li&gt;
&lt;li&gt;Add the images to the classifier.&lt;/li&gt;
&lt;li&gt;Train the classifier with the new classes.&lt;/li&gt;
&lt;li&gt;Download the trained model.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Below you have the code. It is fairly commented but if you need more info you can refer to the &lt;a href="https://ml5js.org/reference/api-FeatureExtractor/" rel="noopener noreferrer"&gt;ml5.featureExtractor documentation&lt;/a&gt;.&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;&lt;/span&gt;&lt;span class="err"&gt;&amp;lt;!&lt;/span&gt;&lt;span class="na"&gt;DOCTYPE&lt;/span&gt; &lt;span class="na"&gt;html&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;html&lt;/span&gt; &lt;span class="na"&gt;lang=&lt;/span&gt;&lt;span class="s"&gt;"en"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;title&amp;gt;&lt;/span&gt;Getting Started with ml5.js&lt;span class="nt"&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"viewport"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"width=device-width, initial-scale=1.0"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://unpkg.com/ml5@0.5.0/dist/ml5.min.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;

  &lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
    &lt;span class="c"&gt;&amp;lt;!-- images to train the classifier --&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"./longboard1.jpg"&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"longboard1"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"./longboard2.jpg"&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"longboard2"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"./longboard3.jpg"&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"longboard3"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"./longboard4.jpg"&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"longboard4"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"./longboard5.jpg"&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"longboard5"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"./longboard6.jpg"&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"longboard6"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;

    &lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"./skateboard1.jpg"&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"skateboard1"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"./skateboard2.jpg"&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"skateboard2"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"./skateboard3.jpg"&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"skateboard3"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"./skateboard4.jpg"&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"skateboard4"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"./skateboard5.jpg"&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"skateboard5"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"./skateboard6.jpg"&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"skateboard6"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;

    &lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"./longboard.jpg"&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"longboard"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"./skateboard.jpg"&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"skateboard"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
      &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;classifier&lt;/span&gt;

      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;featureExtractor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;ml5&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;featureExtractor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;MobileNet&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;modelLoaded&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

      &lt;span class="c1"&gt;// Once the model is loaded&lt;/span&gt;
      &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;modelLoaded&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="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Model Loaded!&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="nx"&gt;classifier&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;featureExtractor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;classification&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

        &lt;span class="c1"&gt;// Retrain the network. You can use a for loop too :)&lt;/span&gt;
        &lt;span class="nx"&gt;classifier&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addImage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;longboard1&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;longboard&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nx"&gt;classifier&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addImage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;longboard2&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;longboard&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nx"&gt;classifier&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addImage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;longboard3&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;longboard&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nx"&gt;classifier&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addImage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;longboard4&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;longboard&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nx"&gt;classifier&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addImage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;longboard5&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;longboard&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nx"&gt;classifier&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addImage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;longboard6&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;longboard&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="nx"&gt;classifier&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addImage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
          &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;skateboard1&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;skateboard&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nx"&gt;classifier&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addImage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
          &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;skateboard2&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;skateboard&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nx"&gt;classifier&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addImage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
          &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;skateboard3&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;skateboard&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nx"&gt;classifier&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addImage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
          &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;skateboard4&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;skateboard&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nx"&gt;classifier&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addImage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
          &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;skateboard5&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;skateboard&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="c1"&gt;//addImage accepts a third argument that is a callback.&lt;/span&gt;
        &lt;span class="nx"&gt;classifier&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addImage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
          &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;skateboard6&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;skateboard&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="nx"&gt;imagesLoaded&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;

      &lt;span class="c1"&gt;// Function that will be called once the images are loaded&lt;/span&gt;
      &lt;span class="c1"&gt;// It trains the model with the new categories&lt;/span&gt;
      &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;imagesLoaded&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="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;do train&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;classifier&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;hasAnyTrainedClass&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="c1"&gt;// train argument is a callback that has as argument the current lossValue.&lt;/span&gt;
        &lt;span class="c1"&gt;// When lossValue is null, it means the training is finished&lt;/span&gt;
        &lt;span class="nx"&gt;classifier&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;train&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;lossValue&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;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Loss is&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;lossValue&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;lossValue&lt;/span&gt; &lt;span class="o"&gt;==&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="nf"&gt;trainFinished&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="p"&gt;}&lt;/span&gt;

      &lt;span class="c1"&gt;// Called once the classifier is trained with the new classes&lt;/span&gt;
      &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;trainFinished&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Get a prediction for that image&lt;/span&gt;
        &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;train finished&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="c1"&gt;// Examples to test the classifier&lt;/span&gt;
        &lt;span class="c1"&gt;// Examples to test the classifier&lt;/span&gt;
        &lt;span class="nx"&gt;classifier&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;classify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
          &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;longboard&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
          &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;result&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;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;is longboard?&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;label&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// Should output 'longboard'&lt;/span&gt;
          &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nx"&gt;classifier&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;classify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
          &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;skateboard&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
          &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;result&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;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;is skateboard?&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;label&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// Should output 'skateboard'&lt;/span&gt;
          &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="c1"&gt;// Saves two files model.json and model.weights.bin&lt;/span&gt;
        &lt;span class="nx"&gt;classifier&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;save&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="c1"&gt;// This is the signal to tell puppeteer we are done with the&lt;/span&gt;
        &lt;span class="nx"&gt;done&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;done&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;display&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;block&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;p&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"done"&lt;/span&gt; &lt;span class="na"&gt;style=&lt;/span&gt;&lt;span class="s"&gt;"display: none;"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Done!&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What we have done until now is pretty similar to what you'll do using a regular ml5. Now, it's time for the magic.&lt;/p&gt;

&lt;h2&gt;
  
  
  NodeJS script
&lt;/h2&gt;

&lt;p&gt;The script is very simple, it navigates to the page of our local server, allows to download the files (our model) and wait till the model is trained which is signaled by displaying an element with the id "done" in the HTML.&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="c1"&gt;//index.js&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;puppeteer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&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;puppeteer&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="p"&gt;;(&lt;/span&gt;&lt;span class="k"&gt;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="nx"&gt;browser&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;puppeteer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;launch&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;page&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;browser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;newPage&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

  &lt;span class="c1"&gt;// Navigate to the page that trains the model&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;goto&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;http://localhost:5000&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="c1"&gt;// if you want to trigger some function in the page use evaluate&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;evaluate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ml5.version&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="c1"&gt;// prints "0.5.0"&lt;/span&gt;

  &lt;span class="c1"&gt;// Display browser console messages on screen&lt;/span&gt;
  &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;console&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;msg&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;text&lt;/span&gt;&lt;span class="p"&gt;()))&lt;/span&gt;

  &lt;span class="c1"&gt;// This allows to save the model when classifier.save() is called.&lt;/span&gt;
  &lt;span class="c1"&gt;// downloadPath is the folder in which the model will be saved.&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Page.setDownloadBehavior&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;behavior&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;allow&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;downloadPath&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&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;span class="c1"&gt;//Wait till element with id="done" is visible&lt;/span&gt;
  &lt;span class="c1"&gt;//By default puppeteer will wait 30s and then throw error. `timeout = 0` disables the timeout.&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;waitForSelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#done&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;visible&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;timeout&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;

  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;DONE!&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nx"&gt;browser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;close&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;To run the script&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;node index.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It is important to note that you need to be running &lt;code&gt;serve&lt;/code&gt; in port 5000 while running the node script.&lt;/p&gt;

&lt;p&gt;If everything goes ok, you should see the text "DONE!" and two new files &lt;code&gt;model.json&lt;/code&gt; and &lt;code&gt;model.weights.bin&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://github.com/merlos/merlos.github.io/tree/master/code/ml5-puppeteer" rel="noopener noreferrer"&gt;source code mentioned in this article is available in this github repository&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrapping up
&lt;/h2&gt;

&lt;p&gt;We have trained an image classification model using transfer learning using ml5, then through a Node script using puppeteer we have been able to run this task with just a few lines of code, which is awesome!&lt;/p&gt;

</description>
      <category>ml5</category>
      <category>machinelearning</category>
      <category>puppeteer</category>
      <category>node</category>
    </item>
  </channel>
</rss>
