{
  "slug": "Small-Example-of-Solidity-Project-41cb5f9f801d",
  "title": "Small Example of Solidity Project",
  "subtitle": "I want to review all the techniques used in this small solidity project in this article.",
  "excerpt": "I want to review all the techniques used in this small solidity project in this article.",
  "date": "2023-12-14",
  "tags": [],
  "readingTime": "12 min",
  "url": "https://medium.com/@mobinshaterian/small-example-of-solidity-project-41cb5f9f801d",
  "hero": "https://cdn-images-1.medium.com/max/800/1*y_UjKC9cJ9Xez2Rb5O9f8g.png",
  "content": [
    {
      "type": "heading",
      "level": 2,
      "text": "Small Example of Solidity Project"
    },
    {
      "type": "paragraph",
      "html": "I want to review all the techniques used in this small solidity project in this article."
    },
    {
      "type": "heading",
      "level": 2,
      "text": "Type of variables in solidity"
    },
    {
      "type": "code",
      "lang": "solidity",
      "code": "// SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.4.22 <0.9.0;\n///\n@title A contract for demonstrate Value types///\n@author Jitendra Kumar///\n@notice For now, this contract just show how Value types works in soliditycontract Types {\n  // Initializing Bool\n  variable bool public boolean = false;\n  // Initializing Integer\n  variable int32 public int_var = -60313;\n  // Initializing String\n  variable string public str = \"GeeksforGeeks\";\n  // Initializing Byte\n  variable bytes1 public b = \"a\";\n  // Defining an enumerator enum my_enum {\n    geeks_, _for, _geeks\n  }\n  // Defining a\n  function to return // values stored in an enumerator\n  function Enum() public pure returns(my_enum) {\n    return my_enum._geeks;\n  }\n}"
    },
    {
      "type": "code",
      "lang": "solidity",
      "code": "// SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.4.22 <0.9.0;\n///\n@title A contract for demonstrate Reference types///\n@author Jitendra Kumar///\n@notice For now, this contract just show how Reference types works in soliditycontract\nmapping_example {\n  // Defining an array uint[5] public array = [uint(1), 2, 3, 4, 5];\n  // Defining a Structure struct student {\n    string name;\n    string subject;\n    uint8 marks;\n  }\n  // Creating a structure object student public std1;\n  // Defining a\n  function to return // values of the elements of the structure\n  function structure() public returns(string memory, string memory, uint){\n    std1.name = \"John\";\n    std1.subject = \"Chemistry\";\n    std1.marks = 88;\n    return (std1.name, std1.subject, std1.marks);\n  }\n  // Creating a mapping mapping (address => student) result;\n  address[] student_result;\n}"
    },
    {
      "type": "heading",
      "level": 2,
      "text": "Units and Globally Available Variables"
    },
    {
      "type": "list",
      "ordered": false,
      "items": [
        "<code>msg.data</code> (<code>bytes calldata</code>): complete calldata",
        "<code>msg.sender</code> (<code>address</code>): sender of the message (current call)",
        "<code>msg.sig</code> (<code>bytes4</code>): first four bytes of the calldata (i.e. function identifier)"
      ]
    },
    {
      "type": "image",
      "src": "https://cdn-images-1.medium.com/max/800/1*y_UjKC9cJ9Xez2Rb5O9f8g.png",
      "alt": "Small Example of Solidity Project",
      "caption": "",
      "width": 831,
      "height": 608
    },
    {
      "type": "heading",
      "level": 2,
      "text": "Solidity — Reference Types"
    },
    {
      "type": "paragraph",
      "html": "Solidity references store and modify complicated data structures including arrays, structs, maps, and strings. These data types hold a reference to the data’s memory or storage location, unlike value types like integers and booleans. Reference types are vital for developing complicated Ethereum smart contracts since they allow for more data structure and manipulation."
    },
    {
      "type": "heading",
      "level": 3,
      "text": "1. Fixed-Size Arrays"
    },
    {
      "type": "code",
      "lang": "solidity",
      "code": "// Solidity program to implement // the fixed-size arrays// SPDX-License-Identifier: MITpragma\nsolidity ^0.8.0;\ncontract FixedSizeArrayExample {\n  uint[5] fixedSizeArray;\n  function populateArray() public {\n    for (uint i = 0;\n    i < 5;\n    i++) {\n      fixedSizeArray[i] = i + 1;\n    }\n  }\n  function getArray() public view returns (uint[5] memory) {\n    return fixedSizeArray;\n  }\n}"
    },
    {
      "type": "heading",
      "level": 3,
      "text": "2. Dynamic-Size Arrays"
    },
    {
      "type": "code",
      "lang": "solidity",
      "code": "// Solidity program to implement // the Dynamic-Size Arrays// SPDX-License-Identifier: MITpragma\nsolidity ^0.8.0;\ncontract DynamicSizeArrayExample {\n  uint[] dynamicSizeArray;\n  function addElement(uint _value) public {\n    dynamicSizeArray.push(_value);\n  }\n  function getArray() public view returns (uint[] memory) {\n    return dynamicSizeArray;\n  }\n}"
    },
    {
      "type": "heading",
      "level": 3,
      "text": "3. Array Members"
    },
    {
      "type": "code",
      "lang": "solidity",
      "code": "// Solidity program to implement// the array memberspragma solidity ^0.5.0;\n// Creating a contractcontract Types {\n  // Declaring an array uint[] data = [10, 20, 30, 40, 50];\n  // Defining a\n  function to find the length // of the array\n  function array_length() public returns(uint) {\n    uint x = data.length;\n    return x;\n  }\n  // Defining the\n  function to push values to the array function array_push() public returns(uint[] memory) {\n    data.push(60);\n    data.push(70);\n    data.push(80);\n    return data;\n  }\n  // Defining a\n  function to pop values from the array function array_pop() public returns(uint[] memory) {\n    data.pop();\n    return data;\n  }\n}"
    },
    {
      "type": "heading",
      "level": 3,
      "text": "4. Byte Arrays"
    },
    {
      "type": "code",
      "lang": "solidity",
      "code": "// Solidity program to implement // the byte arrayspragma solidity ^0.8.0;\ncontract ByteArrayExample {\n  bytes3 fixedSizeByteArray;\n  bytes dynamicSizeByteArray;\n  constructor() {\n    // \"abc\" fixedSizeByteArray = 0x616263;\n    // \"defghi\" dynamicSizeByteArray = hex\"646566676869\";\n  }\n  function getFixedSizeByteArray() public view returns (bytes3) {\n    return fixedSizeByteArray;\n  }\n  function getDynamicSizeByteArray() public view returns (bytes memory) {\n    return dynamicSizeByteArray;\n  }\n}"
    },
    {
      "type": "heading",
      "level": 3,
      "text": "Structs"
    },
    {
      "type": "paragraph",
      "html": "Structs in Solidity allow you to define custom data structures with various properties. A struct is a composite type that groups different properties (of various types) under a single type."
    },
    {
      "type": "code",
      "lang": "solidity",
      "code": "// Solidity program to implement Structspragma solidity ^0.8.0;\ncontract StructsExample {\n  struct Person {\n    string name;\n    uint age;\n  }\n  Person[] public people;\n  function addPerson(string memory _name, uint _age) public {\n    Person memory newPerson = Person(_name, _age);\n    people.push(newPerson);\n  }\n  function getPerson(uint index) public view returns (string memory, uint) {\n    Person memory person = people[index];\n    return (person.name, person.age);\n  }\n}"
    },
    {
      "type": "paragraph",
      "html": "In Solidity, we use the memory keyword <strong>to store the data temporarily during the execution of a smart contract</strong>. When a variable is declared using the memory keyword, it is stored in the memory area of the EVM Ethereum Virtual Machine&nbsp;. This is the default storage location for variables in Solidity."
    },
    {
      "type": "heading",
      "level": 3,
      "text": "Mappings"
    },
    {
      "type": "paragraph",
      "html": "Mappings are a key-value data structure in Solidity, similar to associative arrays or hash maps in other programming languages. They allow you to associate a value with a key."
    },
    {
      "type": "code",
      "lang": "solidity",
      "code": "// Solidity program to implement // the Mappingspragma solidity ^0.8.0;\ncontract MappingsExample {\n  mapping(address => uint) public balances;\n  function updateBalance(address _account, uint _newBalance) public {\n    balances[_account] = _newBalance;\n  }\n  function getBalance(address _account) public view returns (uint) {\n    return balances[_account];\n  }\n}"
    },
    {
      "type": "heading",
      "level": 2,
      "text": "UnimplementedFeatureError: Nested dynamic arrays not implemented here."
    },
    {
      "type": "paragraph",
      "html": "Solidity and Javascript allow nested arrays but <strong>we do not have the ability to pull a nested dynamic array from the solidity over to javascript world</strong>. it is the limitation of the bridge between solidity and javascript."
    },
    {
      "type": "heading",
      "level": 3,
      "text": "Solidity is still in development and that’s why it still lacks in a lot of features that a good programming language should have. One of the features which solidity is missing is that it cannot return or take multi-dimensional arrays as input."
    },
    {
      "type": "paragraph",
      "html": "Step 1: Serialize &amp; De-serialize using solidity"
    },
    {
      "type": "paragraph",
      "html": "Step 2: De-serialize the byte buffer using javascript"
    },
    {
      "type": "heading",
      "level": 2,
      "text": "Payable Functions"
    },
    {
      "type": "paragraph",
      "html": "In Solidity, a payable function is a function that can accept ether as an input. When a contract is called with a payable function, the caller can send ether along with the function call. The ether is then stored in the contract’s balance, which can be accessed using the “address(this).balance” property."
    },
    {
      "type": "heading",
      "level": 2,
      "text": "How to declare a payable function"
    },
    {
      "type": "paragraph",
      "html": "In Solidity, you use the payable function when you want to allow a contract to receive ether. A payable function is declared using the ‘payable’ keyword, which makes it possible to receive ether as part of a function call. See code example below;"
    },
    {
      "type": "code",
      "lang": "solidity",
      "code": "//SPDX-License-Identifier: MITpragma solidity ^0.8.0;\ncontract Payable{\n  mapping(address => uint256) balances;\n  function deposit() external payable {\n    require(msg.value > 0, \"Zero ether not allowed\");\n    balances[msg.sender] = balances[msg.sender] + msg.value;\n  }\n}"
    },
    {
      "type": "heading",
      "level": 2,
      "text": "What is an example of a Solidity payable function?"
    },
    {
      "type": "paragraph",
      "html": "Here is an example of a basic payable function in Solidity with the <strong>deposit</strong> function:"
    },
    {
      "type": "code",
      "lang": "javascript",
      "code": "function deposit() payable external {\n  // no need to write anything here!\n}"
    },
    {
      "type": "paragraph",
      "html": "Notice, in this case, we didn’t write any code in the <strong>deposit</strong> function body. Writing a payable function alone is enough to receive ether and you may not need to write any logic."
    },
    {
      "type": "paragraph",
      "html": "For example, if this was a payable smart contract that was controlled by a charity accepting cryptocurrency donations, perhaps users would just call <strong>deposit</strong> and the charity would eventually be able to withdraw these contributions to an address of their choosing. In that case, it may be better to write a <strong>receive</strong> function:"
    },
    {
      "type": "code",
      "lang": "solidity",
      "code": "receive() external payable {    // this built-in function\ndoesn't require any calldata,    // it will get called if the data field is empty and     // the value field is not empty.    // this allows the smart contract to receive ether just like a     // regular user account controlled by a private key would.}"
    },
    {
      "type": "heading",
      "level": 2,
      "text": "What is Require in Solidity?"
    },
    {
      "type": "paragraph",
      "html": "As the word suggests, require basically means to demand something before availing the service to the users. For example, websites require you to create an account or login into an existing account before giving you access to the account which belongs to you. This is the basic flow of how ‘require’ works in Solidity also. Suppose there are is an account used by Suyash and he wants to send five Ethereum to an account used by Aditya. Now in order for Suyash to send Ethereum to Aditya, Suyash should have at least five Ethereum in his account to send the money to Aditya. So in the Solidity code, we can “require” the sender’s balance to be greater than or equal to the balance he wants to send to the receiver otherwise the transaction should obviously fail. This is just an example of the numerous use cases that use “require” and enable us to perform multiple checks before approving a transaction or anything else."
    },
    {
      "type": "code",
      "lang": "solidity",
      "code": "pragma solidity ^0.8.4;\ncontract Bank {\n  mapping(address => uint) balance;\n  address owner;\n  constructor() {\n    owner = msg.sender;\n    // address that deploys contract will be the owner\n  }\n  function addBalance(uint _toAdd) public returns(uint) {\n    require(msg.sender == owner);\n    balance[msg.sender] += _toAdd;\n    return balance[msg.sender];\n  }\n  function getBalance() public view returns(uint) {\n    return balance[msg.sender];\n  }\n  function transfer(address recipient, uint amount) public {\n    require(balance[msg.sender]>=amount, \"Insufficient Balance\");\n    require(msg.sender != recipient, \"You can't send money to yourself!\");\n    _transfer(msg.sender, recipient, amount);\n  }\n  function _transfer(address from, address to, uint amount) private {\n    balance[from] -= amount;\n    balance[to] += amount;\n  }\n}"
    },
    {
      "type": "heading",
      "level": 2,
      "text": "The Revert Function in Solidity"
    },
    {
      "type": "paragraph",
      "html": "The <strong>revert</strong> function is similar to the require function in that it’s used to revert a transaction if a condition is not met. However, the revert function provides more flexibility in error handling and allows you to provide a reason string to explain why the transaction was reverted. Here’s an example:"
    },
    {
      "type": "code",
      "lang": "javascript",
      "code": "function withdraw(uint amount) public {\n  require(balances[msg.sender] >= amount, \"Insufficient balance\");\n  balances[msg.sender] -= amount;\n  if (!msg.sender.send(amount)) {\n    revert(\"Failed to send funds\");\n  }\n}"
    },
    {
      "type": "heading",
      "level": 2,
      "text": "msg.value is included along with the transaction,"
    },
    {
      "type": "list",
      "ordered": false,
      "items": [
        "<code>msg.value</code> (<code>uint</code>): number of wei sent with the message"
      ]
    },
    {
      "type": "heading",
      "level": 2,
      "text": ". `require`: Validate Inputs and Conditions"
    },
    {
      "type": "paragraph",
      "html": "The `require` function acts as a guard, validating inputs and conditions before executing specific parts of the code. It ensures that the specified conditions are met, and if not, it throws an error and reverts all changes made to the contract’s state. This function is commonly used to validate inputs, check conditions before execution, and validate return values from other functions."
    },
    {
      "type": "code",
      "lang": "solidity",
      "code": "require(_i > 10, “Input must be greater than 10”);"
    },
    {
      "type": "heading",
      "level": 2,
      "text": "How to generate random numbers in solidity?"
    },
    {
      "type": "paragraph",
      "html": "We’ll call the keccak256() function that will compute the hash of the input using the keccak256 hash algorithm. This function takes a single argument of type bytes, and since we want my random number to be computed based on more random values, we will call another function called abi.encode.Packed() is the function that will perform packed encoding of the given arguments and return a variable of type bytes. The function’s arguments are: (msg. sender), (block. timestamp), and our variable, which can also include (block. difficulty) with other global variables to make it more complex."
    },
    {
      "type": "code",
      "lang": "solidity",
      "code": "//SPDX-License-Identifier: GPL-3.0pragma solidity >=0.8.7;\ncontract RandomNumber {\n  uint randNo = 0;\n  function setNumber() external {\n    randNo= uint (keccak256(abi.encodePacked (msg.sender, block.timestamp, randNo)));\n  }\n  function getNumber() external view returns (uint) {\n    return randNo;\n  }\n}"
    },
    {
      "type": "paragraph",
      "html": "Randomness can’t be done in Solidity. If you aren’t worried about someone gaming this, then you can sha256 the timestamp, then hash that hash to get another hash, then hash that hash to get another, and so on."
    },
    {
      "type": "image",
      "src": "https://cdn-images-1.medium.com/max/800/1*YLFcvG7JkLmM6Vw94VIbvw.png",
      "alt": "Small Example of Solidity Project",
      "caption": "",
      "width": 825,
      "height": 104
    },
    {
      "type": "heading",
      "level": 2,
      "text": "How to transfer Ether in solidity"
    },
    {
      "type": "list",
      "ordered": false,
      "items": [
        "<strong>Using the </strong><code><strong>transfer</strong></code><strong> function: </strong>The transfer function is the simplest and safest method to transfer Ether in Solidity. The transfer function sends the specified amount of Ether to the recipient’s address. If the transfer fails (e.g., due to out-of-gas conditions or revert in the recipient’s contract), an exception is thrown, and the entire transaction is reverted. It provides basic security by reverting the transfer if something goes wrong.<strong> Syntax: </strong><code>recipient.transfer(amount);</code>"
      ]
    },
    {
      "type": "heading",
      "level": 2,
      "text": "transfer vs send vs call"
    },
    {
      "type": "list",
      "ordered": true,
      "items": [
        "<strong><em>transfer </em></strong>-&gt; the receiving smart contract should have a <strong><em>fallback </em></strong>function defined or else the transfer call will throw an <strong>error</strong>. There is a gas limit of <strong>2300 gas</strong>, which is enough to complete the transfer operation. It is hardcoded to prevent <strong>reentrancy attacks</strong>."
      ]
    },
    {
      "type": "image",
      "src": "https://cdn-images-1.medium.com/max/800/0*Q_X25Zfyfzp1Ns4O.png",
      "alt": "Small Example of Solidity Project",
      "caption": "",
      "width": 549,
      "height": 78
    },
    {
      "type": "paragraph",
      "html": "transfer() function"
    },
    {
      "type": "paragraph",
      "html": "2. <strong><em>send </em></strong>-&gt; It works in a similar way as to transfer call and has a gas limit of <strong>2300 gas</strong> as well. It returns the status as a <strong>boolean</strong>."
    },
    {
      "type": "image",
      "src": "https://cdn-images-1.medium.com/max/800/0*cz1EX1uMrIfgSzmG.png",
      "alt": "Small Example of Solidity Project",
      "caption": "",
      "width": 538,
      "height": 91
    },
    {
      "type": "paragraph",
      "html": "send() function"
    },
    {
      "type": "paragraph",
      "html": "3. <strong><em>call </em></strong>-&gt;It is the recommended way of sending ETH to a smart contract. The empty argument triggers the <strong><em>fallback </em></strong>function of the receiving address."
    },
    {
      "type": "heading",
      "level": 2,
      "text": "How to Get a Smart Contract’s Balance in Solidity"
    },
    {
      "type": "paragraph",
      "html": "In order to <strong>get the balance of a smart contract</strong>, you first need to obtain the contract address. For that, you can use the <code>this</code> keyword which refers to the contract itself."
    },
    {
      "type": "paragraph",
      "html": "Once you have the contract address, you can call <strong>the </strong><code><strong>balance</strong></code><strong> property, which will return the contract balance.</strong>"
    },
    {
      "type": "paragraph",
      "html": "You can do this in a single line of code 👇"
    },
    {
      "type": "code",
      "lang": "text",
      "code": "address(this).balance;"
    },
    {
      "type": "paragraph",
      "html": "If what you want is to obtain the balance of a different contract, you can use a function like this:"
    },
    {
      "type": "code",
      "lang": "javascript",
      "code": "function getContractBalance(address ContractAddress) public view returns(uint){\n  return ContractAddress.balance;\n}"
    },
    {
      "type": "heading",
      "level": 2,
      "text": "The amount of Ether in this particular smart contract."
    },
    {
      "type": "heading",
      "level": 3,
      "text": "For example: If you deploy this smart contract and send it 5 Eth. Then this function will return “5”."
    },
    {
      "type": "code",
      "lang": "solidity",
      "code": "contract Helper {\n  function getBalance() returns (uint bal) {\n    return this.balance;\n  }\n}"
    },
    {
      "type": "heading",
      "level": 2,
      "text": "New the array address or reset the value of array"
    },
    {
      "type": "code",
      "lang": "solidity",
      "code": "address[] myArray = new address[](0); //dynamic arraymyArray = new address[2](0); //fix array"
    },
    {
      "type": "heading",
      "level": 2,
      "text": "Solidity — Function Modifiers"
    },
    {
      "type": "paragraph",
      "html": "Function Modifiers are used to modify the behaviour of a function. For example to add a prerequisite to a function."
    },
    {
      "type": "code",
      "lang": "solidity",
      "code": "contract Owner {   modifier onlyOwner {      require(msg.sender == owner);      _;   }   modifier\ncosts(uint price) {      if (msg.value >= price) {         _;      }   }}"
    },
    {
      "type": "heading",
      "level": 2,
      "text": "toWei"
    },
    {
      "type": "paragraph",
      "html": "Converts any <a href=\"http://ethdocs.org/en/latest/ether.html\" target=\"_blank\" rel=\"noreferrer noopener\">ether value</a> value into <a href=\"http://ethereum.stackexchange.com/questions/253/the-ether-denominations-are-called-finney-szabo-and-wei-what-who-are-these-na\" target=\"_blank\" rel=\"noreferrer noopener\">wei</a>."
    },
    {
      "type": "code",
      "lang": "javascript",
      "code": "web3.utils.toWei(number [, unit])"
    },
    {
      "type": "heading",
      "level": 2,
      "text": "Nodejs Try catch"
    },
    {
      "type": "paragraph",
      "html": "For handling errors must use the try catch mechanism."
    },
    {
      "type": "code",
      "lang": "text",
      "code": "try {      await enterPlayerInLottery(lottery, accounts[4], web3, 0);      assert(false);    } catch\n(error) {      assert(error);    }"
    },
    {
      "type": "heading",
      "level": 2,
      "text": "web3.eth.getBalance"
    },
    {
      "type": "paragraph",
      "html": "Get the balance of an address at a given block."
    },
    {
      "type": "heading",
      "level": 2,
      "text": "I deploy a smart contract on network, Is it possible run exact this smart contract on network again ?"
    },
    {
      "type": "paragraph",
      "html": "No, once you deploy a smart contract on a blockchain network, it cannot be directly deployed again. This is because the blockchain is a distributed ledger, meaning that all of the nodes on the network maintain a copy of the same data. Once a smart contract has been deployed, its code is embedded into the blockchain and can only be modified by consensus of the network participants."
    },
    {
      "type": "paragraph",
      "html": "If you need to make changes to the logic of a deployed smart contract, you will need to create a new smart contract and deploy it to the network. This new smart contract can then interact with the old smart contract to make the desired changes. This process is often referred to as “smart contract upgrades” or “contract redeployment.”"
    },
    {
      "type": "paragraph",
      "html": "Here are some considerations when upgrading a smart contract:"
    },
    {
      "type": "list",
      "ordered": true,
      "items": [
        "Compatibility: Ensure that the new smart contract is compatible with the old one. This includes the ABI (Application Binary Interface) and any external dependencies.",
        "Backward Compatibility: If possible, maintain backward compatibility so that existing applications and users can still interact with the smart contract after the upgrade.",
        "Testing and Security: Thoroughly test the new smart contract to ensure it functions correctly and does not introduce any new vulnerabilities.",
        "Migration Plan: Develop a clear migration plan that outlines the steps involved in upgrading the smart contract, including communication with users and stakeholders.",
        "Gradual Deployment: Consider deploying the new smart contract in stages or with a gradual rollout to minimize any disruptions."
      ]
    },
    {
      "type": "paragraph",
      "html": "Upgrading smart contracts can be complex and requires careful planning and execution. It’s crucial to prioritize security and compatibility while ensuring a smooth transition for users and applications."
    },
    {
      "type": "paragraph",
      "html": "<a href=\"https://bard.google.com/\" target=\"_blank\" rel=\"noreferrer noopener\">https://bard.google.com/</a>"
    },
    {
      "type": "heading",
      "level": 2,
      "text": "Project code"
    },
    {
      "type": "heading",
      "level": 2,
      "text": "Writing tests"
    },
    {
      "type": "heading",
      "level": 2,
      "text": "Stackademic"
    },
    {
      "type": "paragraph",
      "html": "<em>Thank you for reading until the end. Before you go:</em>"
    },
    {
      "type": "list",
      "ordered": false,
      "items": [
        "<em>Please consider </em><strong><em>clapping</em></strong><em> and </em><strong><em>following</em></strong><em> the writer! 👏</em>",
        "<em>Follow us on </em><a href=\"https://twitter.com/stackademichq\" target=\"_blank\" rel=\"noreferrer noopener\"><strong><em>Twitter(X)</em></strong></a><em>, </em><a href=\"https://www.linkedin.com/company/stackademic\" target=\"_blank\" rel=\"noreferrer noopener\"><strong><em>LinkedIn</em></strong></a><em>, and </em><a href=\"https://www.youtube.com/c/stackademic\" target=\"_blank\" rel=\"noreferrer noopener\"><strong><em>YouTube</em></strong></a><strong><em>.</em></strong>",
        "<em>Visit </em><a href=\"http://stackademic.com/\" target=\"_blank\" rel=\"noreferrer noopener\"><strong><em>Stackademic.com</em></strong></a><em> to find out more about how we are democratizing free programming education around the world.</em>"
      ]
    }
  ]
}
