From 7240d8199fba637298249c9098403c643201e613 Mon Sep 17 00:00:00 2001 From: Markus Bielaszka <69858432+Markus-55@users.noreply.github.com> Date: Sun, 10 Jul 2022 13:29:02 +0200 Subject: [PATCH 1/9] Switch chain on front-end and check assets --- assets/js/spread/app.js | 41 +++++++++++++++++++++++++++++------- assets/js/spread/elements.js | 32 ++++++++++++++++++++++++---- assets/js/spread/utils.js | 5 +++++ spread-dapp.html | 23 +++++++++++++++++++- 4 files changed, 88 insertions(+), 13 deletions(-) diff --git a/assets/js/spread/app.js b/assets/js/spread/app.js index b6a6f15..f5b1c50 100644 --- a/assets/js/spread/app.js +++ b/assets/js/spread/app.js @@ -3,28 +3,53 @@ let user = Moralis.User.current(); if(!user) (Moralis.authenticate().then((user) => console.log(user)))(); // FIXME: logout. const logOut = async () => await Moralis.User.logOut(); +let selectedChain = document.querySelector("#selectedChain"); // Auto log in with metamask and get native assets and token balances. (async function () { + + let networkData = await getNetworkData(); + await getNetworkId(networkData[0], networkData[1]); + getAssets(networkData[0], networkData[1]); + + console.log(networkData[1][103]); +})() + +async function getNetworkData() { const web3Provider = await Moralis.enableWeb3(); const network = await web3Provider.getNetwork(); let response = await fetch("https://chainid.network/chains.json"); let data = await response.json(); - await getNativeAsset(network, data); - await getERC20Assets(); + return [network, data]; +} - selectAssets.addEventListener("change", (event) => token = event.target.value); -})() +selectedChain.addEventListener("change", async (event) => { + let chain = event.target.value; + + let networkData = await getNetworkData(); + switchNetwork(chain, networkData[0], networkData[1]); +}); +selectAssets.addEventListener("change", (event) => token = event.target.value); + +async function getNetworkId(network, data) { + let chainId = await Moralis.chainId; + + if(chainId === "0x1") { + document.getElementById("eth").selected = "true"; + } + else if(chainId === "0x89") { + document.getElementById("matic").selected = "true"; + } +} async function spread() { - const web3Provider = await Moralis.enableWeb3(); - const network = await web3Provider.getNetwork(); + let networkData = await getNetworkData(); - if(selectAssets.value === "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee") sendNativeAsset(network); + if(selectAssets.value === "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee") sendNativeAsset(networkData[0]); else if(selectAssets.value === "") { alert("Please select an asset to spread"); throw "no selected asset"; - } else sendErc20(token, network); + } else sendErc20(token, networkData[0]); } \ No newline at end of file diff --git a/assets/js/spread/elements.js b/assets/js/spread/elements.js index b88da10..dff8d8c 100644 --- a/assets/js/spread/elements.js +++ b/assets/js/spread/elements.js @@ -28,11 +28,11 @@ const getERC20Assets = async () => { for(let index in tokenBalances) { let newOption = document.createElement('option'); newOption.value = tokenBalances[index].token_address; - newOption.appendChild(document.createTextNode(`${tokenBalances[index].symbol}: ${Number(Moralis.Units.FromWei(tokenBalances[index].balance, tokenBalances[index].decimals)).toFixed(3)}`)); - - docFrag.appendChild(newOption); + newOption.innerHTML = `${tokenBalances[index].symbol}: ${Number(Moralis.Units.FromWei(tokenBalances[index].balance, tokenBalances[index].decimals)).toFixed(3)}`; + + selectAssets.append(newOption); } - selectAssets.appendChild(docFrag); + // selectAssets.appendChild(docFrag); } async function sendNativeAsset(network) { @@ -62,4 +62,28 @@ async function sendErc20(token, network) { } if (network.chainId === 1) await Moralis.executeFunction({msgValue: sumOf(valsToSum), contractAddress: spreadMainnet, ...spreadERC20Options}); if (network.chainId === 137) await Moralis.executeFunction({msgValue: sumOf(valsToSum), contractAddress: spreadPolygon, ...spreadERC20Options}); +} + +async function switchNetwork(chain, network, data) { + await Moralis.switchNetwork(chain); + + getAssets(network, data); +} + +async function addPolygonChain() { + const chainId = 137; + const chainName = "Polygon Mainnet"; + const currencyName = "Polygon"; + const currencySymbol = "MATIC"; + const rpcUrl = "https://polygon-rpc.com"; + const blockExplorerUrl = "https://polygonscan.com/"; + + await Moralis.addNetwork( + chainId, + chainName, + currencyName, + currencySymbol, + rpcUrl, + blockExplorerUrl + ); } \ No newline at end of file diff --git a/assets/js/spread/utils.js b/assets/js/spread/utils.js index a273297..7cdad3a 100644 --- a/assets/js/spread/utils.js +++ b/assets/js/spread/utils.js @@ -5,6 +5,11 @@ function sumOf(arr) { return total; } +async function getAssets(network, data) { + await getNativeAsset(network, data); + await getERC20Assets(); +} + function setTableValues() { let address = document.getElementById("input-address").value; let amount = document.getElementById("input-value").value; diff --git a/spread-dapp.html b/spread-dapp.html index 57afb0e..a235680 100644 --- a/spread-dapp.html +++ b/spread-dapp.html @@ -69,6 +69,27 @@ + + + + + + @@ -130,7 +151,7 @@
to broadcast, circulate
Ethereum Logo -
Spread your Ethereum assets across multiple accounts in one transaction.
+
Spread your assets across multiple accounts in one transaction.
From f04f544757419c9a642c7ff712852143bec428d0 Mon Sep 17 00:00:00 2001 From: Markus Bielaszka <69858432+Markus-55@users.noreply.github.com> Date: Sun, 10 Jul 2022 14:48:33 +0200 Subject: [PATCH 2/9] Update --- assets/js/spread/app.js | 41 +++++++++++------------- assets/js/spread/elements.js | 8 ++--- assets/js/spread/utils.js | 62 ++++++++++++++++++------------------ spread-dapp.html | 2 +- 4 files changed, 54 insertions(+), 59 deletions(-) diff --git a/assets/js/spread/app.js b/assets/js/spread/app.js index f5b1c50..bf64477 100644 --- a/assets/js/spread/app.js +++ b/assets/js/spread/app.js @@ -1,18 +1,17 @@ +let selectedChain = document.querySelector("#selectedChain"); +let token; + // FIXME: login. let user = Moralis.User.current(); if(!user) (Moralis.authenticate().then((user) => console.log(user)))(); // FIXME: logout. const logOut = async () => await Moralis.User.logOut(); -let selectedChain = document.querySelector("#selectedChain"); // Auto log in with metamask and get native assets and token balances. (async function () { - let networkData = await getNetworkData(); - await getNetworkId(networkData[0], networkData[1]); + await getNetworkId(); getAssets(networkData[0], networkData[1]); - - console.log(networkData[1][103]); })() async function getNetworkData() { @@ -25,31 +24,29 @@ async function getNetworkData() { return [network, data]; } -selectedChain.addEventListener("change", async (event) => { - let chain = event.target.value; - - let networkData = await getNetworkData(); - switchNetwork(chain, networkData[0], networkData[1]); -}); -selectAssets.addEventListener("change", (event) => token = event.target.value); - -async function getNetworkId(network, data) { +async function getNetworkId() { let chainId = await Moralis.chainId; - if(chainId === "0x1") { - document.getElementById("eth").selected = "true"; - } - else if(chainId === "0x89") { - document.getElementById("matic").selected = "true"; - } + if(chainId === "0x1") document.getElementById("eth").selected = "true"; + else if(chainId === "0x89") document.getElementById("matic").selected = "true"; + else document.getElementById("chooseChain").selected = "true"; } async function spread() { let networkData = await getNetworkData(); - + if(selectAssets.value === "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee") sendNativeAsset(networkData[0]); else if(selectAssets.value === "") { alert("Please select an asset to spread"); throw "no selected asset"; } else sendErc20(token, networkData[0]); -} \ No newline at end of file +} + +selectedChain.addEventListener("change", async (event) => { + let chain = event.target.value; + let networkData = await getNetworkData(); + + await networkSwitch(chain); + await getAssets(networkData[0], networkData[1]); +}); +selectAssets.addEventListener("change", (event) => token = event.target.value); \ No newline at end of file diff --git a/assets/js/spread/elements.js b/assets/js/spread/elements.js index dff8d8c..2d2342f 100644 --- a/assets/js/spread/elements.js +++ b/assets/js/spread/elements.js @@ -2,7 +2,6 @@ let addrList = []; let valueList = []; let valsToSum = []; let sum = 1; -let token; const spreadPolygon = "0x87945Ea3BDCe665461348EA8AfE0b07b0e4E121F"; const spreadMainnet = "0x87945Ea3BDCe665461348EA8AfE0b07b0e4E121F"; @@ -32,7 +31,7 @@ const getERC20Assets = async () => { selectAssets.append(newOption); } - // selectAssets.appendChild(docFrag); + selectAssets.appendChild(docFrag); } async function sendNativeAsset(network) { @@ -64,10 +63,9 @@ async function sendErc20(token, network) { if (network.chainId === 137) await Moralis.executeFunction({msgValue: sumOf(valsToSum), contractAddress: spreadPolygon, ...spreadERC20Options}); } -async function switchNetwork(chain, network, data) { +// +async function networkSwitch(chain) { await Moralis.switchNetwork(chain); - - getAssets(network, data); } async function addPolygonChain() { diff --git a/assets/js/spread/utils.js b/assets/js/spread/utils.js index 7cdad3a..d9e246a 100644 --- a/assets/js/spread/utils.js +++ b/assets/js/spread/utils.js @@ -1,8 +1,8 @@ function sumOf(arr) { - let total = 0; - for(let i = 0; i < arr.length; i++) total += arr[i]; - - return total; + let total = 0; + for(let i = 0; i < arr.length; i++) total += arr[i]; + + return total; } async function getAssets(network, data) { @@ -11,33 +11,33 @@ async function getAssets(network, data) { } function setTableValues() { - let address = document.getElementById("input-address").value; - let amount = document.getElementById("input-value").value; - if((address && amount && selectAssets.value) == ("")) { - alert('Please set all the data'); - throw "you have not set all data"; - }; - - let newRow = document.createElement("tr"); - let newHeading = document.createElement("th"); - let newRecipient = document.createElement("td"); - let newValue = document.createElement("td"); - - newHeading.innerHTML = sum++; - newRecipient.innerHTML = address; - newValue.innerHTML = amount; - - newRow.append(newHeading, newRecipient, newValue); - - document.getElementById("rows").appendChild(newRow); - document.getElementById("input-address").value = ""; - document.getElementById("input-value").value = ""; - - addRecieverDataToLists(address, amount); - } + let address = document.getElementById("input-address").value; + let amount = document.getElementById("input-value").value; + if((address && amount && selectAssets.value) == ("")) { + alert('Please set all the data'); + throw "you have not set all data"; + }; + + let newRow = document.createElement("tr"); + let newHeading = document.createElement("th"); + let newRecipient = document.createElement("td"); + let newValue = document.createElement("td"); + + newHeading.innerHTML = sum++; + newRecipient.innerHTML = address; + newValue.innerHTML = amount; + + newRow.append(newHeading, newRecipient, newValue); + + document.getElementById("rows").appendChild(newRow); + document.getElementById("input-address").value = ""; + document.getElementById("input-value").value = ""; + + addRecieverDataToLists(address, amount); +} function addRecieverDataToLists(account, value) { - addrList.push(account); - valueList.push(Moralis.Units.ETH(value)); - valsToSum.push(Number(Moralis.Units.ETH(value))); + addrList.push(account); + valueList.push(Moralis.Units.ETH(value)); + valsToSum.push(Number(Moralis.Units.ETH(value))); } \ No newline at end of file diff --git a/spread-dapp.html b/spread-dapp.html index a235680..11b7d10 100644 --- a/spread-dapp.html +++ b/spread-dapp.html @@ -86,7 +86,7 @@ --> From b54334ed00a038bf8efa4abbcf7a1ab73f600abc Mon Sep 17 00:00:00 2001 From: Ivo Garofalo Date: Sun, 10 Jul 2022 13:59:08 +0000 Subject: [PATCH 3/9] fix: fetch correct balance after network switch --- .gitpod.yml | 8 +++ assets/js/spread/app.js | 64 +++++++---------- assets/js/spread/elements.js | 87 ----------------------- assets/js/spread/utils.js | 134 ++++++++++++++++++++++++++++++++++- index.html | 2 +- spread-dapp.html | 27 ++----- 6 files changed, 174 insertions(+), 148 deletions(-) create mode 100644 .gitpod.yml delete mode 100644 assets/js/spread/elements.js diff --git a/.gitpod.yml b/.gitpod.yml new file mode 100644 index 0000000..eae2dd7 --- /dev/null +++ b/.gitpod.yml @@ -0,0 +1,8 @@ +# This configuration file was automatically generated by Gitpod. +# Please adjust to your needs (see https://www.gitpod.io/docs/config-gitpod-file) +# and commit this file to your remote git repository to share the goodness with others. + +tasks: + - init: yarn install + + diff --git a/assets/js/spread/app.js b/assets/js/spread/app.js index bf64477..f5e808c 100644 --- a/assets/js/spread/app.js +++ b/assets/js/spread/app.js @@ -1,52 +1,42 @@ +import { setNetworkId, getNetworkData, getAssets, networkSwitch } from "./utils.js"; + let selectedChain = document.querySelector("#selectedChain"); -let token; +let token, logOut; -// FIXME: login. -let user = Moralis.User.current(); -if(!user) (Moralis.authenticate().then((user) => console.log(user)))(); -// FIXME: logout. -const logOut = async () => await Moralis.User.logOut(); // Auto log in with metamask and get native assets and token balances. (async function () { - let networkData = await getNetworkData(); - await getNetworkId(); - getAssets(networkData[0], networkData[1]); -})() - -async function getNetworkData() { - const web3Provider = await Moralis.enableWeb3(); - const network = await web3Provider.getNetwork(); + await setNetworkId(); - let response = await fetch("https://chainid.network/chains.json"); - let data = await response.json(); - - return [network, data]; -} - -async function getNetworkId() { - let chainId = await Moralis.chainId; + // FIXME: login. + let user = Moralis.User.current(); + if(!user) (Moralis.authenticate().then((user) => console.log(user)))(); + // FIXME: logout. + logOut = async () => await Moralis.User.logOut(); - if(chainId === "0x1") document.getElementById("eth").selected = "true"; - else if(chainId === "0x89") document.getElementById("matic").selected = "true"; - else document.getElementById("chooseChain").selected = "true"; -} - -async function spread() { let networkData = await getNetworkData(); + console.log("current Network:", networkData[0]) - if(selectAssets.value === "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee") sendNativeAsset(networkData[0]); - else if(selectAssets.value === "") { - alert("Please select an asset to spread"); - throw "no selected asset"; - } else sendErc20(token, networkData[0]); -} + await getAssets(networkData[0], networkData[1]); + console.log("Refreshed and got the assets for:", networkData[0]); +})() + selectedChain.addEventListener("change", async (event) => { let chain = event.target.value; + console.log("changed select option to:", chain) + + console.log("About to sign transation to change chain:", chain) + let swithedTo = await networkSwitch(chain); + console.log("Transaction signed, network should switch to:", swithedTo); + let networkData = await getNetworkData(); - - await networkSwitch(chain); - await getAssets(networkData[0], networkData[1]); + console.log("current Network:", networkData[0]) + + console.log("about to get assets for:", networkData[0]) + let assets = await getAssets(networkData[0], networkData[1]); + console.log("GetAssets called and returned native assets:", assets[0] ); + console.log("GetAssets called and returned erc assets:", assets[1] ); }); + selectAssets.addEventListener("change", (event) => token = event.target.value); \ No newline at end of file diff --git a/assets/js/spread/elements.js b/assets/js/spread/elements.js deleted file mode 100644 index 2d2342f..0000000 --- a/assets/js/spread/elements.js +++ /dev/null @@ -1,87 +0,0 @@ -let addrList = []; -let valueList = []; -let valsToSum = []; -let sum = 1; - -const spreadPolygon = "0x87945Ea3BDCe665461348EA8AfE0b07b0e4E121F"; -const spreadMainnet = "0x87945Ea3BDCe665461348EA8AfE0b07b0e4E121F"; -let selectAssets = document.querySelector("#selectAssets"); -let nativeAsset = document.querySelector("#nativeAsset"); -let docFrag = document.createDocumentFragment(); - -// fetch the native balance of the address and display it in the select options element -const getNativeAsset = async (network, data) => { - const nativeBalances = await Moralis.Web3API.account.getNativeBalance({chain: Moralis.getChainId()}); - - for(let index in data) { - if(network.chainId == data[index].chainId) { - nativeAsset.innerHTML = `${data[index].nativeCurrency.symbol}: ${Number(Moralis.Units.FromWei(nativeBalances.balance)).toFixed(4)}`;; - } - } -}; - -// get erc20 assets and display them in the select options. -const getERC20Assets = async () => { - const tokenBalances = await Moralis.Web3API.account.getTokenBalances({chain: Moralis.getChainId()}); - - for(let index in tokenBalances) { - let newOption = document.createElement('option'); - newOption.value = tokenBalances[index].token_address; - newOption.innerHTML = `${tokenBalances[index].symbol}: ${Number(Moralis.Units.FromWei(tokenBalances[index].balance, tokenBalances[index].decimals)).toFixed(3)}`; - - selectAssets.append(newOption); - } - selectAssets.appendChild(docFrag); -} - -async function sendNativeAsset(network) { - const spreadOptions = { - functionName: "spreadAsset", - abi: SPREAD_ABI, - params: { - recipients: addrList, - values: valueList - } - } - if (network.chainId === 1) await Moralis.executeFunction({msgValue: sumOf(valsToSum), contractAddress: spreadMainnet, ...spreadOptions}); - if (network.chainId === 137) await Moralis.executeFunction({msgValue: sumOf(valsToSum), contractAddress: spreadPolygon, ...spreadOptions}); -} - -// @notice execute method to spread ERC20 assets. -// @param token The token to spread. -async function sendErc20(token, network) { - const spreadERC20Options = { - functionName: "spreadERC20", - abi: SPREAD_ABI, - params: { - token: token, - recipients: addrList, - values: valueList - } - } - if (network.chainId === 1) await Moralis.executeFunction({msgValue: sumOf(valsToSum), contractAddress: spreadMainnet, ...spreadERC20Options}); - if (network.chainId === 137) await Moralis.executeFunction({msgValue: sumOf(valsToSum), contractAddress: spreadPolygon, ...spreadERC20Options}); -} - -// -async function networkSwitch(chain) { - await Moralis.switchNetwork(chain); -} - -async function addPolygonChain() { - const chainId = 137; - const chainName = "Polygon Mainnet"; - const currencyName = "Polygon"; - const currencySymbol = "MATIC"; - const rpcUrl = "https://polygon-rpc.com"; - const blockExplorerUrl = "https://polygonscan.com/"; - - await Moralis.addNetwork( - chainId, - chainName, - currencyName, - currencySymbol, - rpcUrl, - blockExplorerUrl - ); -} \ No newline at end of file diff --git a/assets/js/spread/utils.js b/assets/js/spread/utils.js index d9e246a..90a918f 100644 --- a/assets/js/spread/utils.js +++ b/assets/js/spread/utils.js @@ -1,3 +1,95 @@ +let addrList = []; +let valueList = []; +let valsToSum = []; +let sum = 1; + +const spreadPolygon = "0x87945Ea3BDCe665461348EA8AfE0b07b0e4E121F"; +const spreadMainnet = "0x87945Ea3BDCe665461348EA8AfE0b07b0e4E121F"; +let selectAssets = document.querySelector("#selectAssets"); +let nativeAsset = document.querySelector("#nativeAsset"); +let docFrag = document.createDocumentFragment(); + +// fetch the native balance of the address and display it in the select options element +const getNativeAsset = async (network, data) => { + const nativeBalances = await Moralis.Web3API.account.getNativeBalance({chain: Moralis.getChainId()}); + + for(let index in data) { + if(network.chainId == data[index].chainId) { + nativeAsset.innerHTML = `${data[index].nativeCurrency.symbol}: ${Number(Moralis.Units.FromWei(nativeBalances.balance)).toFixed(4)}`;; + } + } +}; + +// get erc20 assets and display them in the select options. +const getERC20Assets = async () => { + const tokenBalances = await Moralis.Web3API.account.getTokenBalances({chain: Moralis.getChainId()}); + + for(let index in tokenBalances) { + + let newOption = document.createElement('option'); + newOption.value = tokenBalances[index].token_address; + newOption.innerHTML = `${tokenBalances[index].symbol}: ${Number(Moralis.Units.FromWei(tokenBalances[index].balance, tokenBalances[index].decimals)).toFixed(3)}`; + + selectAssets.append(newOption); + } + + selectAssets.appendChild(docFrag); +} + + +async function sendNativeAsset(network) { + const spreadOptions = { + functionName: "spreadAsset", + abi: SPREAD_ABI, + params: { + recipients: addrList, + values: valueList + } + } + if (network.chainId === 1) await Moralis.executeFunction({msgValue: sumOf(valsToSum), contractAddress: spreadMainnet, ...spreadOptions}); + if (network.chainId === 137) await Moralis.executeFunction({msgValue: sumOf(valsToSum), contractAddress: spreadPolygon, ...spreadOptions}); +} + +// @notice execute method to spread ERC20 assets. +// @param token The token to spread. +async function sendErc20(token, network) { + const spreadERC20Options = { + functionName: "spreadERC20", + abi: SPREAD_ABI, + params: { + token: token, + recipients: addrList, + values: valueList + } + } + if (network.chainId === 1) await Moralis.executeFunction({msgValue: sumOf(valsToSum), contractAddress: spreadMainnet, ...spreadERC20Options}); + if (network.chainId === 137) await Moralis.executeFunction({msgValue: sumOf(valsToSum), contractAddress: spreadPolygon, ...spreadERC20Options}); +} + +// +async function networkSwitch(chain) { + let network = await Moralis.switchNetwork(chain); + return network; +} + +/* async function addPolygonChain() { + const chainId = 137; + const chainName = "Polygon Mainnet"; + const currencyName = "Polygon"; + const currencySymbol = "MATIC"; + const rpcUrl = "https://polygon-rpc.com"; + const blockExplorerUrl = "https://polygonscan.com/"; + + await Moralis.addNetwork( + chainId, + chainName, + currencyName, + currencySymbol, + rpcUrl, + blockExplorerUrl + ); +} */ + function sumOf(arr) { let total = 0; for(let i = 0; i < arr.length; i++) total += arr[i]; @@ -5,9 +97,11 @@ function sumOf(arr) { return total; } +// fetch both native asset and ERC20, and return them. async function getAssets(network, data) { - await getNativeAsset(network, data); - await getERC20Assets(); + let native = await getNativeAsset(network, data); + let erc20 = await getERC20Assets(); + return [native, erc20]; } function setTableValues() { @@ -40,4 +134,38 @@ function addRecieverDataToLists(account, value) { addrList.push(account); valueList.push(Moralis.Units.ETH(value)); valsToSum.push(Number(Moralis.Units.ETH(value))); -} \ No newline at end of file +} + +// Get the nework data like network and chain data. +async function getNetworkData() { + let web3Provider = await Moralis.enableWeb3(); + let network = await web3Provider.getNetwork(); + + let response = await fetch("https://chainid.network/chains.json"); + let data = await response.json(); + + return [network, data]; +} + +// Set the correct network ID in the select options droppdown. +async function setNetworkId() { + let chainId = await Moralis.chainId; + + if(chainId === "0x1") document.getElementById("eth").selected = "true"; + else if(chainId === "0x89") document.getElementById("matic").selected = "true"; + else document.getElementById("chooseChain").selected = "true"; +} + + +// +async function spread() { + let networkData = await getNetworkData(); + + if(selectAssets.value === "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee") sendNativeAsset(networkData[0]); + else if(selectAssets.value === "") { + alert("Please select an asset to spread"); + throw "no selected asset"; + } else sendErc20(token, networkData[0]); +} + +export { spread, setNetworkId, getNetworkData, addRecieverDataToLists, setTableValues, getAssets, sumOf, networkSwitch, } diff --git a/index.html b/index.html index 6883b1f..cefab5e 100644 --- a/index.html +++ b/index.html @@ -40,7 +40,7 @@ - +