<?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: Eyitayo Itunu Babatope</title>
    <description>The latest articles on DEV Community by Eyitayo Itunu Babatope (@eyitayoitalt).</description>
    <link>https://dev.to/eyitayoitalt</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%2F1004396%2F2cd6f15f-e23a-4444-a7fe-3ae9295698bc.jpeg</url>
      <title>DEV Community: Eyitayo Itunu Babatope</title>
      <link>https://dev.to/eyitayoitalt</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/eyitayoitalt"/>
    <language>en</language>
    <item>
      <title>How to Implement LLM Grounding using Retrieval Augmented Generation Technique(RAG)</title>
      <dc:creator>Eyitayo Itunu Babatope</dc:creator>
      <pubDate>Fri, 05 Dec 2025 03:30:11 +0000</pubDate>
      <link>https://dev.to/eyitayoitalt/how-to-implement-llm-grounding-using-retrieval-augmented-generation-techniquerag-1m2p</link>
      <guid>https://dev.to/eyitayoitalt/how-to-implement-llm-grounding-using-retrieval-augmented-generation-techniquerag-1m2p</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Nowadays, when you prompt ChatGPT for information not part of its training data, it will search the web to retrieve it, use it in context, and return an appropriate response. Grounding is when Large Language Models(LLMs) use domain-specific information and data to generate accurate and relevant output. This article will examine LLM grounding using the RAG technique.&lt;/p&gt;

&lt;p&gt;​&lt;/p&gt;

&lt;h2&gt;
  
  
  Importance of LLM grounding
&lt;/h2&gt;

&lt;p&gt;This section highlights the importance of LLM grounding. The importance of LLM grounding is listed below:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Reduce LLM Hallucinations. &lt;/li&gt;
&lt;li&gt;Improve LLM precision and accuracy.&lt;/li&gt;
&lt;li&gt;The LLM becomes adept at addressing complex issues quickly.&lt;/li&gt;
&lt;li&gt;LLM becomes more capable of clarifying intricate issues and reducing confusion.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  LLM grounding techniques
&lt;/h2&gt;

&lt;p&gt;This section examines LLM grounding techniques. There are two broad categories of LLM grounding, namely:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Retrieval-Augumented Generation(RAG)&lt;/li&gt;
&lt;li&gt; Fine-tuning.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This article focuses on the RAG technique.&lt;/p&gt;

&lt;h2&gt;
  
  
  RAG technique
&lt;/h2&gt;

&lt;p&gt;This section focuses on how to implement the RAG technique for LLM grounding. The RAG technique starts by retrieving relevant information based on a query. The retrieved content with the prompt is then merged into the LLM context window to generate a relevant output.&lt;/p&gt;

&lt;p&gt;The Implementation of the RAG technique starts with creating a vector representation of the external data through a process called embeddings. It is the process of converting data into vectors, long arrays of numbers that represent semantic meaning for a given sequence of data.  Below is an embedding produced by the Ollama "nomic-embed-text" model for the text "Grounding improves LLM output".&lt;/p&gt;

&lt;p&gt;​&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="o"&gt;[&lt;/span&gt;0.079886355,0.026696106,-0.2009385,-0.081955306,0.033845328,0.0026561292,0.030165939,0.013311965,-0.055660687,-0.048723537,0.014457284,0.027321639,0.029530374,0.02201595,0.013614955,0.057640318,0.03209041,-0.051196527,-0.017932769,-0.06712348
...
&lt;span class="nt"&gt;-0&lt;/span&gt;.02952636,-0.053060006,0.051573362,-0.0038687028,0.054432027,-0.0071464307,0.07941523,-0.0049896343,-0.013346551,-0.006801469,-0.02958884,-0.039702114,0.005442398,0.027762491,0.029064095,-0.024355555,0.01312534,0.046164576,-0.045630153,0.014882911,-0.031765144,0.049317453,-0.0023815103,-0.059432093,-0.03721353,-0.014398544,-0.021900289]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The vector can be stored in vector databases such as ChromaDB for later use.&lt;/p&gt;

&lt;p&gt;There are LLMs trained to create embeddings. OpenAI has the following embedding models:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;text-embedding-3-small&lt;/li&gt;
&lt;li&gt;text-embedding-3-large&lt;/li&gt;
&lt;li&gt;text-embedding-ada-002&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Similarly, Ollama has the following embedding models:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;nomic-embed-text &lt;/li&gt;
&lt;li&gt;mxbai-embed-large&lt;/li&gt;
&lt;li&gt;all-minilm&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It must be noted that embeddings generated by Ollama LLMs cannot be used by OpenAI models and vice versa. This is because each platform produces vector embeddings with different dimensions. The dimensions for OpenAI LLMs are 1536, 3072 … and for Ollama, the vector dimensions are 768, 1024 …&lt;/p&gt;

&lt;p&gt;To create an OpenAI vector embedding, you can use any of its models, as shown below:&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="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;openai&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;OpenAI&lt;/span&gt;

&lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;OpenAI&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="n"&gt;embedding&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;embeddings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;text-embedding-3-small&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nb"&gt;input&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Grounding Improves LLM output .&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;encoding_format&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;float&lt;/span&gt;&lt;span class="sh"&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;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;embedding&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For Ollama, it can be done as follows, assuming you have an Ollama installation on your system:&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="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;ollama&lt;/span&gt;
&lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ollama&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;embed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="err"&gt;”&lt;/span&gt;&lt;span class="n"&gt;nomic&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;embed&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="err"&gt;”&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;prompt&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Grounding Improves LLM output&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The differences between the embedding models are performance, cost, and vector output size. &lt;/p&gt;

&lt;p&gt;The next step is to retrieve the relevant part of the embeddings. You create an embedding for the user prompt, use it to retrieve content relevant to the user’s prompt, then pass both the content and the prompt to the LLM to generate a response, as shown below:&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="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;openai&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;OpenAI&lt;/span&gt;

&lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;OpenAI&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;responses&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;

    &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;gpt-5-nano&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;

    &lt;span class="nb"&gt;input&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt; You are an assistant, use this data &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; to this input &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;prompt&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="err"&gt;​&lt;/span&gt;&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;output_text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Using Ollama.&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="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;ollama&lt;/span&gt;

&lt;span class="n"&gt;output&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ollama&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;generate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;llama2&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;prompt&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Use this data: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; to respond to this prompt: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nb"&gt;input&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;output&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Data in the codes above refers to the content retrieved from the database using the user prompt embeddings.&lt;/p&gt;

&lt;h2&gt;
  
  
  LLM grounding use case:
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Customer Service and Support: Question and Answer Chatbots&lt;/li&gt;
&lt;li&gt;Legal Research: Quickly retrieving relevant case law and statutes from a large database.&lt;/li&gt;
&lt;li&gt;Content creation and research&lt;/li&gt;
&lt;li&gt;Code Assistant: Troubleshooting and fixing errors in code.&lt;/li&gt;
&lt;li&gt;Medical Assistant: Generate medical insight and history of patients.&lt;/li&gt;
&lt;/ol&gt;

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

&lt;p&gt;Grounding improves LLM output. It reduces hallucination, increasing accuracy and reducing confusion in LLM output. In this article, we have examined the RAG technique for grounding LLM. We examined how to use OpenAI and Ollama embedding models to create embeddings. &lt;/p&gt;

</description>
      <category>llm</category>
      <category>ai</category>
      <category>rag</category>
      <category>grounding</category>
    </item>
    <item>
      <title>Smart Contract Fork Testing Using Foundry Cheatcodes</title>
      <dc:creator>Eyitayo Itunu Babatope</dc:creator>
      <pubDate>Sun, 16 Jun 2024 04:42:16 +0000</pubDate>
      <link>https://dev.to/eyitayoitalt/smart-contract-fork-testing-using-foundry-cheatcodes-4jgd</link>
      <guid>https://dev.to/eyitayoitalt/smart-contract-fork-testing-using-foundry-cheatcodes-4jgd</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Testing is important in smart contract development due to the immutable nature of smart contracts. Testing helps identify and resolve potential security vulnerabilities in smart contracts. Safeguard against unauthorized access.&lt;/p&gt;

&lt;p&gt;Sometimes smart contract developers must interact with real-world data that testnet cannot provide. Hence, there is a need for fork testing. In this article, readers will learn how to conduct fork-testing in a foundry development environment.&lt;br&gt;
 &lt;/p&gt;
&lt;h2&gt;
  
  
  Content
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Introduction&lt;/li&gt;
&lt;li&gt;Prerequisites&lt;/li&gt;
&lt;li&gt;Benefits of fork testing?&lt;/li&gt;
&lt;li&gt;What are Foundry Cheatcodes?&lt;/li&gt;
&lt;li&gt;Project Setup and Testing&lt;/li&gt;
&lt;li&gt;Conclusion.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;This tutorial requires foundry installation. &lt;br&gt;
Knowledge of Solidity programming and smart contract development.&lt;/p&gt;
&lt;h2&gt;
  
  
  Benefits of fork-testing
&lt;/h2&gt;

&lt;p&gt;Fork testing mimics the production environment as much as possible. There is no need to use a testnet public faucet to get test coins for testing. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It allows developers to debug in an environment that is as close to the production as possible.&lt;/li&gt;
&lt;li&gt;It gives developers access to real-time data such as the current state of the blockchain which testnet cannot provide since testnet operates in an isolated environment.&lt;/li&gt;
&lt;li&gt;It gives developers unprecedented control over smart contracts. Developers can mint or transfer tokens like they own the token creation smart contract.&lt;/li&gt;
&lt;li&gt;Developers can create blockchain addresses easily.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  What are Foundry Cheatcodes?
&lt;/h2&gt;

&lt;p&gt;According to Foundry Documentation, Forking cheatcodes allow developers to fork blockchain programmatically using solidity instead of CLI arguments. Forking cheat codes support multiple forks and each fork has a unique &lt;code&gt;uint256&lt;/code&gt; identifier. The developer must assign a unique identifier when the developer creates the fork. Forking cheatcodes execute each test in its own standalone &lt;code&gt;EVM&lt;/code&gt;. Forking cheatcodes isolate tests from one another, and execute tests after the setUp function. It implies that a test in forking cheatcodes mode must have a setup function.&lt;/p&gt;
&lt;h2&gt;
  
  
  Project setup and testing
&lt;/h2&gt;

&lt;p&gt;To demonstrate fork testing, we will create a savings smart contract. The contract will allow users to save, set a deadline for withdrawal, and allows users to withdraw when the deadline has elapsed.&lt;br&gt;
 Open a CLI terminal and run the command below to scaffold a foundry project. Name the project &lt;code&gt;fork_testing&lt;/code&gt;.&lt;br&gt;
&lt;code&gt;forge init fork_testing&lt;/code&gt;.&lt;br&gt;
Navigate to the src folder create a file and name it &lt;code&gt;Savings.sol&lt;/code&gt;.&lt;br&gt;
 Open the &lt;code&gt;Savings.sol&lt;/code&gt; file and create a Savings contract as shown below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// SPDX-License-Identifier: MIT
pragma solidity ^0.8.13; 

contract Savings {

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

&lt;/div&gt;



&lt;p&gt;Create the under-listed variables and an event in the contract as shown below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;event Saver(address payer, uint256 amount);
mapping(address =&amp;gt; uint256) public balances;
mapping(address =&amp;gt; uint256) public tenor;
bool public openForWithdraw = false;
uint256 public contractBalance = address(this).balance;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The variable  &lt;code&gt;tenor&lt;/code&gt; maps the address of the saver to the duration in seconds the user wants to keep his token. The variable balance maps the address of a saver to the amount saved in the contract. The boolean variable &lt;code&gt;openForWithdraw&lt;/code&gt; is set to false and does not allow the saver to withdraw before the tenor lapses. The contract will emit the Saver event when a user transfers or sends funds to the contract.&lt;/p&gt;

&lt;p&gt;Next, add a &lt;code&gt;receive () payable&lt;/code&gt; function that allows the contract to receive funds. The function will require the user to set a tenor before the user can send funds to the contract. The function will use the map balances to keep track of the funds sent by an address. On successful savings, the function emits the address and amount sent by a user. The &lt;code&gt;receive()&lt;/code&gt; is as shown in the code below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;receive() external payable {
        require(tenor[msg.sender] &amp;gt; 0, "You must set a tenor before saving");
        balances[msg.sender] += msg.value;
        contractBalance = address(this).balance;
        emit Saver(msg.sender, msg.value);
    }

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

&lt;/div&gt;



&lt;p&gt;Next add two functions to the contract, a &lt;code&gt;setTenor()&lt;/code&gt; and a &lt;code&gt;getTenor()&lt;/code&gt; view function. The &lt;code&gt;setTenor()&lt;/code&gt; allows the user to set the duration the user wants to keep the funds and &lt;code&gt;getTenor()&lt;/code&gt; retrieves the duration the user wants to keep the funds in the contract. The implementation of the functions is shown below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function setTenor(address saver, uint256 _tenor) public {
        tenor[saver] = block.timestamp + _tenor;
    }

function getTenor(address saver) public view returns (uint256) {
        return tenor[saver];
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add a get balance() as shown below. The function returns the total funds received by the contract.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function getBalance() public view returns (uint256) {
        return address(this).balance;
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, add a view function &lt;code&gt;getIndividualBalance()&lt;/code&gt;  as shown below. The &lt;code&gt;getIndividualBalance()&lt;/code&gt; returns the balance of the individual address.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function getIndividualBalances(
        address saver
    ) public view returns (uint256) {
        return balances[saver];
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add a &lt;code&gt;timeLeft()&lt;/code&gt; view function that returns the time left before the tenor lapses. The implementation is shown below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function timeLeft(address saver) public view returns (uint256) {
        if (block.timestamp &amp;gt;= tenor[saver]) {
            return 0;
        } else {
            return tenor[saver] - block.timestamp;
        }
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Lastly add a withdraw function, that allows the user to withdraw their funds if the tenor has elapsed. The implementation is shown below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; function withdraw(uint amount, address withdrawer) public {
        if (timeLeft(withdrawer) &amp;lt;= 0) {
            openForWithdraw = true;
        }
        require(openForWithdraw, "It is not yet time to withdraw");
        require(
            balances[withdrawer] &amp;gt;= amount,
            "Balance less than amount to withdraw"
        );
        balances[withdrawer] -= amount;
        (bool success, ) = withdrawer.call{value: amount}("");
        require(success, "Unable to withdraw fund");
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Below is the full code implementation of the &lt;code&gt;Savings&lt;/code&gt; contract.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;
contract Savings {
    event Saver(address payer, uint256 amount);
    mapping(address =&amp;gt; uint256) public balances;
    mapping(address =&amp;gt; uint256) public tenor;
    bool public openForWithdraw = false;
    uint256 public contractBalance = address(this).balance;

    // Collect funds in a payable `receive()` function and track individual `balances` with a mapping:
    // Add a `Saver(address,uint256, uint256, uint256)`
    receive() external payable {
        require(tenor[msg.sender] &amp;gt; 0, "You must set a tenor before saving");
        balances[msg.sender] += msg.value;
        contractBalance = address(this).balance;
        emit Saver(msg.sender, msg.value);
    }

    // Set the duration of time a user will save token in the contract.
    function setTenor(address saver, uint256 _tenor) public {
        tenor[saver] = block.timestamp + _tenor;
    }

    // Returns the duration of time a user is willing save funds in the contract.
    function getTenor(address saver) public view returns (uint256) {
        return tenor[saver];
    }

    // Returns the contract balance.
    function getBalance() public view returns (uint256) {
        return address(this).balance;
    }

    // Returns the balance saved in the contact by an address.
    function getIndividualBalances(
        address saver
    ) public view returns (uint256) {
        return balances[saver];
    }

    // Returns the time left before the tenor elapsed.
    function timeLeft(address saver) public view returns (uint256) {
        if (block.timestamp &amp;gt;= tenor[saver]) {
            return 0;
        } else {
            return tenor[saver] - block.timestamp;
        }
    }
    // Allows a user to withraw funds once the tenor has elapsed.
    function withdraw(uint amount, address withdrawer) public {
        if (timeLeft(withdrawer) &amp;lt;= 0) {
            openForWithdraw = true;
        }
        require(openForWithdraw, "It is not yet time to withdraw");
        require(
            balances[withdrawer] &amp;gt;= amount,
            "Balance less than amount to withdraw"
        );
        balances[withdrawer] -= amount;
        (bool success, ) = withdrawer.call{value: amount}("");
        require(success, "Unable to withdraw fund");
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Testing the Savings contract.
&lt;/h3&gt;

&lt;p&gt;Open the test folder, create a &lt;code&gt;.env&lt;/code&gt; file, and add a variable &lt;code&gt;MAINET_RPC_URL&lt;/code&gt;. Copy and paste your mainnet RPC_URL as value as shown below.&lt;br&gt;
&lt;code&gt;MAINET_RPC_URL = ‘https://your_rpc_url’&lt;/code&gt;&lt;br&gt;
Next, create a &lt;code&gt;Savings.t.sol&lt;/code&gt; file. Open the file and specify the license and solidity compiler version. In the file, import the foundry Forge Standard Library, the &lt;code&gt;Savings&lt;/code&gt; contract and forge standard output as shown below.  Forge Standard Library is a collection of contracts that makes Test contracts easy to write and test. The &lt;code&gt;forge-std/Test.sol&lt;/code&gt; contains the forge standard experience.&lt;br&gt;
&lt;br&gt;
 &lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.13;

//import dependencies
import "forge-std/Test.sol";
import "../src/Savings.sol";
import "forge-std/console.sol";
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Add a test contract to the Savings.t.sol file. Let the test contract inherit from the &lt;code&gt;Test.sol&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;contract TestSavings is Test {

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

&lt;/div&gt;



&lt;p&gt;Add the variables listed below to the contract.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;uint256 mainnetFork;
string MAINNET_RPC_URL = vm.envString("MAINNET_RPC_URL");
Savings public savings;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The variable &lt;code&gt;mainnetFork&lt;/code&gt; will hold the fork's unique identifier, and the string &lt;code&gt;MAINNET_RPC_URL&lt;/code&gt; holds the RPC_URL loaded from the .env file using cheatcode&lt;code&gt;vm.envString(). The vm is an instance of&lt;/code&gt;forge &lt;code&gt;cheatcodes.&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Next,  add &lt;code&gt;receive() external payable{}&lt;/code&gt; to allow the test contract to receive funds. Add a &lt;code&gt;setUp&lt;/code&gt; function to the contract, to create, select the mainnet fork and create an instance of the &lt;code&gt;Savings&lt;/code&gt; contract as shown below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; function setUp() public {
        mainnetFork = vm.createFork(MAINNET_RPC_URL);
        vm.selectFork(mainnetFork);
        savings = new Savings();
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the code above, we used the cheatcodes &lt;code&gt;vm.createFork(MAINNET_RPC_URL)&lt;/code&gt; to fork the Ethereum mainnet blockchain and create a unique uint256 identifier which we assigned to the variable &lt;code&gt;mainnetFork&lt;/code&gt;. Next, we select the fork with &lt;code&gt;vm.selectFork(mainnetFork)&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Since forge cheatcodes isolate tests from one another, we will create six test functions listed below.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;function testInitialBalance() public view {}&lt;/code&gt;: To test if the Savings contract initial balance is zero.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;function testSavingsWithoutTenor() public{}&lt;/code&gt;: To test if a user can send funds to the Savings contract without a tenor. The test should revert if a user did not set a tenor before sending funds to the Savings contract.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;function testSetTenor() public {}&lt;/code&gt;: The test expects the tenor to be greater than the current &lt;code&gt;block.timestamp&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;function testSavings() public{}&lt;/code&gt;: Once, the user sets a tenor, the test expects the user to be able to save.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;function testWithdrawBeforeTime() public {}&lt;/code&gt;: The user should not be able to withdraw funds before the tenor elapses.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;function testWithdrawAfterTime() public {}&lt;/code&gt;: The user should be able to withdraw funds after the tenor elapses.
The full code implementation of the test contract is shown below.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.13;

//import dependencies
import "forge-std/Test.sol";
import "../src/Savings.sol";
import "forge-std/console.sol";

//Test Contract
contract TestSavings is Test {
    uint256 mainnetFork;
    string MAINNET_RPC_URL = vm.envString("MAINNET_RPC_URL");
    Savings public savings;

    // Allow the test contract to receive funds.
    receive() external payable {}

    // Initial configuration.
    function setUp() public {
        mainnetFork = vm.createFork(MAINNET_RPC_URL);
        vm.selectFork(mainnetFork);
        savings = new Savings();
    }

    // The initial balance should be 0.
    function testInitialBalance() public view {
        assertLt(savings.getBalance(), 1);
    }

    // User should not be able to save without setting a tenor.
    function testSavingsWithoutTenor() public {
        vm.deal(address(this), 2 ether);
        vm.expectRevert();
        (bool sent, ) = address(savings).call{value: 1 ether}("");
        require(sent, "Failed to send Ether");
    }

    // User should be able to set tenor.
    function testSetTenor() public {
        savings.setTenor(address(this), 30);
        uint tenor = savings.getTenor(address(this));
        assertGt(tenor, block.timestamp);
    }

    // User should be able to save, if the user has set a tenor.
    function testSavings() public {
        savings.setTenor(address(this), 30);
        vm.deal(address(this), 2 ether);
        (bool sent, ) = address(savings).call{value: 1 ether}("");
        require(sent, "Failed to send Ether");
        assertGt(savings.getIndividualBalances(address(this)), 0);
    }

    // User should not be able to with the tenor elapses.
    function testWithdrawBeforeTime() public {
        savings.setTenor(address(this), 30);
        vm.deal(address(this), 2 ether);
        (bool sent, ) = address(savings).call{value: 1 ether}("");
        console.log(sent);
        vm.expectRevert("It is not yet time to withdraw");
        savings.withdraw(0.5 ether, address(this));
    }

    // User should be able to withdraw after the tenor elapses.
    function testWithdrawAfterTime() public {
        savings.setTenor(address(this), 0);
        vm.deal(address(this), 1 ether);
        (bool sent, ) = address(savings).call{value: 1 ether}("");
        console.log(sent);
        uint256 oldBalance = address(this).balance;
        savings.withdraw(0.5 ether, address(this));
        uint256 newBalance = address(this).balance;
        assertGt(newBalance, oldBalance);
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the  &lt;code&gt;testBalance()&lt;/code&gt; , we use the &lt;code&gt;assertLt()&lt;/code&gt; to check if the contract balance is less than 1. The test should pass. &lt;/p&gt;

&lt;p&gt;The &lt;code&gt;testSavingsWithoutTenor()&lt;/code&gt; test if a user can save without setting a tenor. In the function, we retrieve the balance of the Savings contract with &lt;code&gt;savings.getBalance()&lt;/code&gt; and assign the return value to the variable initial balance. Then we set the balance of the test contract to &lt;code&gt;2 ether&lt;/code&gt; using &lt;code&gt;vm.deal()&lt;/code&gt;. We expect that when a user tries to send funds to the Savings contract without a tenor, the transaction should revert. We use &lt;code&gt;vm.expectRevert()&lt;/code&gt; to handle the revert. Then, we send &lt;code&gt;1 ether&lt;/code&gt; to the Savings contract from the test contract using &lt;code&gt;(bool sent, ) = address(savings).call{value: 1 ether}("")&lt;/code&gt;. Next, we retrieve the balance of the Savings contract and assign the return value to the variable &lt;code&gt;newBalance&lt;/code&gt;. Then, we test if the new balance of the savings contract is equal to the initial balance using &lt;code&gt;assertEq()&lt;/code&gt;. We expect the test to pass.&lt;/p&gt;

&lt;p&gt;The function &lt;code&gt;testSetTenor&lt;/code&gt; tests if a user can set the tenor for funds to be stored in the savings contract. We set the tenor using &lt;code&gt;setTenor()&lt;/code&gt; of the Savings contract with the address of the test contract and the duration of 30 seconds. The test expects the tenor should be greater than the current &lt;code&gt;block.timestamp&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The  &lt;code&gt;testSavingsWithTenor()&lt;/code&gt; tests if a user can save after the user sets a tenor. We set the tenor with the &lt;code&gt;savings.setTenor&lt;/code&gt; to 30 seconds, set the balance of the test contract to &lt;code&gt;2 ether&lt;/code&gt;, then transfer &lt;code&gt;1 ether&lt;/code&gt; to the  &lt;code&gt;Savings&lt;/code&gt; contract. We retrieve the balance mapped to the test contract address in the &lt;code&gt;Savings&lt;/code&gt; contract with the &lt;code&gt;getIndividualBalances&lt;/code&gt; function. We expect the retrieved balance to be greater than 0.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;testWithdrawBeforeTime()&lt;/code&gt; tests if a user can withdraw funds before the tenor elapses. We send &lt;code&gt;1 ether&lt;/code&gt; to the savings contract, then try to withdraw &lt;code&gt;0.5 ether&lt;/code&gt; from the &lt;code&gt;Savings&lt;/code&gt; contract to the test contract with &lt;code&gt;savings.withdraw(0.5 ether, address(this))&lt;/code&gt;. We expect the transaction to revert.  &lt;/p&gt;

&lt;p&gt;The &lt;code&gt;testWithdrawAfterTime()&lt;/code&gt; tests if a user can withdraw after the tenor has elapsed. We set the tenor to &lt;code&gt;0 seconds&lt;/code&gt;, retrieve the balance of the test contract and assign it to the variable oldBalance, then transfer &lt;code&gt;1 ether&lt;/code&gt; to the &lt;code&gt;Savings&lt;/code&gt; contract,  and withdraw &lt;code&gt;0.5 ether&lt;/code&gt; from the &lt;code&gt;Savings&lt;/code&gt; contract.  Thereafter, retrieve the balance of the test contract and assign the value to the variable newBalance. We expect that the newBalance should be greater than the oldBalance.&lt;/p&gt;

&lt;p&gt;Run the tests with the command:&lt;br&gt;
&lt;code&gt;forge test&lt;/code&gt;&lt;br&gt;
For trace result, run the command:&lt;br&gt;
&lt;code&gt;forge test -vvv&lt;/code&gt;&lt;br&gt;
Or&lt;br&gt;
&lt;code&gt;forge test -vvvv&lt;/code&gt;&lt;/p&gt;

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

&lt;p&gt;Testing is essential in smart contract development, it enables developers to discover errors, and security vulnerabilities in smart contracts before deployment. Once we deploy a smart contract, it becomes immutable. Fork testing is a way to test smart contracts in an environment that is as close to the production environment as possible. In this article, we have demonstrated how to carry out fork testing using Foundry cheatcodes. We have demonstrated how it is easy to fork an Ethereum mainnet and transfer &lt;code&gt;ether&lt;/code&gt; from one contract to another without the need to use testnet faucet or tokens.&lt;/p&gt;

&lt;p&gt;Like, Share, or Comment if you find this article interesting.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Video Streaming with MPEG-DASH?</title>
      <dc:creator>Eyitayo Itunu Babatope</dc:creator>
      <pubDate>Tue, 17 Oct 2023 18:25:00 +0000</pubDate>
      <link>https://dev.to/eyitayoitalt/what-is-mpeg-dash-l0d</link>
      <guid>https://dev.to/eyitayoitalt/what-is-mpeg-dash-l0d</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;MPEG-DASH is one of the most popular protocols for streaming media content over the internet. MPEG-DASH can download large files without causing bandwidth overuse or interruptions to video streaming. YouTube and Netflix, two major video streaming platforms use MPEG-DASH for video streaming. MPEG-DASH protocols adapt to the connection bandwidth of the user by switching from one bandwidth to another. In this post, the reader will learn about MPEG-DASH, how to encode media files using MPEG-DASH &lt;/p&gt;

&lt;h2&gt;
  
  
  Contents
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;MPEG-DASH&lt;/li&gt;
&lt;li&gt;Dynamic Adaptive Streaming &lt;/li&gt;
&lt;li&gt;Media Presentation Description&lt;/li&gt;
&lt;li&gt;How to encode video files using MPEG-DASH Protocol?&lt;/li&gt;
&lt;li&gt;How to Serve and Consume DASH Stream&lt;/li&gt;
&lt;li&gt;Conclusion &lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  MPEG-DASH
&lt;/h2&gt;

&lt;p&gt;In a bid to have a unified protocol for streaming media content over the internet, Morning Picture Expert Group(MPEG) issued a call for proposals in 2009. In 2012,  the group published a standard specification called Dynamic Adaptive Streaming over HTTP(MPEG-DASH).&lt;/p&gt;

&lt;p&gt;MPEG-DASH  is a streaming protocol. Its advantages over other streaming protocols are that, it is codec agnostic and supports multiplexed and un-multiplexed encoded contents. MPEG-DASH supports multiple Digital Rights Management and encryption of media contents. &lt;br&gt;
According to MPEG-DASH 2012(1) specification guideline, MPEG-DASH has the following features.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Switching and selectable streams: the MPD provides adequate information to the client for selecting and switching between streams, e.g. selecting one audio stream from different languages, selecting video between different camera angles, selecting the subtitles from provided languages, switching between different bitrates of the same video camera dynamically.&lt;/li&gt;
&lt;li&gt;Ad-insertion: Permits advertisement placement as a period between periods or segments between segments in both on-demand and live cases.&lt;/li&gt;
&lt;li&gt;Compact manifest: the segment's address URLs can be signaled using a template scheme that produces a compact MPD.
Fragmented manifest: Division of the MPD into multiple parts or some of its elements externally referenced, enabling downloading MPD in multiple steps. &lt;/li&gt;
&lt;li&gt;Segments with variable durations: Variation of segment duration. With live streaming, the duration of the next segment can also be signaled with the delivery of current segment.
Multiple base URLs: the same content can be available at multiple URLs, i.e. at different servers or CDNs, and the client can stream from any of them to maximize the available network bandwidth.&lt;/li&gt;
&lt;li&gt;Clock drift control for live sessions: the UTC can be included with each segment to enable the client to control its clock drift.&lt;/li&gt;
&lt;li&gt;Scalable Video Coding (SVC) and Multiview Video Coding (MVC) support: the MPD provides adequate information regarding the decoding dependencies between representations and is used for streaming any multi-layer coded streams such as SVC and MVC.&lt;/li&gt;
&lt;li&gt;A flexible set of descriptors: for describing content rating, components roles, accessibility features, camera views, frame-packing, and audio channel configuration.&lt;/li&gt;
&lt;li&gt;Subseting of adaptation sets into groups according to the content author's guidance.&lt;/li&gt;
&lt;li&gt;Quality metrics for reporting the session experience: A set of well-defined quality metrics for the client to measure and report back to a reporting server. &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;MPEG-DASH streams Multimedia content by dividing the content into segments. To prevent buffering, MPEG-DASH will adjust the video quality of the stream according to the user's internet connection speed. MPEG-DASH utilizes Multimedia Presentation Description(MPD) to achieve dynamic adaptive streaming.&lt;/p&gt;
&lt;h2&gt;
  
  
  Dynamic Adaptive Streaming
&lt;/h2&gt;

&lt;p&gt;Dynamic adaptive streaming requires a multiple bitrate of media content to be available on the server. For example, if we have a video file named match.mp4. Typically, this file will contain video, audio, text, and subtitles. To utilize the DASH protocol, we must have multiple bitrates of this file on the server. Let's say we encoded our match.mp4 at the following bitrate 100kb/s, 64kb/s, 24kb/s. After encoding, each alternative bitrate will be in chunks called segments, which are about 10s of multimedia content. Each segment contains approximately 100 Access Units. Also, an iframe-only bitstream with a low frame rate is available for streaming during trick play mode. &lt;/p&gt;

&lt;p&gt;A client device starts streaming the first segment of match.mp4 at the highest bitrate of 100kb/s. While monitoring the network bandwidth, on completion of the first segment, if the device realizes the bandwidth is lower than 100kb/s, the device will start streaming at a lower bandwidth. If the bandwidth increases, the device streams at the highest bandwidth. When the user pauses the stream and rewind, the device streams the video in trick mode, playing the video in reverse order with muted audio until the user press play at the desired point. The device will resume streaming at the highest bitrate rate while monitoring the network bandwidth.&lt;/p&gt;

&lt;p&gt;Multimedia dynamic streaming can stream 3D, video streams with subtitles and captions, ad insertion, and multiple camera view streaming. Dynamic streaming uses an MPD file to switch from one bitrate to another.&lt;/p&gt;
&lt;h2&gt;
  
  
  Media Presentation Description
&lt;/h2&gt;

&lt;p&gt;MPD is an XML document that describes the characteristics of the multimedia content. For a DASH client to stream multimedia content, the client downloads the MPD file and parses the file. MPD files consist of one or more periods. A period is the interval between multimedia contents along the temporal axis. A period consists of multiple adaptation sets. An adaptation set contains information about one or more multimedia components and its alternative bitrate.&lt;/p&gt;

&lt;p&gt;An adaptation set consists of representation: information about the encoded bitrate alternative of the same multimedia component. In an MPD file, rep-24.mp4, rep-64.mp4, and rep-100.mp4 are examples of alternative encoded bitrate representations of the same multimedia content.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;?xml version="1.0" encoding="utf-8"?&amp;gt;
&amp;lt;MPD xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns="urn:mpeg:dash:schema:mpd:2011"
    xmlns:xlink="http://www.w3.org/1999/xlink"
    xsi:schemaLocation="urn:mpeg:DASH:schema:MPD:2011 http://standards.iso.org/ittf/PubliclyAvailableStandards/MPEG-DASH_schema_files/DASH-MPD.xsd"
    profiles="urn:mpeg:dash:profile:isoff-live:2011"
    type="static"
    mediaPresentationDuration="PT8M59.9S"
    maxSegmentDuration="PT5.0S"
    minBufferTime="PT16.6S"&amp;gt;
    &amp;lt;ProgramInformation&amp;gt;
    &amp;lt;/ProgramInformation&amp;gt;
    &amp;lt;ServiceDescription id="0"&amp;gt;
    &amp;lt;/ServiceDescription&amp;gt;
    &amp;lt;Period id="0" start="PT0.0S"&amp;gt;
        &amp;lt;AdaptationSet id="0" contentType="video" startWithSAP="1" segmentAlignment="true" bitstreamSwitching="true" frameRate="60000/1001" maxWidth="1280" maxHeight="720" par="16:9" lang="eng"&amp;gt;
            &amp;lt;Representation id="0" mimeType="video/mp4" codecs="avc1.640020" bandwidth="800000" width="1280" height="720" sar="1:1"&amp;gt;
                &amp;lt;SegmentTemplate timescale="60000" initialization="init-stream$RepresentationID$.m4s" media="chunk-stream$RepresentationID$-$Number%05d$.m4s" startNumber="61"&amp;gt;
                    &amp;lt;SegmentTimeline&amp;gt;
                        &amp;lt;S t="30013984" d="500500" r="3" /&amp;gt;
                        &amp;lt;S d="383383" /&amp;gt;
                    &amp;lt;/SegmentTimeline&amp;gt;
                &amp;lt;/SegmentTemplate&amp;gt;
            &amp;lt;/Representation&amp;gt;
            &amp;lt;Representation id="2" mimeType="video/mp4" codecs="avc1.640020" bandwidth="300000" width="1280" height="720" sar="1:1"&amp;gt;
                &amp;lt;SegmentTemplate timescale="60000" initialization="init-stream$RepresentationID$.m4s" media="chunk-stream$RepresentationID$-$Number%05d$.m4s" startNumber="61"&amp;gt;
                    &amp;lt;SegmentTimeline&amp;gt;
                        &amp;lt;S t="30013984" d="500500" r="3" /&amp;gt;
                        &amp;lt;S d="383383" /&amp;gt;
                    &amp;lt;/SegmentTimeline&amp;gt;
                &amp;lt;/SegmentTemplate&amp;gt;
            &amp;lt;/Representation&amp;gt;
        &amp;lt;/AdaptationSet&amp;gt;
        &amp;lt;AdaptationSet id="1" contentType="audio" startWithSAP="1" segmentAlignment="true" bitstreamSwitching="true" lang="eng"&amp;gt;
            &amp;lt;Representation id="1" mimeType="audio/mp4" codecs="mp4a.40.2" bandwidth="128000" audioSamplingRate="48000"&amp;gt;
                &amp;lt;AudioChannelConfiguration schemeIdUri="urn:mpeg:dash:23003:3:audio_channel_configuration:2011" value="2" /&amp;gt;
                &amp;lt;SegmentTemplate timescale="48000" initialization="init-stream$RepresentationID$.m4s" media="chunk-stream$RepresentationID$-$Number%05d$.m4s" startNumber="104"&amp;gt;
                    &amp;lt;SegmentTimeline&amp;gt;
                        &amp;lt;S t="24784896" d="240640" r="3" /&amp;gt;
                        &amp;lt;S d="171509" /&amp;gt;
                    &amp;lt;/SegmentTimeline&amp;gt;
                &amp;lt;/SegmentTemplate&amp;gt;
            &amp;lt;/Representation&amp;gt;
            &amp;lt;Representation id="3" mimeType="audio/mp4" codecs="mp4a.40.2" bandwidth="128000" audioSamplingRate="48000"&amp;gt;
                &amp;lt;AudioChannelConfiguration schemeIdUri="urn:mpeg:dash:23003:3:audio_channel_configuration:2011" value="2" /&amp;gt;
                &amp;lt;SegmentTemplate timescale="48000" initialization="init-stream$RepresentationID$.m4s" media="chunk-stream$RepresentationID$-$Number%05d$.m4s" startNumber="104"&amp;gt;
                    &amp;lt;SegmentTimeline&amp;gt;
                        &amp;lt;S t="24784896" d="240640" r="3" /&amp;gt;
                        &amp;lt;S d="171509" /&amp;gt;
                    &amp;lt;/SegmentTimeline&amp;gt;
                &amp;lt;/SegmentTemplate&amp;gt;
            &amp;lt;/Representation&amp;gt;
        &amp;lt;/AdaptationSet&amp;gt;
    &amp;lt;/Period&amp;gt;
&amp;lt;/MPD&amp;gt;

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

&lt;/div&gt;



&lt;p&gt;A representation contains information about one or more segments, the actual chunks of a media file. The segment contains the URI of the media file on the server and the start period. A device will use the URI to download the media segment with the HTTPS GET method.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to encode video files using MPEG-DASH Protocol?
&lt;/h2&gt;

&lt;p&gt;To encode our video file, we will use FFmpeg, a software for encoding multimedia content. However, other software like Handshake will work.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Download and install FFmpeg&lt;/strong&gt;&lt;br&gt;
To install FFmpeg on Windows, download the latest build here&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;&lt;code&gt;https://www.gyan.dev/ffmpeg/builds&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;Extract the zip file and copy it to C://. Open the Command Line as an administrator. Copy the following code and press enter.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; setx /m PATH "C:\ffmpeg\bin;%PATH%"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Restart system. To confirm installation, run ffmpeg -h. The command will output a series of ffmpeg commands to the screen.&lt;/p&gt;

&lt;p&gt;After installation, create a folder and give it a name of your choice. In this case, we named the folder videodash. Copy your video into the videodash folder.&lt;a href="https://ffmpeg.org/ffmpeg-formats.html#dash-2"&gt;Section 4.9 of FFmpeg&lt;/a&gt; documentation specified how to use FFmpeg to encode and create MPD files. Open the command line, cd into the videodash folder, copy, and run the code below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ffmpeg -re -i culture.MOV -map 0 -map 0 -c:a aac -c:v libx264 -b:v:0 800k -b:v:1 300k -s:v:1 320x170 -profile:v:1 baseline -profile:v:0 main -bf 1 -keyint_min 120 -g 120 -sc_threshold 0 -b_strategy 0 -ar:a:1 22050 -use_timeline 1 -use_template 1 -window_size 5 -adaptation_sets "id=0,streams=v id=1,streams=a" -f dash output.mpd
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Code Explanation&lt;/strong&gt; &lt;br&gt;
You execute ffmpeg commands with sets of options and parameters. The above code is for dash streaming.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;-re  read input at native frame rate &lt;/li&gt;
&lt;li&gt;-i    indicate input stream &lt;/li&gt;
&lt;li&gt;-map 0 select the first audio stream&lt;/li&gt;
&lt;li&gt;-map 0 select the first video stream&lt;/li&gt;
&lt;li&gt;-c:a   audio codec aac&lt;/li&gt;
&lt;li&gt;-c:v  video codec libx264&lt;/li&gt;
&lt;li&gt;-b:v 0 set the bitrate of the first video stream to 800k&lt;/li&gt;
&lt;li&gt;-b:v 1  set the bitrate of the second video stream to 300k&lt;/li&gt;
&lt;li&gt;-s✌️1  set the size of the second video stream to 320 x 270&lt;/li&gt;
&lt;li&gt;-profile:v 1 use baseline as the profile for the second video&lt;/li&gt;
&lt;li&gt;-profile:v 0 use main as the profile of the first video stream&lt;/li&gt;
&lt;li&gt;-bf 1 set the bufsize to 1&lt;/li&gt;
&lt;li&gt;-keyint-min&lt;/li&gt;
&lt;li&gt;-h gulp size 120&lt;/li&gt;
&lt;li&gt;-sc_threshshold&lt;/li&gt;
&lt;li&gt;-b_strategy&lt;/li&gt;
&lt;li&gt;-ar🅰️1 audio rate of the second audio stream is 22050&lt;/li&gt;
&lt;li&gt;-use_timeline enables the use of Segment templates &lt;/li&gt;
&lt;li&gt;-use_template enables the use of Segment templates &lt;/li&gt;
&lt;li&gt;-window_size sets the number of segments in the manifest to 5.&lt;/li&gt;
&lt;li&gt;-adaptation_sets assign  streams to adaptation sets video stream to id 0 and audio to id 1&lt;/li&gt;
&lt;li&gt;-f specify the wrapper for the output, in this case, dash.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The output file is out.mpd. You can give the output file any name of your choice. For a better understanding of ffmpeg options, &lt;a href="https://ffmpeg.org/documentation.html"&gt;Read the documentation&lt;/a&gt;. In the videodash folder, we will have a series of chunk files with m4s extension and an MPD file.&lt;/p&gt;
&lt;h2&gt;
  
  
  How to Serve and Consume DASH Stream.
&lt;/h2&gt;

&lt;p&gt;Video streamed using MPEG-DASH can only be viewed using DASH Client. There is a JavaScript implementation of the DASH client dash.js which you can download or you can use CDN.&lt;br&gt;
Copy the videodash folder to your localhost or remote server.&lt;br&gt;
In your server folder, create a html file and name it video.html then copy the code below&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;!doctype html&amp;gt;
&amp;lt;html&amp;gt;
    &amp;lt;head&amp;gt;
        &amp;lt;title&amp;gt;Dash.js Rocks&amp;lt;/title&amp;gt;
        &amp;lt;style&amp;gt;
            video {
                width: 640px;
                height: 360px;
            }
        &amp;lt;/style&amp;gt;
    &amp;lt;/head&amp;gt;
    &amp;lt;body&amp;gt;
        &amp;lt;div&amp;gt;
            &amp;lt;video id="videoPlayer" controls&amp;gt;&amp;lt;/video&amp;gt;
        &amp;lt;/div&amp;gt;
        &amp;lt;script src="yourPathToDash/dash.all.min.js"&amp;gt;&amp;lt;/script&amp;gt;
        &amp;lt;script&amp;gt;
            (function(){
                var url = "https://dash.akamaized.net/envivio/EnvivioDash3/manifest.mpd";
                var player = dashjs.MediaPlayer().create();
                player.initialize(document.querySelector("#videoPlayer"), url, true);
            })();
        &amp;lt;/script&amp;gt;
    &amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Go to your browser and input the URL of your server.&lt;/p&gt;

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

&lt;p&gt;Before now there was no interoperability between commercial multi-media streaming platforms. Each commercial platform has its manifest, content format, and protocols but nowadays, media contents over the internet are available to a wide range of devices such as mobile phones, PCs, laptops, consoles, and TVs using the same manifest, protocol, and content format. This is due to the advent of protocols like MPEG-DASH. In this post, we examined the fundamentals of MPEG-DASH, how to encode media files using MPEG-DASH protocol, and how to serve MPEG-DASH encoded media files.&lt;/p&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;ISO/IEC 23009-1:2012(E). Information technology — Dynamic adaptive streaming over HTTP (DASH) — Part 1: Media presentation description and segment formats&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>dash</category>
      <category>videostreaming</category>
      <category>videos</category>
      <category>https</category>
    </item>
    <item>
      <title>Develop a Video Chat App with WebRTC, Socket.IO, Express and React.</title>
      <dc:creator>Eyitayo Itunu Babatope</dc:creator>
      <pubDate>Fri, 01 Sep 2023 03:49:43 +0000</pubDate>
      <link>https://dev.to/eyitayoitalt/develop-a-video-chat-app-with-webrtc-socketio-express-and-react-3jc4</link>
      <guid>https://dev.to/eyitayoitalt/develop-a-video-chat-app-with-webrtc-socketio-express-and-react-3jc4</guid>
      <description>&lt;h2&gt;
  
  
  INTRODUCTION
&lt;/h2&gt;

&lt;p&gt;In 2013, Google developed &lt;a href="https://webrtc.org/"&gt;Web Real-Time Communication&lt;/a&gt; (WebRTC) technology for peer-to-peer communication. WebRTC enables web browsers to capture audio and video, exchange data, and conduct teleconferencing without plugins or intermediaries. WebRTC achieves these through APIs and protocols that interact with one another. WebRTC media streaming, when used with SocKet.IO, will produce an application that streams media and exchanges data instantly.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://socket.io/"&gt;Socket.IO&lt;/a&gt; is a library that provides low latency bi-directional communication between client and server. Socket.IO is built on WebSocket, a communication protocol that provides full-duplex and low-latency communication between the server and browser. In this article, readers will learn how to build a video chat application using WebRTC and Socket.IO. This article is for web developers who wish to develop web applications that can stream media between two computers in real time without installing any plugins.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisite
&lt;/h2&gt;

&lt;p&gt;This article assumes the reader is familiar with setting up an &lt;code&gt;Express NodeJS&lt;/code&gt; server, &lt;code&gt;Socket.IO&lt;/code&gt;, a working knowledge of &lt;code&gt;React.js&lt;/code&gt;, JavaScript, and  CSS. We created the UI of the video chat using React and vanilla CSS, while we created the signaling server using &lt;code&gt;Express&lt;/code&gt; and &lt;code&gt;Socket.IO&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Contents
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;WebRTC Media Streaming Concept&lt;/li&gt;
&lt;li&gt;Advantages of WebRTC&lt;/li&gt;
&lt;li&gt;Drawbacks of WebRTC&lt;/li&gt;
&lt;li&gt;Socket.IO Concept&lt;/li&gt;
&lt;li&gt;Advantages of Socket.IO&lt;/li&gt;
&lt;li&gt;Drawbacks of Socket.IO&lt;/li&gt;
&lt;li&gt;Socket.IO Signaling Server setup&lt;/li&gt;
&lt;li&gt;WebRTC Setup&lt;/li&gt;
&lt;li&gt;Video Chat UI&lt;/li&gt;
&lt;li&gt;Conclusion&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  WebRTC Media Streaming Concept
&lt;/h2&gt;

&lt;p&gt;At the top level, WebRTC media streaming occurs in four phases: &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Offer.&lt;/li&gt;
&lt;li&gt; Signaling.&lt;/li&gt;
&lt;li&gt;Answer.&lt;/li&gt;
&lt;li&gt;Data exchange between two browsers. &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;WebRTC uses &lt;a href="https://datatracker.ietf.org/doc/html/rfc8866"&gt;Session Description Protocol(SDP)&lt;/a&gt; to create an offer and answer mechanism. SDP provides a profile of your device to other users trying to connect to your device. SDP is a text-based protocol, that contains information about the type of media stream, codec, transport layer, and other information.&lt;/p&gt;

&lt;p&gt;To make an offer, a WebRTC peer connection object is created and takes an optional parameter. The optional parameter contains the configuration for the &lt;a href="https://temasys.io/guides/developers/webrtc-ice-sorcery/"&gt;Interactive Connectivity Establishment&lt;/a&gt; Protocol(ICE) servers. ICE finds the shortest path for media to travel between two peers. ICE helps devices connect across the internet, and overcome NAT(&lt;a href="https://datatracker.ietf.org/doc/html/rfc2663"&gt;Network Address Translator&lt;/a&gt;), firewalls, and anything that can hinder peer-to-peer communication.&lt;/p&gt;

&lt;p&gt;For devices to communicate over the internet, they utilize IP addresses and port numbers. However, most devices operate behind a firewall or NAT that hides their IP addresses, preventing peer-to-peer communication. During  ICE gatherings, ICE allows devices to exchange potential network addresses called &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/RTCIceCandidate"&gt;ICE candidates&lt;/a&gt;.  The candidates contain IP addresses, port numbers, and transport protocols. A computer device can have multiple ICE candidates. ICE protocol then decides the best network path for a session using the information provided by ICE candidates. Devices exchange ICE candidates using the ICE servers. There are two types of ICE servers&lt;/p&gt;

&lt;p&gt;1 &lt;a href="https://www.3cx.com/pbx/what-is-a-stun-server/"&gt;Session Traversal Utilities for NATS&lt;/a&gt;(STUN) &lt;br&gt;
2 &lt;a href="https://webrtc.org/getting-started/turn-server"&gt;Traversal Using Relay around NATS&lt;/a&gt;(TURN)&lt;/p&gt;

&lt;p&gt;Turn servers are used in a more restrictive network when both peers are behind a firewall, NAT, or symmetric NAT that prevents direct communication between devices.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Advantages of WebRTC&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;High communication quality &lt;/li&gt;
&lt;li&gt;Automatically adjusts to any type of connection.&lt;/li&gt;
&lt;li&gt;Automatic microphone sensitivity (AGC) control for all connections.&lt;/li&gt;
&lt;li&gt;All connections are protected (HTTPS) and encrypted (SRTP).&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;WebRTC&lt;/code&gt; application works on desktop or mobile operating systems provided it has browser support.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Drawbacks of WebRTC&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Audio and video mixing to run group audio or video conferences.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;WebRTC&lt;/code&gt; solutions are incompatible with each other. &lt;/li&gt;
&lt;li&gt;Vendors decide on signaling, messaging, file transfer, conference scheduling, etc. No uniformity in signaling or messaging&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;
  
  
  Socket.IO concepts
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;Socket.IO&lt;/code&gt; is a library that facilitates bi-directional low-latency communication between the client and the server. The communication between the client and server is event-based. The client and the server emit and listen to events. To use &lt;code&gt;Socket.IO&lt;/code&gt;, the client and the server library must be installed on the client and server. &lt;code&gt;Socket.IO&lt;/code&gt; is used for applications that depend on real-time data like the stock market, weather, and chat applications. &lt;code&gt;Socket.IO&lt;/code&gt; is implemented in most major languages, Python, Java, and C++. In this article, we used JavaScript implementation for both the client and server side.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Advantages of Socket.IO&lt;/strong&gt; &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Multiple namespace streams down a single engine.io session.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Encoding of messages as named &lt;code&gt;JSON&lt;/code&gt; and binary events.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Acknowledgment callbacks per event&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Drawbacks of Socket.IO&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;Socket.IO&lt;/code&gt; doesn't provide end-to-end encryption.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;Socket.IO&lt;/code&gt; does not guarantee exact-once messaging semantics. By default, an at-most-once guarantee is provided.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;
  
  
  SOCKET.IO Signaling server setup
&lt;/h2&gt;

&lt;p&gt;Create a directory and name it &lt;code&gt;videoserver&lt;/code&gt; or any name of your choice.&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;videoserver
&lt;span class="nb"&gt;cd &lt;/span&gt;video server
npm init
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The npm init directive will create a &lt;code&gt;package.json&lt;/code&gt; file in our folder.&lt;br&gt;
Install &lt;code&gt;Express&lt;/code&gt; and &lt;code&gt;Socket.IO&lt;/code&gt; packages.&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;express
npm &lt;span class="nb"&gt;install &lt;/span&gt;socket.io
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create a file in the root of the directory and name it &lt;code&gt;server.js&lt;/code&gt;. Open the &lt;code&gt;server.js&lt;/code&gt; file, and import the necessary packages. Create the server as shown in the code below.&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="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;dotenv&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;config&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;express&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;express&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;cors&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;cors&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;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;express&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;cors&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;server&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;http&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;createServer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;app&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;io&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;socket.io&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="nx"&gt;server&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;cors&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;origin&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://127.0.0.1/:5173&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;PORT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3000&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;PORT&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nx"&gt;io&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;connection&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;socket&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;Connected&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="nx"&gt;socket&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;message&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;message&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;socket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;broadcast&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;emit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;message&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="nx"&gt;socket&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;disconnect&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;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;Disconnected&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;error&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;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// log it&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;test&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;error&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;stack&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// respond with 500 "Internal Server Error".&lt;/span&gt;
  &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;res&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;Internal Server Error&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;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;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;listening on Port 3000&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the script above, the &lt;code&gt;require&lt;/code&gt; statements load the needed packages by the script. The script uses the &lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS"&gt;Cross Origin Resource Sharing&lt;/a&gt; (CORS) package to allow cross-origin server requests.  The code snippet below creates a &lt;code&gt;Socket.IO&lt;/code&gt; session.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;io&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;socket.io&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="nx"&gt;server&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;cors&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;origin&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://127.0.0.1/:5173&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;Socket.IO&lt;/code&gt; permits event-based communication between client and server.  The code below shows how to emit an event with &lt;code&gt;Socket.IO&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="nx"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;emit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;custom-named-event&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The code below shows how to listen to an event.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;socket&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;custom-named-event&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;data&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;//process the data &lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The script listens to a client connection with &lt;code&gt;io.on&lt;/code&gt;. When a &lt;code&gt;Socket.IO&lt;/code&gt; client connects to the server, it will log 'Connected' to the console. The script uses the function &lt;code&gt;error&lt;/code&gt; to handle the error that occurs during the script execution.&lt;/p&gt;

&lt;h2&gt;
  
  
  WebRTC Setup
&lt;/h2&gt;

&lt;p&gt;We mentioned earlier that peer-to-peer connections in WebRTC occur through an offer-and-answer mechanism. A peer(caller) creates an instance of the RTCPeerConnection object and passes to it, an optional configuration object that contains the iceServers. The  RTCPeerConnection creates an offer and sets the offer as its local session description, emits the offer to the remote peer through the signaling server. The caller uses the browser &lt;code&gt;API&lt;/code&gt; &lt;code&gt;getUserMedia&lt;/code&gt; to access the device media. Then attach the media stream and ice candidates to the  RTCPeerConnection.&lt;/p&gt;

&lt;p&gt;The remote peer(callee) will also create an instance of the RTC peer connection. When the callee receives an offer, it will set its remote session description to the offer, then create an answer, and set the answer as its local session description. The callee will send the answer to the caller through the signaling server. The callee would also attach its media stream and ice candidate to the peer connection. &lt;/p&gt;

&lt;p&gt;The connection between the caller and callee can only take place after they have both exchanged ice candidates. We mentioned before that ice candidates are potential network addresses that peers can use to communicate with one another. The caller would send its ice candidate to the callee through the signaling server and listen for the ice candidate of the callee, when the caller receives the ice candidate of the callee, it will add it to the RTCPeerConnection. The callee would also repeat this process.&lt;/p&gt;

&lt;p&gt;We implemented the offer and answer mechanism in the code below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;io&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;socket.io-client&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useRef&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;FiVideo&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;FiVideoOff&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;FiMic&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;FiMicOff&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react-icons/fi&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;configuration&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;iceServers&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="na"&gt;urls&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;stun:stun1.l.google.com:19302&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;stun:stun2.l.google.com:19302&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="na"&gt;iceCandidatePoolSize&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;10&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;socket&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;io&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:3000&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;transports&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;websocket&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;let&lt;/span&gt; &lt;span class="nx"&gt;pc&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;localStream&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;startButton&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;hangupButton&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;muteAudButton&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;remoteVideo&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;localVideo&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nx"&gt;socket&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;message&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;e&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="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;localStream&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;not ready yet&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="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;switch &lt;/span&gt;&lt;span class="p"&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;type&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;offer&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="nf"&gt;handleOffer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;answer&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="nf"&gt;handleAnswer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;candidate&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="nf"&gt;handleCandidate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ready&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="c1"&gt;// A second tab joined. This tab will initiate a call unless in a call already.&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;pc&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;already in call, ignoring&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="p"&gt;}&lt;/span&gt;
      &lt;span class="nf"&gt;makeCall&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
      &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;bye&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pc&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;hangup&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;default&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;unhandled&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="k"&gt;break&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;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;makeCall&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;pc&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;RTCPeerConnection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;configuration&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;pc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onicecandidate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&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;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;candidate&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;candidate&lt;/span&gt;&lt;span class="p"&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="k"&gt;if &lt;/span&gt;&lt;span class="p"&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;candidate&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;candidate&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;candidate&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;candidate&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;sdpMid&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;candidate&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;sdpMid&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;sdpMLineIndex&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;candidate&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;sdpMLineIndex&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="nx"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;emit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;message&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="nx"&gt;pc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ontrack&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&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;remoteVideo&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;srcObject&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;streams&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;localStream&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getTracks&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;track&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;pc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addTrack&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;track&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;localStream&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;offer&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;pc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createOffer&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="nx"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;emit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;message&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;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;offer&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;sdp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;offer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;sdp&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;pc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setLocalDescription&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;offer&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&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="nx"&gt;e&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;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;handleOffer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;offer&lt;/span&gt;&lt;span class="p"&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;pc&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;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;existing peerconnection&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="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;pc&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;RTCPeerConnection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;configuration&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;pc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onicecandidate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&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;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;candidate&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;candidate&lt;/span&gt;&lt;span class="p"&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="k"&gt;if &lt;/span&gt;&lt;span class="p"&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;candidate&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;candidate&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;candidate&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;candidate&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;sdpMid&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;candidate&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;sdpMid&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;sdpMLineIndex&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;candidate&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;sdpMLineIndex&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="nx"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;emit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;message&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="nx"&gt;pc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ontrack&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&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;remoteVideo&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;srcObject&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;streams&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;localStream&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getTracks&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;track&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;pc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addTrack&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;track&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;localStream&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;pc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setRemoteDescription&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;offer&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;answer&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;pc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createAnswer&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="nx"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;emit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;message&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;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;answer&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;sdp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;answer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;sdp&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;pc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setLocalDescription&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;answer&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&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="nx"&gt;e&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;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;handleAnswer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;answer&lt;/span&gt;&lt;span class="p"&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="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;pc&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;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;no peerconnection&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="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;try&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;pc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setRemoteDescription&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;answer&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&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="nx"&gt;e&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;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;handleCandidate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;candidate&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;try&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="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;pc&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;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;no peerconnection&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="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="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;candidate&lt;/span&gt;&lt;span class="p"&gt;)&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;pc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addIceCandidate&lt;/span&gt;&lt;span class="p"&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="k"&gt;else&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;pc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addIceCandidate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;candidate&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;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&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="nx"&gt;e&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;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;hangup&lt;/span&gt;&lt;span class="p"&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;pc&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;pc&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="nx"&gt;pc&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="nx"&gt;localStream&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getTracks&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;track&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;track&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stop&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
  &lt;span class="nx"&gt;localStream&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="nx"&gt;startButton&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;disabled&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;hangupButton&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;disabled&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;muteAudButton&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;disabled&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;App&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;startButton&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useRef&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;hangupButton&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useRef&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;muteAudButton&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useRef&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;localVideo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useRef&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;remoteVideo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useRef&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nf"&gt;useEffect&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;hangupButton&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;disabled&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nx"&gt;muteAudButton&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;disabled&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&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="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;audiostate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setAudio&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;startB&lt;/span&gt; &lt;span class="o"&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="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;localStream&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nb"&gt;navigator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;mediaDevices&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getUserMedia&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="na"&gt;video&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;audio&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;echoCancellation&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="p"&gt;});&lt;/span&gt;
      &lt;span class="nx"&gt;localVideo&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;srcObject&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;localStream&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="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;err&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nx"&gt;startButton&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;disabled&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nx"&gt;hangupButton&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;disabled&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nx"&gt;muteAudButton&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;disabled&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="nx"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;emit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;message&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;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ready&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;hangB&lt;/span&gt; &lt;span class="o"&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="nf"&gt;hangup&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="nx"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;emit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;message&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;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;bye&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;function&lt;/span&gt; &lt;span class="nf"&gt;muteAudio&lt;/span&gt;&lt;span class="p"&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;audiostate&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;localVideo&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;muted&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="nf"&gt;setAudio&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;localVideo&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;muted&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="nf"&gt;setAudio&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="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;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;main&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;container  &lt;/span&gt;&lt;span class="dl"&gt;"&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;div&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;video bg-main&lt;/span&gt;&lt;span class="dl"&gt;"&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;video&lt;/span&gt;
            &lt;span class="nx"&gt;ref&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;localVideo&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;video-item&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
            &lt;span class="nx"&gt;autoPlay&lt;/span&gt;
            &lt;span class="nx"&gt;playsInline&lt;/span&gt;
            &lt;span class="nx"&gt;src&lt;/span&gt;&lt;span class="o"&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="o"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/video&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;video&lt;/span&gt;
            &lt;span class="nx"&gt;ref&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;remoteVideo&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;video-item&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
            &lt;span class="nx"&gt;autoPlay&lt;/span&gt;
            &lt;span class="nx"&gt;playsInline&lt;/span&gt;
            &lt;span class="nx"&gt;src&lt;/span&gt;&lt;span class="o"&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="o"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/video&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="sr"&gt;/div&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;div&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;btn&lt;/span&gt;&lt;span class="dl"&gt;"&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;button&lt;/span&gt;
            &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;btn-item btn-start&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
            &lt;span class="nx"&gt;ref&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;startButton&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="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;startB&lt;/span&gt;&lt;span class="p"&gt;}&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;FiVideo&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="sr"&gt;/button&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;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;btn-item btn-end&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
            &lt;span class="nx"&gt;ref&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;hangupButton&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="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;hangB&lt;/span&gt;&lt;span class="p"&gt;}&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;FiVideoOff&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="sr"&gt;/button&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;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;btn-item btn-start&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
            &lt;span class="nx"&gt;ref&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;muteAudButton&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="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;muteAudio&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;audiostate&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;FiMic&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;FiMicOff&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="sr"&gt;/button&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="sr"&gt;/div&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="sr"&gt;/main&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="sr"&gt;/&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="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;App&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the script above, we initialized a variable named &lt;code&gt;configuration&lt;/code&gt;  and assigned it an object with two fields, iceServers, and iceCandidatePoolSize. The value of the iceServers field is an array that contains the URL of the ice servers. Next, we instantiated a &lt;code&gt;Socket.IO&lt;/code&gt; client and assigned it to the variable socket. The instance of the &lt;code&gt;Socket.IO&lt;/code&gt; client contains two parameters, the &lt;code&gt;URL&lt;/code&gt; of server-side &lt;code&gt;Socket.IO&lt;/code&gt; and the transport protocol to use. Then, we declared seven global variables without assigning any value to them. &lt;/p&gt;

&lt;p&gt;The instance of the &lt;code&gt;Socket.IO&lt;/code&gt; client listens to a message event. On receiving a message event, the event will be passed through a switch block to handle a specific type of event. The offer and answer were implemented through five async functions:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;makeCall &lt;/li&gt;
&lt;li&gt;handleOffer&lt;/li&gt;
&lt;li&gt;handleAnswer &lt;/li&gt;
&lt;li&gt;handleCandidate &lt;/li&gt;
&lt;li&gt;hangUp&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Video App UI
&lt;/h2&gt;

&lt;p&gt;We used React.js  to create the UI of the video chat app. We created a component named App. To start a video call, click on the phone icon. This will fire the browser &lt;code&gt;API&lt;/code&gt; &lt;code&gt;navigator.mediaDevices.getUserMedia({video: true, audio:{'echoCancellation':true}})&lt;/code&gt; The stream from the camera will be seen in the video element of the App component. Open another tab in the browser, and type the &lt;code&gt;URL&lt;/code&gt; of the React App, you will see two streams of videos. One local and one remote.&lt;/p&gt;

&lt;p&gt;Below are the Cascading Style Sheets(CSS) and HTML for the UI&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.bg-body&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;background-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#332e33&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.container&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;flex&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;flex-direction&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;column&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="py"&gt;gap&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;5px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;10px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nc"&gt;.col-container&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;flex&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;flex-direction&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;column&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;inherit&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nc"&gt;.label-text&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#fff&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;text-align&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;center&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;font-size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;20px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nc"&gt;.btn-start&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;background-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#0ced23&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nc"&gt;.btn-end&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;background-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;rgb&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;225&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;5&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nc"&gt;.btn&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;flex&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;flex-direction&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;justify-content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;center&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;column-gap&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;20px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;margin-top&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;10px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nc"&gt;.btn-item&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;50px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;50px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#fff&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;border-radius&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;50%&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nc"&gt;.video&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;flex&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;flex-direction&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;column&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;justify-content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;center&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;align-items&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;center&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="py"&gt;row-gap&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;10px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nc"&gt;.video-item&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;90%&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;250px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;border&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2px&lt;/span&gt; &lt;span class="nb"&gt;solid&lt;/span&gt; &lt;span class="m"&gt;#fff&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;border-radius&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;10px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;margin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;10px&lt;/span&gt; &lt;span class="nb"&gt;auto&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;@media&lt;/span&gt; &lt;span class="n"&gt;only&lt;/span&gt; &lt;span class="n"&gt;screen&lt;/span&gt; &lt;span class="n"&gt;and&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;min-width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;800px&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nc"&gt;.container&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;margin-top&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;30px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nc"&gt;.video&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;flex&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;flex-direction&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;column-gap&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0.5%&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;justify-content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;center&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nc"&gt;.video-item&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;40%&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;400px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nc"&gt;.btn-item&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;80px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;80px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#fff&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;border-radius&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;50%&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;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;meta&lt;/span&gt; &lt;span class="na"&gt;charset=&lt;/span&gt;&lt;span class="s"&gt;"UTF-8"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"icon"&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"image/svg+xml"&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"/vite.svg"&lt;/span&gt; &lt;span class="nt"&gt;/&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;link&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"stylesheet"&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"/style.css"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;title&amp;gt;&lt;/span&gt;Video Chat&lt;span class="nt"&gt;&amp;lt;/title&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&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"bg-body"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"root"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"module"&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"/src/main.jsx"&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;/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;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;In this article, we explained &lt;code&gt;WebRTC&lt;/code&gt;, and &lt;code&gt;Socket.IO&lt;/code&gt; concepts and how to set them up to create a Video Chat App. Also, we discussed the advantages and disadvantages of using &lt;code&gt;WebRTC&lt;/code&gt; for video chat applications.&lt;/p&gt;

&lt;p&gt;Like, Share, or Comment if you find this article interesting.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Toggle Password Visibility Using React useRef</title>
      <dc:creator>Eyitayo Itunu Babatope</dc:creator>
      <pubDate>Fri, 04 Aug 2023 10:41:59 +0000</pubDate>
      <link>https://dev.to/eyitayoitalt/toggle-password-visibility-using-react-useref-3ck0</link>
      <guid>https://dev.to/eyitayoitalt/toggle-password-visibility-using-react-useref-3ck0</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;One way to manipulate &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Document_Object_Model/Introduction" rel="noopener noreferrer"&gt;Document Object Model&lt;/a&gt;(DOM) without triggering a re-render of the component in React is to use the &lt;a href="https://www.w3schools.com/react/react_useref.asp" rel="noopener noreferrer"&gt;useRef hook&lt;/a&gt;. In this article, I will use the ref hook to toggle password input visibility.&lt;/p&gt;

&lt;p&gt;This article is for React beginner developers with a basic understanding of the React library. The reader will learn how to toggle password field visibility using useRef.&lt;/p&gt;

&lt;h2&gt;
  
  
  Outline
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Understanding useRef
&lt;/li&gt;
&lt;li&gt;Application of useRef&lt;/li&gt;
&lt;li&gt;Toggle password Demo&lt;/li&gt;
&lt;li&gt;Conclusion&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Understanding useRef
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://react.dev/reference/react/useRef#useref" rel="noopener noreferrer"&gt;React documentation&lt;/a&gt; defines useRef as a hook that lets you reference a value not needed for rendering. It is a built-in hook used for accessing the DOM. It does not trigger a re-render of the component. UseRef is a top-level component. You can access the value held by useRef using its current property. &lt;/p&gt;

&lt;h2&gt;
  
  
  Application of useRef
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
import React,{useRef} from 'react';

function TogglePassword(){

    const inputRef= useRef(initialValue)

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

&lt;/div&gt;



&lt;p&gt;In the above code example, I imported useRef from React and initialized it with an initial value. The value can be string, int, or object. To access the useRef value, I used its current property as shown below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const refValue= inputRef.current

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

&lt;/div&gt;



&lt;h2&gt;
  
  
  Toggle password Demo
&lt;/h2&gt;

&lt;p&gt;I used uesRef to access the DOM to achieve the toggle password effect. In the code example below, I set the initial value of useRef to null.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import React, { useRef, useState } from "react";
import { FaEyeSlash, FaEye } from "react-icons/fa";
function TogglePassword() {
  const inputref = useRef(null);
  const [iconState, setIcon] = useState(false);
  const handleClick = () =&amp;gt; {
    const inputattr = inputref.current.getAttribute("type");
    inputattr === "password"
      ? inputref.current.setAttribute("type", "text")
      : inputref.current.setAttribute("type", "password");
    iconState ? setIcon(false) : setIcon(true);
  };
  let icon;
  if (iconState) {
    icon = &amp;lt;FaEyeSlash /&amp;gt;;
  } else {
    icon = &amp;lt;FaEye /&amp;gt;;
  }
  return (
    &amp;lt;&amp;gt;
      &amp;lt;div&amp;gt;
        &amp;lt;p&amp;gt;Email&amp;lt;/p&amp;gt;
        &amp;lt;input type="text" id="email" /&amp;gt;
      &amp;lt;/div&amp;gt;
      &amp;lt;div&amp;gt;
        &amp;lt;p&amp;gt;Password&amp;lt;/p&amp;gt;
        &amp;lt;input ref={inputref} type="password" id="pwd" /&amp;gt;

        &amp;lt;span onClick={handleClick}&amp;gt;{icon}&amp;lt;/span&amp;gt;
      &amp;lt;/div&amp;gt;
    &amp;lt;/&amp;gt;
  );
}

export default TogglePassword;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the code above, I initialized the iconState to false using the useState hook to track password visibility. I created a handleClick function to toggle password visibility by listening to a click event on the eye icon. In the JSX of the togglePassword component, I used inputRef to hold the reference to the password input. Next, I used the inputRef.current property to access the input type attribute. If the input type attribute was password, I set the type to 'text' and vice versa using the ternary operator. Then, I toggled iconState to true or false. Next, I declared a variable icon and was assigned an eye component or eye slash component depending on the iconState.&lt;/p&gt;

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

&lt;p&gt;In the article, I demonstrated the usage of useRef and showed how it can access the DOM. Now, the readers should have gained a better understanding of useRef and how to use it to access the DOM.&lt;/p&gt;

&lt;p&gt;Find this article educative, comment, like, and share. &lt;/p&gt;

</description>
      <category>javascript</category>
      <category>frontend</category>
      <category>react</category>
      <category>useref</category>
    </item>
    <item>
      <title>React Hooks Made Easy</title>
      <dc:creator>Eyitayo Itunu Babatope</dc:creator>
      <pubDate>Wed, 19 Jul 2023 07:18:17 +0000</pubDate>
      <link>https://dev.to/eyitayoitalt/react-hooks-made-easy-4b7j</link>
      <guid>https://dev.to/eyitayoitalt/react-hooks-made-easy-4b7j</guid>
      <description>&lt;h2&gt;
  
  
  Introduction:
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://legacy.reactjs.org/docs/hooks-intro.html"&gt;React Hooks&lt;/a&gt; allow &lt;a href="https://www.geeksforgeeks.org/reactjs-functional-components/"&gt;functional components&lt;/a&gt; to use React features such as state and life cycle methods. Functional components use hooks to maintain state, fetch data from an external source, cache results of an expensive calculation, and receive data from distant parent components without passing it as props. Knowing which React hooks to use can be tricky. In two articles series, we will look at each of the React Hooks and demonstrate their usage with code examples.&lt;/p&gt;

&lt;p&gt;These two articles series are for React developers who wish to better understand React hooks. The article assumes the reader has basic knowledge of React, functional components, &lt;a href="https://www.w3schools.com/react/react_lifecycle.asp"&gt;lifecycle methods&lt;/a&gt;, and how to include &lt;a href="https://react.dev/learn/add-react-to-an-existing-project"&gt;React library&lt;/a&gt; in a project. &lt;/p&gt;

&lt;p&gt;In this article, the reader will learn about&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Rules for hooks&lt;/li&gt;
&lt;li&gt;How to use hooks&lt;/li&gt;
&lt;li&gt;Categories of Built in hooks &lt;/li&gt;
&lt;li&gt;Usage of hooks &lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Rules for Hooks
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Hooks are call within a functional component.&lt;/li&gt;
&lt;li&gt;Hooks are call at the top level of a component.&lt;/li&gt;
&lt;li&gt;It cannot be conditional &lt;/li&gt;
&lt;li&gt;Hooks begin with the keyword use.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How to use Hooks in an application
&lt;/h2&gt;

&lt;p&gt;To use hooks in an application, we import the hooks using the keyword import.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import {useState} from "react"

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

&lt;/div&gt;



&lt;p&gt;In the above example, we imported the useState from React. We can import more than one hooks. See the example below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import {useState, useEffect} from "react"

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

&lt;/div&gt;



&lt;p&gt;React comes with built-in hooks. Also, we can &lt;a href="https://legacy.reactjs.org/docs/hooks-custom.html"&gt;customize hooks&lt;/a&gt; to meet specific requirements.&lt;/p&gt;

&lt;p&gt;React Built-Hooks are categorize into the following groups:&lt;br&gt;
1)State Hooks &lt;br&gt;
2) Effect Hooks&lt;br&gt;
3) Context Hooks&lt;br&gt;
4) Performance Hooks&lt;br&gt;
5) Other Hooks&lt;/p&gt;
&lt;h2&gt;
  
  
  React State Hooks
&lt;/h2&gt;

&lt;p&gt;State in react is a built-in react object that stores data or value of a property. State let component remember user input between re-render. When the value of a property changes, react re-renders the component. &lt;br&gt;
&lt;a href="https://legacy.reactjs.org/docs/hooks-state.html"&gt;useState&lt;/a&gt; and &lt;a href="https://react.dev/reference/react/useReducer"&gt;useReducer&lt;/a&gt; are two hooks that manage the state in React. &lt;/p&gt;
&lt;h2&gt;
  
  
  React useState
&lt;/h2&gt;

&lt;p&gt;useState is a react hook that updates or sets the value of a property directly. The useState returns an array of two values. The current state and a function that sets or updates the current state.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1 import React,{useState} from 'react';
2 function MyText(){
3 const [myText, setText]=useState('first Text');
4 const handleSubmit=(event)=&amp;gt;{
5    event.preventDefault();
6    const textForm=document.forms['textForm']['mytext'].value
7   setText(textForm)
8 }
9 return(
10    &amp;lt;&amp;gt;
11    &amp;lt;div&amp;gt;{myText}&amp;lt;/div&amp;gt;
12    &amp;lt;form name="textForm" onSubmit={handleSubmit}&amp;gt;
13        &amp;lt;textarea name="mytext"  cols={20} rows={10} /&amp;gt;
14        &amp;lt;button type="submit"&amp;gt;Click Me&amp;lt;/button&amp;gt;
15    &amp;lt;/form&amp;gt;
16    &amp;lt;/&amp;gt;


17 )
18 }
19 export default MyText;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Line 1: We imported useState. &lt;br&gt;
Line 2: We created a react functional component called MyDetails.&lt;br&gt;
Line 3: We initialized useState with a string and deconstructed the array returned by useState with variable text and function setText.&lt;br&gt;
Line 4: We declared a function to handle the form submission.&lt;br&gt;
Line 5: We called the event.preventDefault function to prevent default form propagation.&lt;br&gt;
Line 6: We assigned the value of the textarea element to the variable textForm.&lt;br&gt;
Line 7: Called setText to set the value of myText.&lt;br&gt;
Line 9: Return JSX of  MyText component.&lt;/p&gt;

&lt;p&gt;React useState hook can be initialized with an empty string, an object, or an array. See the code example below.&lt;br&gt;
&lt;/p&gt;

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

1 import React,{useState} from 'react';

2 function MyDetails(){
3 const [myDetails, setMyDetails]=useState({'firstname':"",'lastname':' ','age':0});
4 const handleSubmit=(event)=&amp;gt;{
5    event.preventDefault();
6    const fname=document.forms['detailsForm']['fname'].value
7    const lname=document.forms['detailsForm']['lname'].value
8    const age=document.forms['detailsForm']['age'].value
9    setMyDetails({firstname:fname,
10    lastname:lname,
11    age: age    })
12 }
13 return(
14    &amp;lt;&amp;gt;

15    &amp;lt;form name="detailsForm" onSubmit={handleSubmit}&amp;gt;
16       &amp;lt;label&amp;gt;Firstname&amp;lt;/label&amp;gt;
17        &amp;lt;input type='text' name='fname' /&amp;gt;
18        &amp;lt;label&amp;gt;Lastname&amp;lt;/label&amp;gt;
19        &amp;lt;input type='text' name='lname' /&amp;gt;
20       &amp;lt;label&amp;gt;Age&amp;lt;/label&amp;gt;
21        &amp;lt;input type='number' name='age' min='1' max='100'/&amp;gt;

22        &amp;lt;button type="submit"&amp;gt;Click Me&amp;lt;/button&amp;gt;
23    &amp;lt;/form&amp;gt;
24    &amp;lt;ul&amp;gt;
25        {Object.entries(myDetails).map(([index,element]) =&amp;gt; {
26          return (&amp;lt;li key={element}&amp;gt;{index}:{element}&amp;lt;/li&amp;gt;)
27        })
28        }
29    &amp;lt;/ul&amp;gt;
30    &amp;lt;/&amp;gt;


31 )
32 }
33 export default MyDetails;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Line 3: We initialized useState with an object with firstname, lastname, and age as properties. &lt;/p&gt;

&lt;p&gt;Line 4: We declared the handleSubmit function with an event argument.&lt;br&gt;
Lines 6,7,8: We assigned the values of the input fields to variables.&lt;br&gt;
Line 8: We called the setMyDetails to set the value of the properties of MyDetails.&lt;br&gt;
Line 13: It rendered JSX of the MyDetails component.&lt;br&gt;
Line 25: We called the Object.entries function to transform myDetails into an array of key and value pairs and iterated through the returned array with the array.map function.&lt;/p&gt;
&lt;h2&gt;
  
  
  useReducer
&lt;/h2&gt;

&lt;p&gt;useReducer sets or updates state but the logic to update the state is in another function called reducer.&lt;br&gt;
useReducer takes three arguments: the reducer function, the initial argument, and an init function(optional). The init function returns the initial state. If it is not specified, it defaults to the initial argument. The useReducer returns an array of two values: the current state and a dispatch function that lets you update the current state to a new value.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1 import React,{useReducer} from 'react';
2 function reducer(jobDescription,action){

3   switch(action.type){
4.      case "janitor":
      5 return{category: action.type}
6       case "manager":
        7 return{category: action.type}
8       case "secretary":
        9 return{category: action.type}
10       default:
          11 return " ";
    }

}
12 const initialArg={category:""}
13 function Employee(){
14 const [jobDescription, dispatch]= useReducer(reducer,initialArg);

15 return(
    &amp;lt;&amp;gt;
16   &amp;lt;select name='jobs' onChange={(event)=&amp;gt;{
         dispatch({type:event.target.value})
    }}&amp;gt;
17        &amp;lt;option value=" "&amp;gt; &amp;lt;/option&amp;gt;
18        &amp;lt;option value="janitor"&amp;gt;Janitor&amp;lt;/option&amp;gt;
19       &amp;lt;option value="secretary"&amp;gt;Secretary&amp;lt;/option&amp;gt;
20        &amp;lt;option value="manager"&amp;gt;Manager&amp;lt;/option&amp;gt;
    &amp;lt;/select&amp;gt;
21   &amp;lt;div&amp;gt;Your job description is {jobDescription.category}&amp;lt;/div&amp;gt;
    &amp;lt;/&amp;gt;


)
}
22 export default Employee;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Line 2: We declared a reducer function with two arguments; jobDescription(state) and action&lt;br&gt;
Line 3-11: We passed action.type through a switch block, each case set the category and returned the updated category.&lt;br&gt;
Line 12: We declared a  variable initial argument and initialized it with an object that has a category field with an empty value.&lt;br&gt;
Line 13: We declared an Employee component.&lt;br&gt;
Line 14: We called a useReducer hook with two arguments; reducer function and intialArg. The useReducer returned an array of two values which we deconstructed into variable jobDescription(state) and a dispatch function.&lt;br&gt;
Line 16: We used the HTML select tag to create four options field, with an onChange event listener. Whenever there is a change in the selected value, the dispatch function will be called inside the event listener.&lt;br&gt;
Line 17-20: The different option.&lt;br&gt;
Line 21: We rendered the current jobDescription(state).&lt;/p&gt;

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

&lt;p&gt;In part 1 of react hooks, we defined hooks, enumerated the rules for hooks, and mentioned various types of hooks. We demonstrated how to use useState and useReducer hooks with code examples. In part two of react hooks, we will discuss other react hooks.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Test Driven Development in NodeJS</title>
      <dc:creator>Eyitayo Itunu Babatope</dc:creator>
      <pubDate>Fri, 17 Feb 2023 18:34:27 +0000</pubDate>
      <link>https://dev.to/eyitayoitalt/test-driven-development-in-nodejs-1jap</link>
      <guid>https://dev.to/eyitayoitalt/test-driven-development-in-nodejs-1jap</guid>
      <description>&lt;h1&gt;
  
  
  Introduction
&lt;/h1&gt;

&lt;p&gt;Testing in software is the step wise process that ensures your code does what it was written to do.  A typical programmer's work flow is to come up with an algorithm, write the code, and run the code. If the program runs without an error, it is code well written. If otherwise, the programmer tries to fix the error using the error message as a guide. Then, run the program again, hoping the error has been fixed. Sometimes the error get fixed at the first attempt and sometimes it takes many attempt.&lt;/p&gt;

&lt;p&gt;For few lines of code, this method of testing will do but as application scales, this method of testing becomes tedious and time-consuming. Hence, the need for automated testing. Though test-driven development might sound esoteric, something for the senior developers. In reality, testing can be automated using testing frameworks such as mocha and implemented with few lines of code. &lt;/p&gt;

&lt;p&gt;Mocha is a popular JavaScript framework that organizes our tests and runs them for us. In this post, mocha framework will be used to organize the test and assert module of Nodejs will be used to compare test values.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Prerequisite: JavaScript, Nodejs.&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;Objective: To gain knowledge about using mocha testing framework.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 1: Install mocha using&lt;/strong&gt;&lt;br&gt;
npm install mocha -save&lt;br&gt;
 in your package.json change the test field to &lt;br&gt;
"test":" mocha test.js"&lt;/p&gt;

&lt;p&gt;In the root folder, create a test.js file. &lt;br&gt;
There are two key functions in mocha &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;describe(): it helps group similar tests together.&lt;/li&gt;
&lt;li&gt;it(): contains test code, this is where we run our test code.
Other functions are the hooks, such as&lt;/li&gt;
&lt;li&gt;before()&lt;/li&gt;
&lt;li&gt;beforeEach()&lt;/li&gt;
&lt;li&gt;after()&lt;/li&gt;
&lt;li&gt;afterEach()
Read more about mocha Mocha Framework &lt;a href="https://mochajs.org/" rel="noopener noreferrer"&gt;here&lt;/a&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The above are hooks you run before or after the test function. The implementation is shown in the example below. The before and after() hooks run once, while beforeEach and afterEach run before and after every it() .&lt;/p&gt;

&lt;p&gt;Open the test.js file and import the assert module and any other module needed. See the example below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import assert from "assert/strict";
import { describe } from "node:test";
import { Student } from "../model/schema.js";
import { connectToDb,conClose } from "../model/connection.js";

describe('CRUD test',function(){

before(function(){
 connectToDb()
})
it('document should save without an error', function(done){
    const result=  new Student({email:"eyitayo@yahoo.com",pwd:"Sep215"})
    result.save(done)

  })
it('collection should return length greater than 0',async function(){
  const result= await Student.find({})
  assert.notStrictEqual(result.length, 0)

})
it('document should update without an error', async function( ){
    const query= await Student.updateOne({email:"eyitt@yahoo.com"},{firstname:'eyitayo',lastname:'itunu',gender:'male'})
    const result= await Student.findOne({email:'eyitayo@yahoo.com'})
    assert.strictEqual(result.lastname,'itunu')

  })
after(function(){
    conClose()
})
})
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the above example, the describe() has two parameters: a string that describes the test and a callback function. Inside the callback function is it(). It has two parameters: a string that describes the outcome and a callback function that contains the test code. The assert strict function is used to compare test values. Other assert functions are&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;assert.deepEqual()&lt;/li&gt;
&lt;li&gt;assert.deepStrictEqual()&lt;/li&gt;
&lt;li&gt;assert.notDeepEqual()&lt;/li&gt;
&lt;li&gt;assert.notDeepStrictEqual()&lt;/li&gt;
&lt;li&gt;assert.notEqual()&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Read more about [assert module]( &lt;a href="https://github.com/nodejs/node/blob/v19.0.1/lib/assert.js" rel="noopener noreferrer"&gt;https://github.com/nodejs/node/blob/v19.0.1/lib/assert.js&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To run the test, go to the terminal and type npm test, test result is shown below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;gt; lmsnj@1.0.0 test
&amp;gt; mocha test/test.js

# Subtest: CRUD test
ok 1 - CRUD test
  ---
  duration_ms: 0.0530164
  ...



connected to MongoDb successfully
  1) document should save without an error
  ✔ collection should return length greater than 0 (350ms)
  ✔ document should update without an error (1713ms)

  2 passing (5s)
  1 failing

  1) document should save without an error:
     Error: Timeout of 2000ms exceeded. For async tests and hooks, ensure "done()" is called; if returning a Promise, ensure it resolves. (C:\Users\USER\lmsnj\test\test.js)
      at listOnTimeout (node:internal/timers:559:17)
      at processTimers (node:internal/timers:502:7)



1..1
# tests 1
# pass 1
# fail 0
# cancelled 0
# skipped 0
# todo 0
# duration_ms 38.0393548
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The first test failed, while the other two passed and were marked accordingly.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Finally&lt;/strong&gt;&lt;br&gt;
Testing is an important aspect of software development. It ensures that the code does what it was written to do. Using a testing framework like mocha automates the process.&lt;/p&gt;

&lt;p&gt;If you find this post interesting, like and comment. &lt;/p&gt;

</description>
      <category>node</category>
      <category>webdev</category>
      <category>javascript</category>
      <category>express</category>
    </item>
    <item>
      <title>Take Your Web Development Skills to Next with Web API's</title>
      <dc:creator>Eyitayo Itunu Babatope</dc:creator>
      <pubDate>Fri, 17 Feb 2023 17:30:22 +0000</pubDate>
      <link>https://dev.to/eyitayoitalt/take-your-web-development-skills-to-next-with-web-apis-184h</link>
      <guid>https://dev.to/eyitayoitalt/take-your-web-development-skills-to-next-with-web-apis-184h</guid>
      <description>&lt;p&gt;Web API's is one of the most kept open secret in Web development. You hardly see it in text or any forum post. If you have used document.querySelector() or document.getElementById to interact with HTML element, you have made use of Web API's. Web API's are used typically with  JavaScript but it can be used with any programming Language. There are many many Web APIs available and it can be daunting going through each one. From media streaming to HTML drag and drop, Web API's are available. One thing is sure, Web API's will take your web development skills to another level.&lt;/p&gt;

&lt;p&gt;In this post and subsequent ones, I will demonstrate Web API's fuctionality. I will start with Web Share API for sharing text,links, files and  any content to any selected target.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Prerequisite: HTML, Javascript&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;Objective: To famailarise readers with Web Share API&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The Web share API has two methods&lt;br&gt;
    1. navigator.canShare() method to validate data is shareble.&lt;br&gt;
    2. navigator.share() method invokes the native sharing mechanism of the underlying operating system.&lt;/p&gt;

&lt;p&gt;I will use the HTML skeleton below to demonstrate Web share API are at work.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;html&amp;gt;
&amp;lt;head&amp;gt;
&amp;lt;title&amp;gt;Share page &amp;lt;/title&amp;gt;
&amp;lt;/head&amp;gt;
&amp;lt;body&amp;gt;
        &amp;lt;div class="share"&amp;gt;

            &amp;lt;h1 class="groupH"&amp;gt;SHARE DONATION LINK&amp;lt;/h1&amp;gt;
            &amp;lt;p class="groupP"&amp;gt;Share a link to family and friends to make DONATION to your alma mata&amp;lt;/p&amp;gt;

            &amp;lt;button class="btn-secondary share-link" type="submit" onclick="shareLink()"&amp;gt;SHARE DONATION LINK&amp;lt;/button&amp;gt;
        &amp;lt;/div&amp;gt;
 &amp;lt;script type="text/javascript"&amp;gt;
        const shareData = {
            title: 'Donation',
            text: 'Donation for my Alma matter',
            url: 'http://localhost:3080/share'
        }
        const shareLink = async (event) =&amp;gt; {

            try {
                await navigator.share(shareData)
                console.log('Donation shared successfully')
            } catch (err) {
                console.log(err)
            }
        }


    &amp;lt;/script&amp;gt;
&amp;lt;/body&amp;gt;
&amp;lt;html&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the script tag, I created a javascript object shareData that has the web page I want to share. I called navigator.share() with the shareData as parameter inside shareLink function. ShareLink is triggered when the user clicks the Share Donation Button. This will trigger the operating system sharing mechanism. &lt;/p&gt;

&lt;h2&gt;
  
  
  Finally
&lt;/h2&gt;

&lt;p&gt;As demonstrated above, Web API's makes  web development easy. In my next post, I will demonstrate how to use Web Share API to share files. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Like and comment&lt;/strong&gt;, if you find this post educative.&lt;/p&gt;

</description>
      <category>watercooler</category>
    </item>
    <item>
      <title>Take Your Web Development Skills to Next Level with Web API's</title>
      <dc:creator>Eyitayo Itunu Babatope</dc:creator>
      <pubDate>Thu, 02 Feb 2023 12:13:12 +0000</pubDate>
      <link>https://dev.to/eyitayoitalt/take-your-web-development-skills-to-next-with-web-apis-1n26</link>
      <guid>https://dev.to/eyitayoitalt/take-your-web-development-skills-to-next-with-web-apis-1n26</guid>
      <description>&lt;p&gt;Web API's is one of the most kept open secret in Web development. You hardly see it in text or any forum post. If you have used document.querySelector() or document.getElementById to interact with HTML element, you have made use of Web API's. Web API's are used typically with  JavaScript but it can be used with any programming Language. There are many many Web APIs available and it can be daunting going through each one. From media streaming to HTML drag and drop, Web API's are available. One thing is sure, Web API's will take your web development skills to another level.&lt;/p&gt;

&lt;p&gt;In this post and subsequent ones, I will demonstrate Web API's fuctionality. I will start with Web Share API for sharing text,links, files and  any content to any selected target.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Prerequisite: HTML, Javascript&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;Objective: To famailarise readers with Web Share API&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The Web share API has two methods&lt;br&gt;
    1. navigator.canShare() method to validate data is shareble.&lt;br&gt;
    2. navigator.share() method invokes the native sharing mechanism of the underlying operating system.&lt;/p&gt;

&lt;p&gt;I will use the HTML skeleton below to demonstrate Web share API at work.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;html&amp;gt;
&amp;lt;head&amp;gt;
&amp;lt;title&amp;gt;Share page &amp;lt;/title&amp;gt;
&amp;lt;/head&amp;gt;
&amp;lt;body&amp;gt;
        &amp;lt;div class="share"&amp;gt;

            &amp;lt;h1 class="groupH"&amp;gt;SHARE DONATION LINK&amp;lt;/h1&amp;gt;
            &amp;lt;p class="groupP"&amp;gt;Share a link to family and friends to make DONATION to your alma mata&amp;lt;/p&amp;gt;

            &amp;lt;button class="btn-secondary share-link" type="submit" onclick="shareLink()"&amp;gt;SHARE DONATION LINK&amp;lt;/button&amp;gt;
        &amp;lt;/div&amp;gt;
 &amp;lt;script type="text/javascript"&amp;gt;
        const shareData = {
            title: 'Donation',
            text: 'Donation for my Alma matter',
            url: 'http://localhost:3080/share'
        }
        const shareLink = async (event) =&amp;gt; {

            try {
                await navigator.share(shareData)
                console.log('Donation shared successfully')
            } catch (err) {
                console.log(err)
            }
        }


    &amp;lt;/script&amp;gt;
&amp;lt;/body&amp;gt;
&amp;lt;html&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the script tag, I created a javascript object shareData that has the web page link I want to share. I called navigator.share() with the shareData as parameter inside the shareLink function. When a user clicks the Share Donation Button, the operating system sharing mechanism will be triggered.&lt;/p&gt;

&lt;h2&gt;
  
  
  Finally
&lt;/h2&gt;

&lt;p&gt;As demonstrated above, Web API's makes  web development easy. In my next post, I will demonstrate how to use Web Share API to share files. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Like and comment&lt;/strong&gt;, if you find this post educative.&lt;/p&gt;

</description>
      <category>blockchain</category>
      <category>crypto</category>
      <category>web3</category>
    </item>
    <item>
      <title>Responsive Web Design Hack</title>
      <dc:creator>Eyitayo Itunu Babatope</dc:creator>
      <pubDate>Mon, 16 Jan 2023 03:05:40 +0000</pubDate>
      <link>https://dev.to/eyitayoitalt/responsive-web-design-with-css-flex-2mlk</link>
      <guid>https://dev.to/eyitayoitalt/responsive-web-design-with-css-flex-2mlk</guid>
      <description>&lt;p&gt;Sometimes ago, I came across a post on the web that says " If you have to write many media queries and CSS to create a responsive web pages, then the design is faulty." I agree with this principle. With few lines of CSS, you can create responsive web pages adaptable to any device using CSS flex and common tricks. In this post, the reader will learn how to create responsive web pages with fewer lines of CSS code. This post assumes the reader knows the basic of CSS and CSS flex&lt;/p&gt;

&lt;h2&gt;
  
  
  Table of Content
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Introduction&lt;/li&gt;
&lt;li&gt;Relative Units&lt;/li&gt;
&lt;li&gt;Responsive design &amp;amp; CSS Flex box layout&lt;/li&gt;
&lt;li&gt;Conclusion&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Introduction
&lt;/h3&gt;

&lt;p&gt;Responsive web pages target the width of the device and not the height. It is natural to scroll up a web page but unnatural to scroll side ways. Scrolling sideways leads to poor user experience. So the hack of responsive web pages is to focus on the width of the html elements and make it adapt to the width of any device.&lt;/p&gt;

&lt;p&gt;The first step in developing responsive web pages with few CSS code and media query is to start with mobile version first.  A developer might be tempted to start with the desktop version because of the development environment, such as laptop and desktop. Later on, the developer writes media query to adapt to mobile devices. Experience have shown that this is a tedious process. So remember &lt;strong&gt;mobile first&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The second is to set the device viewport in the html head.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;head&amp;gt;
&amp;lt;meta name='viewport' content='width=device-width,intial-scale=1.0' &amp;gt;
&amp;lt;/head&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The above will control dimension and scale of the web page  read more about viewport&lt;a href="https://www.w3schools.com/css/css_rwd_viewport.asp" rel="noopener noreferrer"&gt;here&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Relative Unit
&lt;/h3&gt;

&lt;p&gt;One major hack of responsive web design is to use relative unit for the width of the element instead of fixed unit. Remember, responsive design is about the width of the device. Relative unit scale very well. Fixed unit don't change. Example of fixed unit are &lt;br&gt;
-px&lt;br&gt;
-cm&lt;br&gt;
-pt etc.&lt;/p&gt;

&lt;p&gt;relative unit are &lt;br&gt;
-rem&lt;br&gt;
-em&lt;br&gt;
-% &lt;br&gt;
-vh&lt;br&gt;
-vw etc.&lt;br&gt;
&lt;a href="https://blog.logrocket.com/using-em-vs-rem-css/#:~:text=Let's%20get%20started!-,What%20are%20em%20and%20rem%20and%20why%20use%20them%3F,relative%20to%20a%20set%20value." rel="noopener noreferrer"&gt;Read&lt;/a&gt; more about relative unit.&lt;/p&gt;

&lt;p&gt;rem unit are relative to the font size of the root html while em are relative to the font size of the nearest parent element. rem provides better control than em.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;html{
font-size:16px;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;2rem= 32px&lt;/p&gt;

&lt;p&gt;Another hack is to set the width of images and form elements such as input, button in percentages. The elements will scale nicely on any device.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;img{
  width:100%; 
height:10rem; /* 160px */
}

input{
 width: 60%;
}
button{
 width:30%;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;CSS flex box layout has made responsive web design easy. On mobile version set your flex box direction to column. All the element in the flex container will be displayed stacked on one another. On larger devices, you can set the flex direction to row, to display element side by side.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Mobile version&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;div{
 display:flex;
flex-direction:column;
width:100%;

}

@media screen and (min-width:1000px){

div{
  display:flex;
flex-direction:row;
}


}

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

&lt;/div&gt;



&lt;p&gt;Another hack is to set the flex-flow property of the flex box to row wrap. The element inside the flex box will stack on one another or flow side by side depending on the width of the element.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;div{
  display:flex;
flex-flow: row wrap;

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

&lt;/div&gt;



&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;It is most likely that your web page will be viewed on mobile device. In November 2022, about 50 percent of internet traffic came from a mobile device. This figure will continue to rise. Hence, it is imperative to develop a website that will adapt to most devices. The objective of this post is to enable developers to design responsive web page with ease.&lt;/p&gt;

&lt;p&gt;If you find this post educative, comment and like.&lt;/p&gt;

</description>
      <category>discuss</category>
    </item>
    <item>
      <title>Hack CSS GROUPING SELECTORS</title>
      <dc:creator>Eyitayo Itunu Babatope</dc:creator>
      <pubDate>Wed, 11 Jan 2023 10:02:33 +0000</pubDate>
      <link>https://dev.to/eyitayoitalt/hack-css-grouping-selectors-gp3</link>
      <guid>https://dev.to/eyitayoitalt/hack-css-grouping-selectors-gp3</guid>
      <description>&lt;p&gt;This article is for intermediate or entry level frontend developers interested  in  CSS Grouping selectors. The writer assumes that the reader has basic knowledge of CSS selectors, HTML elements. This  article will not cover other type of selectors . At the end of the article, the reader can style nested HTML elements with CSS grouping selectors. The article will utilize a basic HTML layout to demonstrate CSS grouping selectors at work.&lt;/p&gt;

&lt;p&gt;HTML Layout.&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%2Fwbyq5z6bisptw4bwem4x.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%2Fwbyq5z6bisptw4bwem4x.png" alt="Image description" width="800" height="353"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Types of grouping Selectors&lt;br&gt;
1)Selector list (“,”): Two or more CSS selectors separated by comma(s). From the above HTML, below is an example of selector list. &lt;/p&gt;

&lt;p&gt;.header-content, .content-input, .header-people{&lt;br&gt;
background-color: red;&lt;br&gt;
}&lt;br&gt;
The above styles will give the three classes a background color of red.&lt;/p&gt;

&lt;p&gt;2) Descendant selectors ("  " ): It is an empty space  two CSS selectors.&lt;/p&gt;

&lt;p&gt;.container  p{&lt;br&gt;
color:#FF4820&lt;/p&gt;

&lt;p&gt;}&lt;br&gt;
The style above gives all the p element and any element within p such as the span element an orange colour.&lt;/p&gt;

&lt;p&gt;3) Child selectors “&amp;gt;”: Greater than sign between two CSS selectors D&amp;gt;E. The style affects all E that are directly within D and not those inside E.&lt;br&gt;
.container &amp;gt;p{&lt;br&gt;
color:#FF4820&lt;/p&gt;

&lt;p&gt;}&lt;br&gt;
The style will only affect the p element and not the span element.&lt;/p&gt;

&lt;p&gt;4)Sibling selector (~): Given two CSS selectors A~B, the sibling selector select all B that follows A.&lt;br&gt;
H1~p{&lt;br&gt;
      font-family:verdana;&lt;br&gt;
      font-size:24px;&lt;/p&gt;

&lt;p&gt;}&lt;br&gt;
The above will style all p elements that follows h1&lt;br&gt;
5) Adjacent Sibling Selector (+): Given two CSS selectors D+E. The style will affect the first E that follows D.&lt;br&gt;
h1+p{&lt;br&gt;
       font-family:verdana;&lt;br&gt;
      font-size:24px;&lt;/p&gt;

&lt;p&gt;}&lt;br&gt;
The style will affect the first p that follows h1.&lt;/p&gt;

&lt;p&gt;Take note that grouping selectors can be nested. For example&lt;/p&gt;

&lt;p&gt;.container .header-content &amp;gt;p {&lt;/p&gt;

&lt;p&gt;}&lt;br&gt;
It means style a element p that is a child of class header-content, a descendant of class container.&lt;/p&gt;

&lt;p&gt;The article listed different CSS grouping selectors with examples. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Selector List&lt;/li&gt;
&lt;li&gt;Descendant Selector&lt;/li&gt;
&lt;li&gt;Child Selector&lt;/li&gt;
&lt;li&gt;Sibling Selector&lt;/li&gt;
&lt;li&gt;Adjacent selector
Also, the articles demonstrated nesting of grouping selectors.&lt;/li&gt;
&lt;/ul&gt;

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